2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
|
2011-06-01 11:34:52 -07:00
|
|
|
// trans.rs: Translate the completed AST to the LLVM IR.
|
|
|
|
//
|
|
|
|
// Some functions here, such as trans_block and trans_expr, return a value --
|
|
|
|
// the result of the translation to LLVM -- while others, such as trans_fn,
|
|
|
|
// trans_obj, and trans_item, are called only for the side effect of adding a
|
|
|
|
// particular definition to the LLVM IR output we're producing.
|
2011-06-01 16:33:03 -07:00
|
|
|
//
|
|
|
|
// Hopefully useful general knowledge about trans:
|
2011-06-07 17:54:22 -07:00
|
|
|
//
|
2011-06-01 16:33:03 -07:00
|
|
|
// * There's no way to find out the ty::t type of a ValueRef. Doing so
|
|
|
|
// would be "trying to get the eggs out of an omelette" (credit:
|
|
|
|
// pcwalton). You can, instead, find out its TypeRef by calling val_ty,
|
|
|
|
// but many TypeRefs correspond to one ty::t; for instance, tup(int, int,
|
|
|
|
// int) and rec(x=int, y=int, z=int) will have the same TypeRef.
|
2011-05-17 20:41:41 +02:00
|
|
|
import std::int;
|
|
|
|
import std::str;
|
|
|
|
import std::uint;
|
|
|
|
import std::vec;
|
|
|
|
import std::str::rustrt::sbuf;
|
|
|
|
import std::vec::rustrt::vbuf;
|
2011-05-12 17:24:54 +02:00
|
|
|
import std::map;
|
|
|
|
import std::map::hashmap;
|
|
|
|
import std::option;
|
|
|
|
import std::option::some;
|
|
|
|
import std::option::none;
|
2011-06-07 17:54:22 -07:00
|
|
|
import std::fs;
|
2011-05-12 17:24:54 +02:00
|
|
|
import front::ast;
|
|
|
|
import front::creader;
|
|
|
|
import driver::session;
|
|
|
|
import middle::ty;
|
2011-05-13 16:47:37 -04:00
|
|
|
import back::link;
|
2011-05-12 17:24:54 +02:00
|
|
|
import back::x86;
|
|
|
|
import back::abi;
|
|
|
|
import back::upcall;
|
|
|
|
import middle::ty::pat_ty;
|
2011-06-10 17:24:20 +02:00
|
|
|
import visit::vt;
|
2011-05-12 17:24:54 +02:00
|
|
|
import util::common;
|
|
|
|
import util::common::istr;
|
|
|
|
import util::common::new_def_hash;
|
|
|
|
import util::common::new_str_hash;
|
2011-05-18 15:35:16 -07:00
|
|
|
import util::common::local_rhs_span;
|
2011-05-31 18:24:06 -07:00
|
|
|
import util::common::span;
|
2011-05-12 17:24:54 +02:00
|
|
|
import lib::llvm::llvm;
|
|
|
|
import lib::llvm::builder;
|
|
|
|
import lib::llvm::target_data;
|
|
|
|
import lib::llvm::type_handle;
|
|
|
|
import lib::llvm::type_names;
|
|
|
|
import lib::llvm::mk_target_data;
|
|
|
|
import lib::llvm::mk_type_handle;
|
|
|
|
import lib::llvm::mk_type_names;
|
|
|
|
import lib::llvm::llvm::ModuleRef;
|
|
|
|
import lib::llvm::llvm::ValueRef;
|
|
|
|
import lib::llvm::llvm::TypeRef;
|
|
|
|
import lib::llvm::llvm::TypeHandleRef;
|
|
|
|
import lib::llvm::llvm::BuilderRef;
|
|
|
|
import lib::llvm::llvm::BasicBlockRef;
|
|
|
|
import lib::llvm::False;
|
|
|
|
import lib::llvm::True;
|
|
|
|
import lib::llvm::Bool;
|
2011-06-07 17:54:22 -07:00
|
|
|
import link::mangle_internal_name_by_type_only;
|
|
|
|
import link::mangle_internal_name_by_seq;
|
|
|
|
import link::mangle_internal_name_by_path;
|
|
|
|
import link::mangle_internal_name_by_path_and_seq;
|
|
|
|
import link::mangle_exported_name;
|
|
|
|
import link::crate_meta_name;
|
|
|
|
import link::crate_meta_vers;
|
|
|
|
import link::crate_meta_extras_hash;
|
2011-06-09 09:48:16 -07:00
|
|
|
import pretty::ppaux::ty_to_str;
|
|
|
|
import pretty::ppaux::ty_to_short_str;
|
|
|
|
import pretty::pprust::expr_to_str;
|
2011-06-07 17:54:22 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
obj namegen(mutable int i) {
|
|
|
|
fn next(str prefix) -> str { i += 1; ret prefix + istr(i); }
|
2010-09-28 12:23:40 -07:00
|
|
|
}
|
|
|
|
|
2011-05-11 11:56:49 -07:00
|
|
|
type derived_tydesc_info = rec(ValueRef lltydesc, bool escapes);
|
|
|
|
|
2011-06-10 14:57:39 -07:00
|
|
|
type glue_fns = rec(ValueRef no_op_type_glue);
|
2010-09-23 17:16:34 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
type tydesc_info =
|
|
|
|
rec(ty::t ty,
|
|
|
|
ValueRef tydesc,
|
|
|
|
ValueRef size,
|
|
|
|
ValueRef align,
|
|
|
|
mutable option::t[ValueRef] take_glue,
|
|
|
|
mutable option::t[ValueRef] drop_glue,
|
|
|
|
mutable option::t[ValueRef] free_glue,
|
|
|
|
mutable option::t[ValueRef] cmp_glue,
|
|
|
|
vec[uint] ty_params);
|
|
|
|
|
2011-03-04 17:22:43 -08:00
|
|
|
|
2011-03-25 15:48:00 -07:00
|
|
|
/*
|
|
|
|
* A note on nomenclature of linking: "upcall", "extern" and "native".
|
|
|
|
*
|
|
|
|
* An "extern" is an LLVM symbol we wind up emitting an undefined external
|
|
|
|
* reference to. This means "we don't have the thing in this compilation unit,
|
|
|
|
* please make sure you link it in at runtime". This could be a reference to
|
|
|
|
* C code found in a C library, or rust code found in a rust crate.
|
|
|
|
*
|
2011-05-26 16:42:17 -07:00
|
|
|
* A "native" is an extern that references C code. Called with cdecl.
|
2011-03-25 15:48:00 -07:00
|
|
|
*
|
|
|
|
* An upcall is a native call generated by the compiler (not corresponding to
|
|
|
|
* any user-written call in the code) into librustrt, to perform some helper
|
|
|
|
* task such as bringing a task to life, allocating memory, etc.
|
|
|
|
*
|
|
|
|
*/
|
2011-06-15 11:19:50 -07:00
|
|
|
type stats =
|
|
|
|
rec(mutable uint n_static_tydescs,
|
|
|
|
mutable uint n_derived_tydescs,
|
|
|
|
mutable uint n_glues_created,
|
|
|
|
mutable uint n_null_glues,
|
|
|
|
mutable uint n_real_glues);
|
|
|
|
|
2011-06-15 12:18:02 -07:00
|
|
|
// Crate context. Every crate we compile has one of these.
|
2011-06-15 11:19:50 -07:00
|
|
|
type crate_ctxt =
|
|
|
|
rec(session::session sess,
|
|
|
|
ModuleRef llmod,
|
|
|
|
target_data td,
|
|
|
|
type_names tn,
|
|
|
|
hashmap[str, ValueRef] externs,
|
|
|
|
hashmap[str, ValueRef] intrinsics,
|
2011-06-15 12:18:02 -07:00
|
|
|
|
|
|
|
// A mapping from the def_id of each item in this crate to the address
|
|
|
|
// of the first instruction of the item's definition in the executable
|
|
|
|
// we're generating.
|
2011-06-15 11:19:50 -07:00
|
|
|
hashmap[ast::def_id, ValueRef] item_ids,
|
|
|
|
hashmap[ast::def_id, @ast::item] items,
|
|
|
|
hashmap[ast::def_id, @ast::native_item] native_items,
|
|
|
|
hashmap[ast::def_id, str] item_symbols,
|
|
|
|
mutable option::t[ValueRef] main_fn,
|
|
|
|
str crate_meta_name,
|
|
|
|
str crate_meta_vers,
|
|
|
|
str crate_meta_extras_hash,
|
|
|
|
|
|
|
|
// TODO: hashmap[tup(tag_id,subtys), @tag_info]
|
|
|
|
hashmap[ty::t, uint] tag_sizes,
|
|
|
|
hashmap[ast::def_id, ValueRef] discrims,
|
|
|
|
hashmap[ast::def_id, str] discrim_symbols,
|
|
|
|
hashmap[ast::def_id, ValueRef] fn_pairs,
|
|
|
|
hashmap[ast::def_id, ValueRef] consts,
|
|
|
|
hashmap[ast::def_id, ()] obj_methods,
|
|
|
|
hashmap[ty::t, @tydesc_info] tydescs,
|
|
|
|
hashmap[str, ValueRef] module_data,
|
|
|
|
hashmap[ty::t, TypeRef] lltypes,
|
|
|
|
@glue_fns glues,
|
|
|
|
namegen names,
|
|
|
|
std::sha1::sha1 sha,
|
|
|
|
hashmap[ty::t, str] type_sha1s,
|
|
|
|
hashmap[ty::t, metadata::ty_abbrev] type_abbrevs,
|
|
|
|
hashmap[ty::t, str] type_short_names,
|
|
|
|
ty::ctxt tcx,
|
|
|
|
stats stats,
|
|
|
|
@upcall::upcalls upcalls);
|
|
|
|
|
|
|
|
type local_ctxt =
|
|
|
|
rec(vec[str] path,
|
|
|
|
vec[str] module_path,
|
|
|
|
vec[ast::ty_param] obj_typarams,
|
|
|
|
vec[ast::obj_field] obj_fields,
|
|
|
|
@crate_ctxt ccx);
|
2011-04-25 16:17:14 -07:00
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
|
2011-06-01 11:34:52 -07:00
|
|
|
// Types used for llself.
|
|
|
|
type val_self_pair = rec(ValueRef v, ty::t t);
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-01 11:34:52 -07:00
|
|
|
type ty_self_pair = tup(TypeRef, ty::t);
|
2011-04-05 14:18:44 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-27 17:58:22 -07:00
|
|
|
// Function context. Every LLVM function we create will have one of these.
|
2011-06-15 11:19:50 -07:00
|
|
|
type fn_ctxt =
|
|
|
|
rec(
|
|
|
|
// The ValueRef returned from a call to llvm::LLVMAddFunction; the
|
|
|
|
// address of the first instruction in the sequence of instructions
|
|
|
|
// for this function that will go in the .text section of the
|
|
|
|
// executable we're generating.
|
|
|
|
ValueRef llfn,
|
|
|
|
|
|
|
|
// The three implicit arguments that arrive in the function we're
|
|
|
|
// creating. For instance, foo(int, int) is really foo(ret*, task*,
|
|
|
|
// env*, int, int). These are also available via
|
|
|
|
// llvm::LLVMGetParam(llfn, uint) where uint = 1, 2, 0 respectively,
|
|
|
|
// but we unpack them into these fields for convenience.
|
|
|
|
ValueRef lltaskptr,
|
|
|
|
ValueRef llenv,
|
|
|
|
ValueRef llretptr,
|
|
|
|
|
|
|
|
// The next three elements: "hoisted basic blocks" containing
|
|
|
|
// administrative activities that have to happen in only one place in
|
|
|
|
// the function, due to LLVM's quirks.
|
|
|
|
|
|
|
|
// A block for all the function's allocas, so that LLVM will coalesce
|
|
|
|
// them into a single alloca call.
|
|
|
|
mutable BasicBlockRef llallocas,
|
|
|
|
|
|
|
|
// A block containing code that copies incoming arguments to space
|
|
|
|
// already allocated by code in the llallocas block. (LLVM requires
|
|
|
|
// that arguments be copied to local allocas before allowing most any
|
|
|
|
// operation to be performed on them.)
|
|
|
|
mutable BasicBlockRef llcopyargs,
|
|
|
|
|
|
|
|
// A block containing derived tydescs received from the runtime. See
|
|
|
|
// description of derived_tydescs, below.
|
|
|
|
mutable BasicBlockRef llderivedtydescs,
|
|
|
|
|
|
|
|
// FIXME: Is llcopyargs actually the block containing the allocas for
|
|
|
|
// incoming function arguments? Or is it merely the block containing
|
|
|
|
// code that copies incoming args to space already alloca'd by code in
|
|
|
|
// llallocas?
|
|
|
|
|
|
|
|
// The 'self' object currently in use in this function, if there is
|
|
|
|
// one.
|
|
|
|
mutable option::t[val_self_pair] llself,
|
|
|
|
|
|
|
|
// If this function is actually a iter, a block containing the code
|
|
|
|
// called whenever the iter calls 'put'.
|
|
|
|
mutable option::t[ValueRef] lliterbody,
|
|
|
|
|
|
|
|
// The next four items: hash tables mapping from AST def_ids to
|
|
|
|
// LLVM-stuff-in-the-frame.
|
|
|
|
|
|
|
|
// Maps arguments to allocas created for them in llallocas.
|
|
|
|
hashmap[ast::def_id, ValueRef] llargs,
|
|
|
|
|
|
|
|
// Maps fields in objects to pointers into the interior of llself's
|
|
|
|
// body.
|
|
|
|
hashmap[ast::def_id, ValueRef] llobjfields,
|
|
|
|
|
|
|
|
// Maps the def_ids for local variables to the allocas created for
|
|
|
|
// them in llallocas.
|
|
|
|
hashmap[ast::def_id, ValueRef] lllocals,
|
|
|
|
|
|
|
|
// The same as above, but for variables accessed via the frame pointer
|
|
|
|
// we pass into an iter, for access to the static environment of the
|
|
|
|
// iter-calling frame.
|
|
|
|
hashmap[ast::def_id, ValueRef] llupvars,
|
|
|
|
|
|
|
|
// For convenience, a vector of the incoming tydescs for each of this
|
|
|
|
// functions type parameters, fetched via llvm::LLVMGetParam. For
|
|
|
|
// example, for a function foo[A, B, C](), lltydescs contains the
|
|
|
|
// ValueRefs for the tydescs for A, B, and C.
|
|
|
|
mutable vec[ValueRef] lltydescs,
|
|
|
|
|
|
|
|
// Derived tydescs are tydescs created at runtime, for types that
|
|
|
|
// involve type parameters inside type constructors. For example,
|
|
|
|
// suppose a function parameterized by T creates a vector of type
|
|
|
|
// vec[T]. The function doesn't know what T is until runtime, and the
|
|
|
|
// function's caller knows T but doesn't know that a vector is
|
|
|
|
// involved. So a tydesc for vec[T] can't be created until runtime,
|
|
|
|
// when information about both "vec" and "T" are available. When such
|
|
|
|
// a tydesc is created, we cache it in the derived_tydescs table for
|
|
|
|
// the next time that such a tydesc is needed.
|
|
|
|
hashmap[ty::t, derived_tydesc_info] derived_tydescs,
|
|
|
|
|
|
|
|
// The source span where this function comes from, for error
|
|
|
|
// reporting.
|
|
|
|
span sp,
|
|
|
|
|
|
|
|
// This function's enclosing local context.
|
|
|
|
@local_ctxt lcx);
|
|
|
|
|
|
|
|
tag cleanup { clean(fn(&@block_ctxt) -> result ); }
|
2010-09-29 17:22:07 -07:00
|
|
|
|
2011-01-24 15:26:10 -08:00
|
|
|
tag block_kind {
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-27 17:58:22 -07:00
|
|
|
// A scope block is a basic block created by translating a block { ... }
|
|
|
|
// the the source language. Since these blocks create variable scope, any
|
|
|
|
// variables created in them that are still live at the end of the block
|
|
|
|
// must be dropped and cleaned up when the block ends.
|
2011-01-24 15:26:10 -08:00
|
|
|
SCOPE_BLOCK;
|
2011-05-27 17:58:22 -07:00
|
|
|
|
|
|
|
// A basic block created from the body of a loop. Contains pointers to
|
|
|
|
// which block to jump to in the case of "continue" or "break", with the
|
|
|
|
// "continue" block optional, because "while" and "do while" don't support
|
|
|
|
// "continue" (TODO: is this intentional?)
|
2011-05-12 17:24:54 +02:00
|
|
|
LOOP_SCOPE_BLOCK(option::t[@block_ctxt], @block_ctxt);
|
2011-05-27 17:58:22 -07:00
|
|
|
|
|
|
|
// A non-scope block is a basic block created as a translation artifact
|
|
|
|
// from translating code that expresses conditional logic rather than by
|
|
|
|
// explicit { ... } block structure in the source language. It's called a
|
|
|
|
// non-scope block because it doesn't introduce a new variable scope.
|
2011-01-24 15:26:10 -08:00
|
|
|
NON_SCOPE_BLOCK;
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-27 17:58:22 -07:00
|
|
|
// Basic block context. We create a block context for each basic block
|
|
|
|
// (single-entry, single-exit sequence of instructions) we generate from Rust
|
|
|
|
// code. Each basic block we generate is attached to a function, typically
|
|
|
|
// with many basic blocks per function. All the basic blocks attached to a
|
|
|
|
// function are organized as a directed graph.
|
2011-06-15 11:19:50 -07:00
|
|
|
type block_ctxt =
|
|
|
|
rec(
|
|
|
|
// The BasicBlockRef returned from a call to
|
|
|
|
// llvm::LLVMAppendBasicBlock(llfn, name), which adds a basic block to
|
|
|
|
// the function pointed to by llfn. We insert instructions into that
|
|
|
|
// block by way of this block context.
|
|
|
|
BasicBlockRef llbb,
|
2011-05-27 17:58:22 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
// The llvm::builder object serving as an interface to LLVM's
|
|
|
|
// LLVMBuild* functions.
|
|
|
|
builder build,
|
2011-05-27 17:58:22 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
// The block pointing to this one in the function's digraph.
|
|
|
|
block_parent parent,
|
2011-05-27 17:58:22 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
// The 'kind' of basic block this is.
|
|
|
|
block_kind kind,
|
2011-05-27 17:58:22 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
// A list of functions that run at the end of translating this block,
|
|
|
|
// cleaning up any variables that were introduced in the block and
|
|
|
|
// need to go out of scope at the end of it.
|
|
|
|
mutable vec[cleanup] cleanups,
|
2011-05-27 17:58:22 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
// The source span where this block comes from, for error reporting.
|
|
|
|
span sp,
|
|
|
|
|
|
|
|
// The function context for the function to which this block is
|
|
|
|
// attached.
|
|
|
|
@fn_ctxt fcx);
|
2011-05-27 17:58:22 -07:00
|
|
|
|
2010-09-29 17:22:07 -07:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
// FIXME: we should be able to use option::t[@block_parent] here but
|
2010-11-10 17:46:49 -08:00
|
|
|
// the infinite-tag check in rustboot gets upset.
|
2011-06-15 11:19:50 -07:00
|
|
|
tag block_parent { parent_none; parent_some(@block_ctxt); }
|
2010-11-10 17:46:49 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
type result = rec(@block_ctxt bcx, ValueRef val);
|
2010-10-04 15:55:12 -07:00
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn extend_path(@local_ctxt cx, &str name) -> @local_ctxt {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret @rec(path=cx.path + [name] with *cx);
|
2011-03-26 17:36:47 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn res(@block_ctxt bcx, ValueRef val) -> result { ret rec(bcx=bcx, val=val); }
|
2010-10-04 15:55:12 -07:00
|
|
|
|
2011-02-17 18:16:51 -08:00
|
|
|
fn ty_str(type_names tn, TypeRef t) -> str {
|
2011-05-12 17:24:54 +02:00
|
|
|
ret lib::llvm::type_to_str(tn, t);
|
2010-09-29 17:22:07 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn val_ty(ValueRef v) -> TypeRef { ret llvm::LLVMTypeOf(v); }
|
|
|
|
|
|
|
|
fn val_str(type_names tn, ValueRef v) -> str { ret ty_str(tn, val_ty(v)); }
|
2010-09-29 17:22:07 -07:00
|
|
|
|
2010-09-24 14:56:04 -07:00
|
|
|
|
2011-06-10 13:49:22 -07:00
|
|
|
// Returns the nth element of the given LLVM structure type.
|
|
|
|
fn struct_elt(TypeRef llstructty, uint n) -> TypeRef {
|
|
|
|
auto elt_count = llvm::LLVMCountStructElementTypes(llstructty);
|
|
|
|
assert (n < elt_count);
|
|
|
|
auto elt_tys = vec::init_elt(T_nil(), elt_count);
|
|
|
|
llvm::LLVMGetStructElementTypes(llstructty, vec::buf(elt_tys));
|
|
|
|
ret llvm::LLVMGetElementType(elt_tys.(n));
|
|
|
|
}
|
|
|
|
|
2010-09-24 14:56:04 -07:00
|
|
|
|
|
|
|
// LLVM type constructors.
|
2010-10-04 15:55:12 -07:00
|
|
|
fn T_void() -> TypeRef {
|
|
|
|
// Note: For the time being llvm is kinda busted here, it has the notion
|
|
|
|
// of a 'void' type that can only occur as part of the signature of a
|
|
|
|
// function, but no general unit type of 0-sized value. This is, afaict,
|
|
|
|
// vestigial from its C heritage, and we'll be attempting to submit a
|
|
|
|
// patch upstream to fix it. In the mean time we only model function
|
|
|
|
// outputs (Rust functions and C functions) using T_void, and model the
|
|
|
|
// Rust general purpose nil type you can construct as 1-bit (always
|
|
|
|
// zero). This makes the result incorrect for now -- things like a tuple
|
|
|
|
// of 10 nil values will have 10-bit size -- but it doesn't seem like we
|
|
|
|
// have any other options until it's fixed upstream.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
ret llvm::LLVMVoidType();
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
|
|
|
|
2010-10-04 15:55:12 -07:00
|
|
|
fn T_nil() -> TypeRef {
|
|
|
|
// NB: See above in T_void().
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
ret llvm::LLVMInt1Type();
|
2010-09-28 16:17:28 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn T_i1() -> TypeRef { ret llvm::LLVMInt1Type(); }
|
2010-09-28 12:23:40 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn T_i8() -> TypeRef { ret llvm::LLVMInt8Type(); }
|
2010-09-28 12:23:40 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn T_i16() -> TypeRef { ret llvm::LLVMInt16Type(); }
|
2010-09-22 17:05:38 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn T_i32() -> TypeRef { ret llvm::LLVMInt32Type(); }
|
2010-09-28 12:23:40 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn T_i64() -> TypeRef { ret llvm::LLVMInt64Type(); }
|
2010-10-19 14:54:10 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn T_f32() -> TypeRef { ret llvm::LLVMFloatType(); }
|
2010-10-19 14:54:10 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn T_f64() -> TypeRef { ret llvm::LLVMDoubleType(); }
|
|
|
|
|
|
|
|
fn T_bool() -> TypeRef { ret T_i1(); }
|
2010-10-19 17:24:15 -07:00
|
|
|
|
2010-09-28 12:23:40 -07:00
|
|
|
fn T_int() -> TypeRef {
|
|
|
|
// FIXME: switch on target type.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-09-28 12:23:40 -07:00
|
|
|
ret T_i32();
|
|
|
|
}
|
|
|
|
|
2011-03-21 17:12:05 -07:00
|
|
|
fn T_float() -> TypeRef {
|
|
|
|
// FIXME: switch on target type.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-21 17:12:05 -07:00
|
|
|
ret T_f64();
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn T_char() -> TypeRef { ret T_i32(); }
|
2010-10-19 14:54:10 -07:00
|
|
|
|
2011-05-09 15:32:12 -07:00
|
|
|
fn T_size_t() -> TypeRef {
|
|
|
|
// FIXME: switch on target type.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-09 15:32:12 -07:00
|
|
|
ret T_i32();
|
|
|
|
}
|
|
|
|
|
2010-09-22 17:05:38 -07:00
|
|
|
fn T_fn(vec[TypeRef] inputs, TypeRef output) -> TypeRef {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret llvm::LLVMFunctionType(output, vec::buf[TypeRef](inputs),
|
|
|
|
vec::len[TypeRef](inputs), False);
|
2010-09-23 17:16:34 -07:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn T_fn_pair(&type_names tn, TypeRef tfn) -> TypeRef {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret T_struct([T_ptr(tfn), T_opaque_closure_ptr(tn)]);
|
2011-01-03 22:39:43 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn T_ptr(TypeRef t) -> TypeRef { ret llvm::LLVMPointerType(t, 0u); }
|
2010-09-23 17:16:34 -07:00
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn T_struct(&vec[TypeRef] elts) -> TypeRef {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret llvm::LLVMStructType(vec::buf[TypeRef](elts), vec::len[TypeRef](elts),
|
|
|
|
False);
|
2010-09-23 17:16:34 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn T_opaque() -> TypeRef { ret llvm::LLVMOpaqueType(); }
|
2010-09-23 17:16:34 -07:00
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn T_task(&type_names tn) -> TypeRef {
|
2011-02-17 18:16:51 -08:00
|
|
|
auto s = "task";
|
2011-06-15 11:19:50 -07:00
|
|
|
if (tn.name_has_type(s)) { ret tn.get_type(s); }
|
|
|
|
auto t =
|
|
|
|
T_struct([T_int(), // Refcount
|
|
|
|
T_int(), // Delegate pointer
|
|
|
|
T_int(), // Stack segment pointer
|
|
|
|
T_int(), // Runtime SP
|
|
|
|
T_int(), // Rust SP
|
|
|
|
T_int(), // GC chain
|
|
|
|
T_int(), // Domain pointer
|
|
|
|
// Crate cache pointer
|
|
|
|
T_int()]);
|
2011-02-17 18:16:51 -08:00
|
|
|
tn.associate(s, t);
|
|
|
|
ret t;
|
2010-09-24 15:22:48 -07:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn T_tydesc_field(&type_names tn, int field) -> TypeRef {
|
2011-04-18 10:56:52 -07:00
|
|
|
// Bit of a kludge: pick the fn typeref out of the tydesc..
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-18 10:56:52 -07:00
|
|
|
let vec[TypeRef] tydesc_elts =
|
2011-05-17 20:41:41 +02:00
|
|
|
vec::init_elt[TypeRef](T_nil(), abi::n_tydesc_fields as uint);
|
2011-05-12 17:24:54 +02:00
|
|
|
llvm::LLVMGetStructElementTypes(T_tydesc(tn),
|
2011-06-15 11:19:50 -07:00
|
|
|
vec::buf[TypeRef](tydesc_elts));
|
2011-05-12 17:24:54 +02:00
|
|
|
auto t = llvm::LLVMGetElementType(tydesc_elts.(field));
|
2011-04-18 10:56:52 -07:00
|
|
|
ret t;
|
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn T_glue_fn(&type_names tn) -> TypeRef {
|
2011-02-17 18:16:51 -08:00
|
|
|
auto s = "glue_fn";
|
2011-06-15 11:19:50 -07:00
|
|
|
if (tn.name_has_type(s)) { ret tn.get_type(s); }
|
2011-05-12 17:24:54 +02:00
|
|
|
auto t = T_tydesc_field(tn, abi::tydesc_field_drop_glue);
|
2011-04-18 10:56:52 -07:00
|
|
|
tn.associate(s, t);
|
|
|
|
ret t;
|
|
|
|
}
|
|
|
|
|
2011-05-31 18:24:06 -07:00
|
|
|
fn T_dtor(&@crate_ctxt ccx, &span sp, TypeRef llself_ty) -> TypeRef {
|
2011-05-18 15:35:16 -07:00
|
|
|
ret type_of_fn_full(ccx, sp, ast::proto_fn, some[TypeRef](llself_ty),
|
2011-05-17 20:41:41 +02:00
|
|
|
vec::empty[ty::arg](), ty::mk_nil(ccx.tcx), 0u);
|
2011-04-29 13:34:30 +02:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn T_cmp_glue_fn(&type_names tn) -> TypeRef {
|
2011-04-18 10:56:52 -07:00
|
|
|
auto s = "cmp_glue_fn";
|
2011-06-15 11:19:50 -07:00
|
|
|
if (tn.name_has_type(s)) { ret tn.get_type(s); }
|
2011-05-12 17:24:54 +02:00
|
|
|
auto t = T_tydesc_field(tn, abi::tydesc_field_cmp_glue);
|
2011-02-17 18:16:51 -08:00
|
|
|
tn.associate(s, t);
|
|
|
|
ret t;
|
2011-02-08 11:47:53 -08:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn T_tydesc(&type_names tn) -> TypeRef {
|
2011-02-17 18:16:51 -08:00
|
|
|
auto s = "tydesc";
|
2011-06-15 11:19:50 -07:00
|
|
|
if (tn.name_has_type(s)) { ret tn.get_type(s); }
|
2011-01-28 14:34:25 -08:00
|
|
|
auto th = mk_type_handle();
|
2011-05-12 17:24:54 +02:00
|
|
|
auto abs_tydesc = llvm::LLVMResolveTypeHandle(th.llth);
|
2011-01-28 15:45:13 -08:00
|
|
|
auto tydescpp = T_ptr(T_ptr(abs_tydesc));
|
2010-12-16 16:34:20 -08:00
|
|
|
auto pvoid = T_ptr(T_i8());
|
2011-06-15 11:19:50 -07:00
|
|
|
auto glue_fn_ty =
|
|
|
|
T_ptr(T_fn([T_ptr(T_nil()), T_taskptr(tn), T_ptr(T_nil()), tydescpp,
|
|
|
|
pvoid], T_void()));
|
|
|
|
auto cmp_glue_fn_ty =
|
|
|
|
T_ptr(T_fn([T_ptr(T_i1()), T_taskptr(tn), T_ptr(T_nil()), tydescpp,
|
|
|
|
pvoid, pvoid, T_i8()], T_void()));
|
|
|
|
auto tydesc =
|
|
|
|
T_struct([tydescpp, // first_param
|
|
|
|
T_int(), // size
|
|
|
|
T_int(), // align
|
|
|
|
glue_fn_ty, // take_glue
|
|
|
|
glue_fn_ty, // drop_glue
|
|
|
|
glue_fn_ty, // free_glue
|
|
|
|
glue_fn_ty, // sever_glue
|
|
|
|
glue_fn_ty, // mark_glue
|
|
|
|
glue_fn_ty, // obj_drop_glue
|
|
|
|
glue_fn_ty, // is_stateful
|
|
|
|
cmp_glue_fn_ty]); // cmp_glue
|
2011-01-28 14:34:25 -08:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
llvm::LLVMRefineType(abs_tydesc, tydesc);
|
|
|
|
auto t = llvm::LLVMResolveTypeHandle(th.llth);
|
2011-02-17 18:16:51 -08:00
|
|
|
tn.associate(s, t);
|
|
|
|
ret t;
|
2010-12-16 16:34:20 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn T_array(TypeRef t, uint n) -> TypeRef { ret llvm::LLVMArrayType(t, n); }
|
2010-10-01 18:25:42 -07:00
|
|
|
|
2010-11-22 14:28:05 -08:00
|
|
|
fn T_vec(TypeRef t) -> TypeRef {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret T_struct([T_int(), // Refcount
|
|
|
|
T_int(), // Alloc
|
|
|
|
T_int(), // Fill
|
|
|
|
T_int(), // Pad
|
|
|
|
// Body elements
|
|
|
|
T_array(t, 0u)]);
|
2010-09-29 17:22:07 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn T_opaque_vec_ptr() -> TypeRef { ret T_ptr(T_vec(T_int())); }
|
|
|
|
|
2011-03-06 12:46:33 -08:00
|
|
|
|
2011-06-10 12:07:38 -07:00
|
|
|
// Interior vector.
|
|
|
|
//
|
|
|
|
// TODO: Support user-defined vector sizes.
|
2011-06-12 00:44:43 -07:00
|
|
|
fn T_ivec(TypeRef t) -> TypeRef {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret T_struct([T_int(), // Length ("fill"; if zero, heapified)
|
|
|
|
T_int(), // Alloc
|
|
|
|
T_array(t, abi::ivec_default_length)]); // Body elements
|
|
|
|
|
2011-06-12 00:44:43 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-12 00:44:43 -07:00
|
|
|
// Note that the size of this one is in bytes.
|
|
|
|
fn T_opaque_ivec() -> TypeRef {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret T_struct([T_int(), // Length ("fill"; if zero, heapified)
|
|
|
|
T_int(), // Alloc
|
|
|
|
T_array(T_i8(), 0u)]); // Body elements
|
|
|
|
|
2011-06-10 12:07:38 -07:00
|
|
|
}
|
|
|
|
|
2011-06-13 18:52:04 -07:00
|
|
|
fn T_ivec_heap_part(TypeRef t) -> TypeRef {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret T_struct([T_int(), // Real length
|
|
|
|
T_array(t, 0u)]); // Body elements
|
|
|
|
|
2011-06-13 18:52:04 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-13 18:52:04 -07:00
|
|
|
// Interior vector on the heap, also known as the "stub". Cast to this when
|
|
|
|
// the allocated length (second element of T_ivec above) is zero.
|
2011-06-10 12:07:38 -07:00
|
|
|
fn T_ivec_heap(TypeRef t) -> TypeRef {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret T_struct([T_int(), // Length (zero)
|
|
|
|
T_int(), // Alloc
|
|
|
|
T_ptr(T_ivec_heap_part(t))]); // Pointer
|
|
|
|
|
2011-06-13 18:52:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn T_opaque_ivec_heap_part() -> TypeRef {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret T_struct([T_int(), // Real length
|
|
|
|
T_array(T_i8(), 0u)]); // Body elements
|
2011-06-13 18:52:04 -07:00
|
|
|
|
2011-06-10 12:07:38 -07:00
|
|
|
}
|
|
|
|
|
2011-06-10 19:35:59 -07:00
|
|
|
fn T_opaque_ivec_heap() -> TypeRef {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret T_struct([T_int(), // Length (zero)
|
|
|
|
T_int(), // Alloc
|
|
|
|
T_ptr(T_opaque_ivec_heap_part())]); // Pointer
|
2011-06-10 19:35:59 -07:00
|
|
|
|
2010-10-01 18:25:42 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn T_str() -> TypeRef { ret T_vec(T_i8()); }
|
|
|
|
|
|
|
|
fn T_box(TypeRef t) -> TypeRef { ret T_struct([T_int(), t]); }
|
2010-10-19 14:54:10 -07:00
|
|
|
|
2011-03-16 21:49:15 -04:00
|
|
|
fn T_port(TypeRef t) -> TypeRef {
|
2011-05-16 18:21:22 -07:00
|
|
|
ret T_struct([T_int()]); // Refcount
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-16 21:49:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn T_chan(TypeRef t) -> TypeRef {
|
2011-05-16 18:21:22 -07:00
|
|
|
ret T_struct([T_int()]); // Refcount
|
2011-03-16 21:49:15 -04:00
|
|
|
|
2010-09-23 17:16:34 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn T_taskptr(&type_names tn) -> TypeRef { ret T_ptr(T_task(tn)); }
|
|
|
|
|
|
|
|
|
2011-03-04 18:05:48 -08:00
|
|
|
// This type must never be used directly; it must always be cast away.
|
2011-05-11 04:58:46 +00:00
|
|
|
fn T_typaram(&type_names tn) -> TypeRef {
|
2011-02-17 18:16:51 -08:00
|
|
|
auto s = "typaram";
|
2011-06-15 11:19:50 -07:00
|
|
|
if (tn.name_has_type(s)) { ret tn.get_type(s); }
|
2011-03-04 18:05:48 -08:00
|
|
|
auto t = T_i8();
|
2011-02-17 18:16:51 -08:00
|
|
|
tn.associate(s, t);
|
|
|
|
ret t;
|
2011-01-14 16:46:44 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn T_typaram_ptr(&type_names tn) -> TypeRef { ret T_ptr(T_typaram(tn)); }
|
2011-03-04 18:05:48 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn T_closure_ptr(&type_names tn, TypeRef lltarget_ty, TypeRef llbindings_ty,
|
2011-02-23 10:58:43 -08:00
|
|
|
uint n_ty_params) -> TypeRef {
|
2011-03-07 18:13:39 -08:00
|
|
|
// NB: keep this in sync with code in trans_bind; we're making
|
2011-05-12 17:24:54 +02:00
|
|
|
// an LLVM typeref structure that has the same "shape" as the ty::t
|
2011-03-07 18:13:39 -08:00
|
|
|
// it constructs.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
ret T_ptr(T_box(T_struct([T_ptr(T_tydesc(tn)), lltarget_ty, llbindings_ty,
|
|
|
|
T_captured_tydescs(tn, n_ty_params)])));
|
2011-01-07 15:12:23 -08:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn T_opaque_closure_ptr(&type_names tn) -> TypeRef {
|
2011-02-17 18:16:51 -08:00
|
|
|
auto s = "*closure";
|
2011-06-15 11:19:50 -07:00
|
|
|
if (tn.name_has_type(s)) { ret tn.get_type(s); }
|
|
|
|
auto t =
|
|
|
|
T_closure_ptr(tn, T_struct([T_ptr(T_nil()), T_ptr(T_nil())]), T_nil(),
|
|
|
|
0u);
|
2011-02-17 18:16:51 -08:00
|
|
|
tn.associate(s, t);
|
|
|
|
ret t;
|
2011-01-07 15:12:23 -08:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn T_tag(&type_names tn, uint size) -> TypeRef {
|
2011-05-17 20:41:41 +02:00
|
|
|
auto s = "tag_" + uint::to_str(size, 10u);
|
2011-06-15 11:19:50 -07:00
|
|
|
if (tn.name_has_type(s)) { ret tn.get_type(s); }
|
2011-05-13 16:09:17 -04:00
|
|
|
auto t = T_struct([T_int(), T_array(T_i8(), size)]);
|
2011-03-04 15:08:33 -08:00
|
|
|
tn.associate(s, t);
|
|
|
|
ret t;
|
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn T_opaque_tag(&type_names tn) -> TypeRef {
|
2011-04-07 14:28:57 -07:00
|
|
|
auto s = "opaque_tag";
|
2011-06-15 11:19:50 -07:00
|
|
|
if (tn.name_has_type(s)) { ret tn.get_type(s); }
|
2011-05-16 18:21:22 -07:00
|
|
|
auto t = T_struct([T_int(), T_i8()]);
|
2011-03-03 15:52:54 -08:00
|
|
|
tn.associate(s, t);
|
|
|
|
ret t;
|
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn T_opaque_tag_ptr(&type_names tn) -> TypeRef {
|
2011-03-04 15:08:33 -08:00
|
|
|
ret T_ptr(T_opaque_tag(tn));
|
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn T_captured_tydescs(&type_names tn, uint n) -> TypeRef {
|
2011-05-17 20:41:41 +02:00
|
|
|
ret T_struct(vec::init_elt[TypeRef](T_ptr(T_tydesc(tn)), n));
|
2011-02-03 14:40:57 -08:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn T_obj_ptr(&type_names tn, uint n_captured_tydescs) -> TypeRef {
|
2011-03-03 11:49:35 -08:00
|
|
|
// This function is not publicly exposed because it returns an incomplete
|
|
|
|
// type. The dynamically-sized fields follow the captured tydescs.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-03 11:49:35 -08:00
|
|
|
fn T_obj(type_names tn, uint n_captured_tydescs) -> TypeRef {
|
2011-05-16 18:21:22 -07:00
|
|
|
ret T_struct([T_ptr(T_tydesc(tn)),
|
2011-06-15 11:19:50 -07:00
|
|
|
T_captured_tydescs(tn, n_captured_tydescs)]);
|
2011-03-03 11:49:35 -08:00
|
|
|
}
|
|
|
|
ret T_ptr(T_box(T_obj(tn, n_captured_tydescs)));
|
2011-02-03 14:40:57 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn T_opaque_obj_ptr(&type_names tn) -> TypeRef { ret T_obj_ptr(tn, 0u); }
|
2011-02-03 14:40:57 -08:00
|
|
|
|
2011-05-10 14:03:47 -07:00
|
|
|
fn T_opaque_port_ptr() -> TypeRef { ret T_ptr(T_i8()); }
|
2011-05-09 15:32:12 -07:00
|
|
|
|
2011-05-10 14:03:47 -07:00
|
|
|
fn T_opaque_chan_ptr() -> TypeRef { ret T_ptr(T_i8()); }
|
2011-05-09 15:32:12 -07:00
|
|
|
|
2011-01-07 15:12:23 -08:00
|
|
|
|
2011-03-03 14:10:36 -08:00
|
|
|
// This function now fails if called on a type with dynamic size (as its
|
|
|
|
// return value was always meaningless in that case anyhow). Beware!
|
|
|
|
//
|
|
|
|
// TODO: Enforce via a predicate.
|
2011-05-31 18:24:06 -07:00
|
|
|
fn type_of(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef {
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_has_dynamic_size(cx.tcx, t)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.sess.span_err(sp,
|
|
|
|
"type_of() called on a type with dynamic size: " +
|
|
|
|
ty_to_str(cx.tcx, t));
|
2011-03-03 14:10:36 -08:00
|
|
|
}
|
2011-05-18 15:35:16 -07:00
|
|
|
ret type_of_inner(cx, sp, t);
|
2010-11-20 22:04:34 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn type_of_explicit_args(&@crate_ctxt cx, &span sp, &vec[ty::arg] inputs) ->
|
|
|
|
vec[TypeRef] {
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[TypeRef] atys = [];
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ty::arg arg in inputs) {
|
|
|
|
if (ty::type_has_dynamic_size(cx.tcx, arg.ty)) {
|
2011-06-10 12:03:50 +02:00
|
|
|
assert (arg.mode != ty::mo_val);
|
2011-05-16 18:21:22 -07:00
|
|
|
atys += [T_typaram_ptr(cx.tn)];
|
2011-02-16 16:16:11 -05:00
|
|
|
} else {
|
2011-06-15 11:19:50 -07:00
|
|
|
let TypeRef t;
|
2011-02-16 16:16:11 -05:00
|
|
|
alt (arg.mode) {
|
2011-06-10 12:03:50 +02:00
|
|
|
case (ty::mo_alias(_)) {
|
2011-05-18 15:35:16 -07:00
|
|
|
t = T_ptr(type_of_inner(cx, sp, arg.ty));
|
2011-03-04 15:08:33 -08:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { t = type_of_inner(cx, sp, arg.ty); }
|
2011-02-16 16:16:11 -05:00
|
|
|
}
|
2011-05-16 18:21:22 -07:00
|
|
|
atys += [t];
|
2011-02-16 16:16:11 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ret atys;
|
|
|
|
}
|
2011-02-08 11:47:53 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-02-08 11:47:53 -08:00
|
|
|
// NB: must keep 4 fns in sync:
|
|
|
|
//
|
|
|
|
// - type_of_fn_full
|
|
|
|
// - create_llargs_for_fn_args.
|
|
|
|
// - new_fn_ctxt
|
|
|
|
// - trans_args
|
2011-06-15 11:19:50 -07:00
|
|
|
fn type_of_fn_full(&@crate_ctxt cx, &span sp, ast::proto proto,
|
|
|
|
&option::t[TypeRef] obj_self, &vec[ty::arg] inputs,
|
|
|
|
&ty::t output, uint ty_param_count) -> TypeRef {
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[TypeRef] atys = [];
|
2011-02-08 11:47:53 -08:00
|
|
|
// Arg 0: Output pointer.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_has_dynamic_size(cx.tcx, output)) {
|
2011-05-16 18:21:22 -07:00
|
|
|
atys += [T_typaram_ptr(cx.tn)];
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { atys += [T_ptr(type_of_inner(cx, sp, output))]; }
|
2011-05-12 17:24:54 +02:00
|
|
|
// Arg 1: task pointer.
|
2011-02-08 11:47:53 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
atys += [T_taskptr(cx.tn)];
|
2011-02-08 11:47:53 -08:00
|
|
|
// Arg 2: Env (closure-bindings / self-obj)
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-12-23 17:31:16 -08:00
|
|
|
alt (obj_self) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (some(?t)) { assert (t as int != 0); atys += [t]; }
|
|
|
|
case (_) { atys += [T_opaque_closure_ptr(cx.tn)]; }
|
2010-12-23 17:31:16 -08:00
|
|
|
}
|
2011-02-09 09:54:58 -08:00
|
|
|
// Args >3: ty params, if not acquired via capture...
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-02-09 09:54:58 -08:00
|
|
|
if (obj_self == none[TypeRef]) {
|
|
|
|
auto i = 0u;
|
|
|
|
while (i < ty_param_count) {
|
2011-05-16 18:21:22 -07:00
|
|
|
atys += [T_ptr(T_tydesc(cx.tn))];
|
2011-02-09 09:54:58 -08:00
|
|
|
i += 1u;
|
|
|
|
}
|
2011-02-08 11:47:53 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
if (proto == ast::proto_iter) {
|
2011-02-17 12:20:55 -08:00
|
|
|
// If it's an iter, the 'output' type of the iter is actually the
|
|
|
|
// *input* type of the function we're given as our iter-block
|
|
|
|
// argument.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-16 14:58:02 -07:00
|
|
|
atys +=
|
2011-05-16 18:21:22 -07:00
|
|
|
[T_fn_pair(cx.tn,
|
2011-05-18 15:35:16 -07:00
|
|
|
type_of_fn_full(cx, sp, ast::proto_fn, none[TypeRef],
|
2011-06-10 12:03:50 +02:00
|
|
|
[rec(mode=ty::mo_alias(false),
|
2011-06-15 11:19:50 -07:00
|
|
|
ty=output)], ty::mk_nil(cx.tcx),
|
|
|
|
0u))];
|
2011-02-17 12:20:55 -08:00
|
|
|
}
|
2011-02-08 11:47:53 -08:00
|
|
|
// ... then explicit args.
|
2010-12-16 10:23:47 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
atys += type_of_explicit_args(cx, sp, inputs);
|
2011-05-12 17:24:54 +02:00
|
|
|
ret T_fn(atys, llvm::LLVMVoidType());
|
2010-12-16 10:23:47 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn type_of_fn(&@crate_ctxt cx, &span sp, ast::proto proto,
|
|
|
|
&vec[ty::arg] inputs, &ty::t output, uint ty_param_count) ->
|
|
|
|
TypeRef {
|
2011-05-18 15:35:16 -07:00
|
|
|
ret type_of_fn_full(cx, sp, proto, none[TypeRef], inputs, output,
|
2011-03-08 16:51:23 -08:00
|
|
|
ty_param_count);
|
2010-12-23 17:31:16 -08:00
|
|
|
}
|
|
|
|
|
2011-05-31 18:24:06 -07:00
|
|
|
fn type_of_native_fn(&@crate_ctxt cx, &span sp, ast::native_abi abi,
|
2011-06-15 11:19:50 -07:00
|
|
|
&vec[ty::arg] inputs, &ty::t output, uint ty_param_count)
|
|
|
|
-> TypeRef {
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[TypeRef] atys = [];
|
2011-05-12 17:24:54 +02:00
|
|
|
if (abi == ast::native_abi_rust) {
|
2011-05-16 18:21:22 -07:00
|
|
|
atys += [T_taskptr(cx.tn)];
|
2011-05-12 17:24:54 +02:00
|
|
|
auto t = ty::ty_native_fn(abi, inputs, output);
|
2011-02-28 10:37:49 -05:00
|
|
|
auto i = 0u;
|
|
|
|
while (i < ty_param_count) {
|
2011-05-16 18:21:22 -07:00
|
|
|
atys += [T_ptr(T_tydesc(cx.tn))];
|
2011-02-28 10:37:49 -05:00
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
}
|
2011-05-18 15:35:16 -07:00
|
|
|
atys += type_of_explicit_args(cx, sp, inputs);
|
|
|
|
ret T_fn(atys, type_of_inner(cx, sp, output));
|
2011-02-16 16:16:11 -05:00
|
|
|
}
|
|
|
|
|
2011-05-31 18:24:06 -07:00
|
|
|
fn type_of_inner(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef {
|
2011-04-19 16:40:46 -07:00
|
|
|
// Check the cache.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
if (cx.lltypes.contains_key(t)) { ret cx.lltypes.get(t); }
|
2011-02-25 16:24:19 -08:00
|
|
|
let TypeRef llty = 0 as TypeRef;
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(cx.tcx, t)) {
|
|
|
|
case (ty::ty_native) { llty = T_ptr(T_i8()); }
|
|
|
|
case (ty::ty_nil) { llty = T_nil(); }
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_bot) {
|
|
|
|
llty = T_nil(); /* ...I guess? */
|
|
|
|
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_bool) { llty = T_bool(); }
|
|
|
|
case (ty::ty_int) { llty = T_int(); }
|
|
|
|
case (ty::ty_float) { llty = T_float(); }
|
|
|
|
case (ty::ty_uint) { llty = T_int(); }
|
|
|
|
case (ty::ty_machine(?tm)) {
|
2010-10-19 14:54:10 -07:00
|
|
|
alt (tm) {
|
2011-05-12 17:24:54 +02:00
|
|
|
case (common::ty_i8) { llty = T_i8(); }
|
|
|
|
case (common::ty_u8) { llty = T_i8(); }
|
|
|
|
case (common::ty_i16) { llty = T_i16(); }
|
|
|
|
case (common::ty_u16) { llty = T_i16(); }
|
|
|
|
case (common::ty_i32) { llty = T_i32(); }
|
|
|
|
case (common::ty_u32) { llty = T_i32(); }
|
|
|
|
case (common::ty_i64) { llty = T_i64(); }
|
|
|
|
case (common::ty_u64) { llty = T_i64(); }
|
|
|
|
case (common::ty_f32) { llty = T_f32(); }
|
|
|
|
case (common::ty_f64) { llty = T_f64(); }
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_char) { llty = T_char(); }
|
|
|
|
case (ty::ty_str) { llty = T_ptr(T_str()); }
|
2011-06-12 00:44:43 -07:00
|
|
|
case (ty::ty_istr) { llty = T_ivec(T_i8()); }
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_tag(_, _)) {
|
|
|
|
if (ty::type_has_dynamic_size(cx.tcx, t)) {
|
2011-03-04 15:08:33 -08:00
|
|
|
llty = T_opaque_tag(cx.tn);
|
|
|
|
} else {
|
2011-05-18 15:35:16 -07:00
|
|
|
auto size = static_size_of_tag(cx, sp, t);
|
2011-03-04 15:08:33 -08:00
|
|
|
llty = T_tag(cx.tn, size);
|
|
|
|
}
|
2010-12-01 19:03:47 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_box(?mt)) {
|
2011-05-18 15:35:16 -07:00
|
|
|
llty = T_ptr(T_box(type_of_inner(cx, sp, mt.ty)));
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_vec(?mt)) {
|
2011-05-18 15:35:16 -07:00
|
|
|
llty = T_ptr(T_vec(type_of_inner(cx, sp, mt.ty)));
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2011-06-10 12:07:38 -07:00
|
|
|
case (ty::ty_ivec(?mt)) {
|
2011-06-12 00:44:43 -07:00
|
|
|
if (ty::type_has_dynamic_size(cx.tcx, mt.ty)) {
|
|
|
|
llty = T_opaque_ivec();
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { llty = T_ivec(type_of_inner(cx, sp, mt.ty)); }
|
2011-06-03 15:02:58 -04:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_ptr(?mt)) { llty = T_ptr(type_of_inner(cx, sp, mt.ty)); }
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_port(?t)) {
|
2011-05-18 15:35:16 -07:00
|
|
|
llty = T_ptr(T_port(type_of_inner(cx, sp, t)));
|
2011-03-16 21:49:15 -04:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_chan(?t)) {
|
2011-05-18 15:35:16 -07:00
|
|
|
llty = T_ptr(T_chan(type_of_inner(cx, sp, t)));
|
2011-03-16 21:49:15 -04:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_task) { llty = T_taskptr(cx.tn); }
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_tup(?elts)) {
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[TypeRef] tys = [];
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ty::mt elt in elts) {
|
2011-05-18 15:35:16 -07:00
|
|
|
tys += [type_of_inner(cx, sp, elt.ty)];
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2011-02-25 16:24:19 -08:00
|
|
|
llty = T_struct(tys);
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_rec(?fields)) {
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[TypeRef] tys = [];
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ty::field f in fields) {
|
2011-05-18 15:35:16 -07:00
|
|
|
tys += [type_of_inner(cx, sp, f.mt.ty)];
|
2010-11-30 10:39:35 -08:00
|
|
|
}
|
2011-02-25 16:24:19 -08:00
|
|
|
llty = T_struct(tys);
|
2010-11-30 10:39:35 -08:00
|
|
|
}
|
2011-06-09 09:48:16 -07:00
|
|
|
case (ty::ty_fn(?proto, ?args, ?out, _, _)) {
|
2011-05-18 15:35:16 -07:00
|
|
|
llty = T_fn_pair(cx.tn, type_of_fn(cx, sp, proto, args, out, 0u));
|
2010-12-16 10:23:47 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_native_fn(?abi, ?args, ?out)) {
|
2011-05-18 15:35:16 -07:00
|
|
|
auto nft = native_fn_wrapper_type(cx, sp, 0u, t);
|
2011-03-18 15:01:45 -07:00
|
|
|
llty = T_fn_pair(cx.tn, nft);
|
2011-02-16 16:16:11 -05:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_obj(?meths)) {
|
2010-12-23 17:31:16 -08:00
|
|
|
auto th = mk_type_handle();
|
2011-05-12 17:24:54 +02:00
|
|
|
auto self_ty = llvm::LLVMResolveTypeHandle(th.llth);
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[TypeRef] mtys = [T_ptr(T_i8())];
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ty::method m in meths) {
|
2010-12-23 17:31:16 -08:00
|
|
|
let TypeRef mty =
|
2011-06-15 11:19:50 -07:00
|
|
|
type_of_fn_full(cx, sp, m.proto, some[TypeRef](self_ty),
|
2011-03-08 16:51:23 -08:00
|
|
|
m.inputs, m.output, 0u);
|
2011-05-16 18:21:22 -07:00
|
|
|
mtys += [T_ptr(mty)];
|
2010-12-13 16:12:45 -08:00
|
|
|
}
|
2010-12-16 10:23:47 -08:00
|
|
|
let TypeRef vtbl = T_struct(mtys);
|
2011-06-15 11:19:50 -07:00
|
|
|
let TypeRef pair =
|
|
|
|
T_struct([T_ptr(vtbl), T_opaque_obj_ptr(cx.tn)]);
|
2011-05-12 17:24:54 +02:00
|
|
|
auto abs_pair = llvm::LLVMResolveTypeHandle(th.llth);
|
|
|
|
llvm::LLVMRefineType(abs_pair, pair);
|
|
|
|
abs_pair = llvm::LLVMResolveTypeHandle(th.llth);
|
2011-02-25 16:24:19 -08:00
|
|
|
llty = abs_pair;
|
2010-11-19 20:08:57 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_var(_)) {
|
2011-06-04 18:13:00 -07:00
|
|
|
cx.tcx.sess.span_err(sp, "trans::type_of called on ty_var");
|
2010-12-16 12:23:48 -08:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_param(_)) { llty = T_i8(); }
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_type) { llty = T_ptr(T_tydesc(cx.tn)); }
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2011-05-02 17:47:24 -07:00
|
|
|
assert (llty as int != 0);
|
2011-05-10 16:43:34 -07:00
|
|
|
if (cx.sess.get_opts().save_temps) {
|
2011-06-15 11:19:50 -07:00
|
|
|
llvm::LLVMAddTypeName(cx.llmod, str::buf(ty_to_short_str(cx.tcx, t)),
|
|
|
|
llty);
|
2011-05-10 16:43:34 -07:00
|
|
|
}
|
2011-04-19 16:40:46 -07:00
|
|
|
cx.lltypes.insert(t, llty);
|
2011-02-25 16:24:19 -08:00
|
|
|
ret llty;
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
|
|
|
|
2011-05-31 18:24:06 -07:00
|
|
|
fn type_of_arg(@local_ctxt cx, &span sp, &ty::arg arg) -> TypeRef {
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(cx.ccx.tcx, arg.ty)) {
|
|
|
|
case (ty::ty_param(_)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
if (arg.mode != ty::mo_val) { ret T_typaram_ptr(cx.ccx.tn); }
|
2011-03-02 16:13:33 -08:00
|
|
|
}
|
|
|
|
case (_) {
|
|
|
|
// fall through
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-02 16:13:33 -08:00
|
|
|
}
|
|
|
|
}
|
2011-03-04 15:08:33 -08:00
|
|
|
auto typ;
|
2011-06-10 12:03:50 +02:00
|
|
|
if (arg.mode != ty::mo_val) {
|
2011-05-18 15:35:16 -07:00
|
|
|
typ = T_ptr(type_of_inner(cx.ccx, sp, arg.ty));
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { typ = type_of_inner(cx.ccx, sp, arg.ty); }
|
2011-03-02 16:13:33 -08:00
|
|
|
ret typ;
|
2010-12-06 16:50:24 -08:00
|
|
|
}
|
|
|
|
|
2011-05-31 18:24:06 -07:00
|
|
|
fn type_of_ty_param_count_and_ty(@local_ctxt lcx, &span sp,
|
2011-05-12 17:24:54 +02:00
|
|
|
&ty::ty_param_count_and_ty tpt) -> TypeRef {
|
|
|
|
alt (ty::struct(lcx.ccx.tcx, tpt._1)) {
|
2011-06-09 09:48:16 -07:00
|
|
|
case (ty::ty_fn(?proto, ?inputs, ?output, _, _)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llfnty =
|
|
|
|
type_of_fn(lcx.ccx, sp, proto, inputs, output, tpt._0);
|
2011-04-17 14:24:45 +02:00
|
|
|
ret T_fn_pair(lcx.ccx.tn, llfnty);
|
2011-03-30 18:15:29 -07:00
|
|
|
}
|
|
|
|
case (_) {
|
|
|
|
// fall through
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-30 18:15:29 -07:00
|
|
|
}
|
|
|
|
}
|
2011-05-18 15:35:16 -07:00
|
|
|
ret type_of(lcx.ccx, sp, tpt._1);
|
2011-03-30 18:15:29 -07:00
|
|
|
}
|
|
|
|
|
2011-06-10 19:35:59 -07:00
|
|
|
fn type_of_or_i8(&@block_ctxt bcx, ty::t typ) -> TypeRef {
|
2011-06-15 11:19:50 -07:00
|
|
|
if (ty::type_has_dynamic_size(bcx.fcx.lcx.ccx.tcx, typ)) { ret T_i8(); }
|
2011-06-10 19:35:59 -07:00
|
|
|
ret type_of(bcx.fcx.lcx.ccx, bcx.sp, typ);
|
|
|
|
}
|
|
|
|
|
2011-03-30 18:15:29 -07:00
|
|
|
|
2010-12-10 15:02:23 -08:00
|
|
|
// Name sanitation. LLVM will happily accept identifiers with weird names, but
|
|
|
|
// gas doesn't!
|
2011-05-11 04:58:46 +00:00
|
|
|
fn sanitize(&str s) -> str {
|
2010-12-10 15:02:23 -08:00
|
|
|
auto result = "";
|
|
|
|
for (u8 c in s) {
|
2011-06-15 11:19:50 -07:00
|
|
|
if (c == '@' as u8) {
|
2010-12-10 15:02:23 -08:00
|
|
|
result += "boxed_";
|
|
|
|
} else {
|
2011-06-15 11:19:50 -07:00
|
|
|
if (c == ',' as u8) {
|
2010-12-20 19:52:14 -08:00
|
|
|
result += "_";
|
|
|
|
} else {
|
2011-06-15 11:19:50 -07:00
|
|
|
if (c == '{' as u8 || c == '(' as u8) {
|
2010-12-20 19:52:14 -08:00
|
|
|
result += "_of_";
|
|
|
|
} else {
|
2011-06-15 11:19:50 -07:00
|
|
|
if (c != 10u8 && c != '}' as u8 && c != ')' as u8 &&
|
|
|
|
c != ' ' as u8 && c != '\t' as u8 &&
|
|
|
|
c != ';' as u8) {
|
2011-05-16 18:21:22 -07:00
|
|
|
auto v = [c];
|
2011-05-17 20:41:41 +02:00
|
|
|
result += str::from_bytes(v);
|
2010-12-20 19:52:14 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ret result;
|
|
|
|
}
|
|
|
|
|
2010-09-24 14:56:04 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
// LLVM constant constructors.
|
|
|
|
fn C_null(TypeRef t) -> ValueRef { ret llvm::LLVMConstNull(t); }
|
2010-09-24 14:56:04 -07:00
|
|
|
|
2011-05-07 18:54:23 +00:00
|
|
|
fn C_integral(TypeRef t, uint u, Bool sign_extend) -> ValueRef {
|
2011-05-12 17:24:54 +02:00
|
|
|
// FIXME: We can't use LLVM::ULongLong with our existing minimal native
|
2011-05-07 18:54:23 +00:00
|
|
|
// API, which only knows word-sized args.
|
2010-09-24 14:56:04 -07:00
|
|
|
//
|
2011-05-12 17:24:54 +02:00
|
|
|
// ret llvm::LLVMConstInt(T_int(), t as LLVM::ULongLong, False);
|
2010-09-24 14:56:04 -07:00
|
|
|
//
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
ret llvm::LLVMRustConstSmallInt(t, u, sign_extend);
|
2010-09-28 12:23:40 -07:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn C_float(&str s) -> ValueRef {
|
2011-05-17 20:41:41 +02:00
|
|
|
ret llvm::LLVMConstRealOfString(T_float(), str::buf(s));
|
2011-03-21 17:12:05 -07:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn C_floating(&str s, TypeRef t) -> ValueRef {
|
2011-05-17 20:41:41 +02:00
|
|
|
ret llvm::LLVMConstRealOfString(t, str::buf(s));
|
2011-03-22 17:25:40 -07:00
|
|
|
}
|
|
|
|
|
2010-10-04 15:55:12 -07:00
|
|
|
fn C_nil() -> ValueRef {
|
|
|
|
// NB: See comment above in T_void().
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-07 18:54:23 +00:00
|
|
|
ret C_integral(T_i1(), 0u, False);
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
|
|
|
|
2010-09-28 14:01:21 -07:00
|
|
|
fn C_bool(bool b) -> ValueRef {
|
|
|
|
if (b) {
|
2011-05-07 18:54:23 +00:00
|
|
|
ret C_integral(T_bool(), 1u, False);
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { ret C_integral(T_bool(), 0u, False); }
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn C_int(int i) -> ValueRef { ret C_integral(T_int(), i as uint, True); }
|
2010-09-24 14:56:04 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn C_uint(uint i) -> ValueRef { ret C_integral(T_int(), i, False); }
|
|
|
|
|
|
|
|
fn C_u8(uint i) -> ValueRef { ret C_integral(T_i8(), i, False); }
|
2011-06-10 19:35:59 -07:00
|
|
|
|
2011-04-19 15:22:57 -07:00
|
|
|
|
2011-01-21 12:09:25 -08:00
|
|
|
// This is a 'c-like' raw string, which differs from
|
|
|
|
// our boxed-and-length-annotated strings.
|
2011-05-11 04:58:46 +00:00
|
|
|
fn C_cstr(&@crate_ctxt cx, &str s) -> ValueRef {
|
2011-05-17 20:41:41 +02:00
|
|
|
auto sc = llvm::LLVMConstString(str::buf(s), str::byte_len(s), False);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto g =
|
|
|
|
llvm::LLVMAddGlobal(cx.llmod, val_ty(sc),
|
|
|
|
str::buf(cx.names.next("str")));
|
2011-05-12 17:24:54 +02:00
|
|
|
llvm::LLVMSetInitializer(g, sc);
|
|
|
|
llvm::LLVMSetGlobalConstant(g, True);
|
2011-06-15 11:19:50 -07:00
|
|
|
llvm::LLVMSetLinkage(g, lib::llvm::LLVMInternalLinkage as llvm::Linkage);
|
2010-09-28 12:23:40 -07:00
|
|
|
ret g;
|
2010-09-24 14:56:04 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-01-21 12:09:25 -08:00
|
|
|
// A rust boxed-and-length-annotated string.
|
2011-05-11 04:58:46 +00:00
|
|
|
fn C_str(&@crate_ctxt cx, &str s) -> ValueRef {
|
2011-05-17 20:41:41 +02:00
|
|
|
auto len = str::byte_len(s);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto box =
|
|
|
|
C_struct([C_int(abi::const_refcount as int),
|
|
|
|
C_int(len + 1u as int), // 'alloc'
|
|
|
|
C_int(len + 1u as int), // 'fill'
|
|
|
|
C_int(0), // 'pad'
|
|
|
|
llvm::LLVMConstString(str::buf(s), len, False)]);
|
|
|
|
auto g =
|
|
|
|
llvm::LLVMAddGlobal(cx.llmod, val_ty(box),
|
|
|
|
str::buf(cx.names.next("str")));
|
2011-05-12 17:24:54 +02:00
|
|
|
llvm::LLVMSetInitializer(g, box);
|
|
|
|
llvm::LLVMSetGlobalConstant(g, True);
|
2011-06-15 11:19:50 -07:00
|
|
|
llvm::LLVMSetLinkage(g, lib::llvm::LLVMInternalLinkage as llvm::Linkage);
|
2011-05-12 17:24:54 +02:00
|
|
|
ret llvm::LLVMConstPointerCast(g, T_ptr(T_str()));
|
2011-01-21 12:09:25 -08:00
|
|
|
}
|
|
|
|
|
2010-12-03 16:55:59 -08:00
|
|
|
fn C_zero_byte_arr(uint size) -> ValueRef {
|
|
|
|
auto i = 0u;
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ValueRef] elts = [];
|
2011-06-15 11:19:50 -07:00
|
|
|
while (i < size) { elts += [C_u8(0u)]; i += 1u; }
|
2011-05-17 20:41:41 +02:00
|
|
|
ret llvm::LLVMConstArray(T_i8(), vec::buf[ValueRef](elts),
|
2011-06-15 11:19:50 -07:00
|
|
|
vec::len[ValueRef](elts));
|
2010-12-03 16:55:59 -08:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn C_struct(&vec[ValueRef] elts) -> ValueRef {
|
2011-05-17 20:41:41 +02:00
|
|
|
ret llvm::LLVMConstStruct(vec::buf[ValueRef](elts),
|
2011-06-15 11:19:50 -07:00
|
|
|
vec::len[ValueRef](elts), False);
|
2010-09-24 14:56:04 -07:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn C_array(TypeRef ty, &vec[ValueRef] elts) -> ValueRef {
|
2011-05-17 20:41:41 +02:00
|
|
|
ret llvm::LLVMConstArray(ty, vec::buf[ValueRef](elts),
|
2011-06-15 11:19:50 -07:00
|
|
|
vec::len[ValueRef](elts));
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn decl_fn(ModuleRef llmod, &str name, uint cc, TypeRef llty) -> ValueRef {
|
2011-06-15 11:19:50 -07:00
|
|
|
let ValueRef llfn = llvm::LLVMAddFunction(llmod, str::buf(name), llty);
|
2011-05-12 17:24:54 +02:00
|
|
|
llvm::LLVMSetFunctionCallConv(llfn, cc);
|
2010-09-23 17:16:34 -07:00
|
|
|
ret llfn;
|
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn decl_cdecl_fn(ModuleRef llmod, &str name, TypeRef llty) -> ValueRef {
|
2011-05-12 17:24:54 +02:00
|
|
|
ret decl_fn(llmod, name, lib::llvm::LLVMCCallConv, llty);
|
2010-11-14 12:28:07 -08:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn decl_fastcall_fn(ModuleRef llmod, &str name, TypeRef llty) -> ValueRef {
|
2011-05-12 17:24:54 +02:00
|
|
|
ret decl_fn(llmod, name, lib::llvm::LLVMFastCallConv, llty);
|
2010-11-14 12:28:07 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-15 19:53:06 -04:00
|
|
|
// Only use this if you are going to actually define the function. It's
|
|
|
|
// not valid to simply declare a function as internal.
|
2011-06-15 11:19:50 -07:00
|
|
|
fn decl_internal_fastcall_fn(ModuleRef llmod, &str name, TypeRef llty) ->
|
|
|
|
ValueRef {
|
2011-05-12 17:24:54 +02:00
|
|
|
auto llfn = decl_fn(llmod, name, lib::llvm::LLVMFastCallConv, llty);
|
2011-06-15 11:19:50 -07:00
|
|
|
llvm::LLVMSetLinkage(llfn,
|
|
|
|
lib::llvm::LLVMInternalLinkage as llvm::Linkage);
|
2011-03-26 19:14:07 -07:00
|
|
|
ret llfn;
|
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn decl_glue(ModuleRef llmod, type_names tn, &str s) -> ValueRef {
|
2011-05-16 18:21:22 -07:00
|
|
|
ret decl_cdecl_fn(llmod, s, T_fn([T_taskptr(tn)], T_void()));
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn get_extern_fn(&hashmap[str, ValueRef] externs, ModuleRef llmod, &str name,
|
2011-03-25 17:59:45 -07:00
|
|
|
uint cc, TypeRef ty) -> ValueRef {
|
2011-06-15 11:19:50 -07:00
|
|
|
if (externs.contains_key(name)) { ret externs.get(name); }
|
2011-03-25 17:59:45 -07:00
|
|
|
auto f = decl_fn(llmod, name, cc, ty);
|
2011-03-25 15:48:00 -07:00
|
|
|
externs.insert(name, f);
|
2010-09-23 18:38:37 -07:00
|
|
|
ret f;
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn get_extern_const(&hashmap[str, ValueRef] externs, ModuleRef llmod,
|
|
|
|
&str name, TypeRef ty) -> ValueRef {
|
|
|
|
if (externs.contains_key(name)) { ret externs.get(name); }
|
2011-05-17 20:41:41 +02:00
|
|
|
auto c = llvm::LLVMAddGlobal(llmod, ty, str::buf(name));
|
2011-03-25 17:59:45 -07:00
|
|
|
externs.insert(name, c);
|
|
|
|
ret c;
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn get_simple_extern_fn(&hashmap[str, ValueRef] externs, ModuleRef llmod,
|
|
|
|
&str name, int n_args) -> ValueRef {
|
2011-05-17 20:41:41 +02:00
|
|
|
auto inputs = vec::init_elt[TypeRef](T_int(), n_args as uint);
|
2011-03-25 17:59:45 -07:00
|
|
|
auto output = T_int();
|
|
|
|
auto t = T_fn(inputs, output);
|
2011-05-12 17:24:54 +02:00
|
|
|
ret get_extern_fn(externs, llmod, name, lib::llvm::LLVMCCallConv, t);
|
2011-03-25 17:59:45 -07:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn trans_native_call(&builder b, @glue_fns glues, ValueRef lltaskptr,
|
2011-06-15 11:19:50 -07:00
|
|
|
&hashmap[str, ValueRef] externs, &type_names tn,
|
|
|
|
ModuleRef llmod, &str name, bool pass_task,
|
|
|
|
&vec[ValueRef] args) -> ValueRef {
|
|
|
|
let int n = vec::len[ValueRef](args) as int;
|
2011-03-25 17:59:45 -07:00
|
|
|
let ValueRef llnative = get_simple_extern_fn(externs, llmod, name, n);
|
2011-05-26 16:42:17 -07:00
|
|
|
let vec[ValueRef] call_args = [];
|
2011-06-15 11:19:50 -07:00
|
|
|
for (ValueRef a in args) { call_args += [b.ZExtOrBitCast(a, T_int())]; }
|
2011-05-26 16:42:17 -07:00
|
|
|
ret b.Call(llnative, call_args);
|
2010-09-24 14:56:04 -07:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn trans_non_gc_free(&@block_ctxt cx, ValueRef v) -> result {
|
2011-05-10 14:03:47 -07:00
|
|
|
cx.build.Call(cx.fcx.lcx.ccx.upcalls.free,
|
2011-06-15 11:19:50 -07:00
|
|
|
[cx.fcx.lltaskptr, cx.build.PointerCast(v, T_ptr(T_i8())),
|
|
|
|
C_int(0)]);
|
2011-05-10 14:03:47 -07:00
|
|
|
ret res(cx, C_int(0));
|
2010-09-29 17:22:07 -07:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn find_scope_cx(&@block_ctxt cx) -> @block_ctxt {
|
2011-06-15 11:19:50 -07:00
|
|
|
if (cx.kind != NON_SCOPE_BLOCK) { ret cx; }
|
2010-12-02 19:12:34 -08:00
|
|
|
alt (cx.parent) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (parent_some(?b)) { be find_scope_cx(b); }
|
2010-12-02 19:12:34 -08:00
|
|
|
case (parent_none) {
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.fcx.lcx.ccx.sess.bug("trans::find_scope_cx() " +
|
|
|
|
"called on parentless block_ctxt");
|
2010-12-02 19:12:34 -08:00
|
|
|
}
|
|
|
|
}
|
2011-03-31 21:20:10 -04:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn umax(&@block_ctxt cx, ValueRef a, ValueRef b) -> ValueRef {
|
2011-05-12 17:24:54 +02:00
|
|
|
auto cond = cx.build.ICmp(lib::llvm::LLVMIntULT, a, b);
|
2011-01-18 15:38:35 -08:00
|
|
|
ret cx.build.Select(cond, b, a);
|
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn umin(&@block_ctxt cx, ValueRef a, ValueRef b) -> ValueRef {
|
2011-05-12 17:24:54 +02:00
|
|
|
auto cond = cx.build.ICmp(lib::llvm::LLVMIntULT, a, b);
|
2011-03-09 20:14:19 -08:00
|
|
|
ret cx.build.Select(cond, a, b);
|
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn align_to(&@block_ctxt cx, ValueRef off, ValueRef align) -> ValueRef {
|
2011-01-18 15:38:35 -08:00
|
|
|
auto mask = cx.build.Sub(align, C_int(1));
|
|
|
|
auto bumped = cx.build.Add(off, mask);
|
|
|
|
ret cx.build.And(bumped, cx.build.Not(mask));
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-04 15:08:33 -08:00
|
|
|
// Returns the real size of the given type for the current target.
|
2011-05-11 04:58:46 +00:00
|
|
|
fn llsize_of_real(&@crate_ctxt cx, TypeRef t) -> uint {
|
2011-05-12 17:24:54 +02:00
|
|
|
ret llvm::LLVMStoreSizeOfType(cx.td.lltd, t);
|
2011-03-04 15:08:33 -08:00
|
|
|
}
|
|
|
|
|
2011-01-18 15:38:35 -08:00
|
|
|
fn llsize_of(TypeRef t) -> ValueRef {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret llvm::LLVMConstIntCast(lib::llvm::llvm::LLVMSizeOf(t), T_int(),
|
|
|
|
False);
|
2010-12-20 12:54:50 -08:00
|
|
|
}
|
|
|
|
|
2011-01-18 15:38:35 -08:00
|
|
|
fn llalign_of(TypeRef t) -> ValueRef {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret llvm::LLVMConstIntCast(lib::llvm::llvm::LLVMAlignOf(t), T_int(),
|
|
|
|
False);
|
2010-12-20 12:54:50 -08:00
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn size_of(&@block_ctxt cx, &ty::t t) -> result {
|
|
|
|
if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-05-18 15:35:16 -07:00
|
|
|
ret res(cx, llsize_of(type_of(cx.fcx.lcx.ccx, cx.sp, t)));
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
|
|
|
ret dynamic_size_of(cx, t);
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn align_of(&@block_ctxt cx, &ty::t t) -> result {
|
|
|
|
if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-05-18 15:35:16 -07:00
|
|
|
ret res(cx, llalign_of(type_of(cx.fcx.lcx.ccx, cx.sp, t)));
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
|
|
|
ret dynamic_align_of(cx, t);
|
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn alloca(&@block_ctxt cx, TypeRef t) -> ValueRef {
|
2011-03-28 18:04:52 -07:00
|
|
|
ret new_builder(cx.fcx.llallocas).Alloca(t);
|
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn array_alloca(&@block_ctxt cx, TypeRef t, ValueRef n) -> ValueRef {
|
2011-03-28 18:04:52 -07:00
|
|
|
ret new_builder(cx.fcx.llallocas).ArrayAlloca(t, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-04-15 10:18:23 -07:00
|
|
|
// Creates a simpler, size-equivalent type. The resulting type is guaranteed
|
|
|
|
// to have (a) the same size as the type that was passed in; (b) to be non-
|
|
|
|
// recursive. This is done by replacing all boxes in a type with boxed unit
|
|
|
|
// types.
|
2011-05-12 17:24:54 +02:00
|
|
|
fn simplify_type(&@crate_ctxt ccx, &ty::t typ) -> ty::t {
|
|
|
|
fn simplifier(@crate_ctxt ccx, ty::t typ) -> ty::t {
|
|
|
|
alt (ty::struct(ccx.tcx, typ)) {
|
|
|
|
case (ty::ty_box(_)) {
|
|
|
|
ret ty::mk_imm_box(ccx.tcx, ty::mk_nil(ccx.tcx));
|
2011-04-15 10:18:23 -07:00
|
|
|
}
|
2011-05-12 18:37:28 -07:00
|
|
|
case (ty::ty_vec(_)) {
|
|
|
|
ret ty::mk_imm_vec(ccx.tcx, ty::mk_nil(ccx.tcx));
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_fn(_, _, _, _, _)) {
|
|
|
|
ret ty::mk_imm_tup(ccx.tcx,
|
|
|
|
[ty::mk_imm_box(ccx.tcx,
|
2011-06-02 17:40:12 -07:00
|
|
|
ty::mk_nil(ccx.tcx)),
|
2011-06-15 11:19:50 -07:00
|
|
|
ty::mk_imm_box(ccx.tcx,
|
2011-06-02 17:40:12 -07:00
|
|
|
ty::mk_nil(ccx.tcx))]);
|
|
|
|
}
|
|
|
|
case (ty::ty_obj(_)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret ty::mk_imm_tup(ccx.tcx,
|
|
|
|
[ty::mk_imm_box(ccx.tcx,
|
2011-06-02 17:40:12 -07:00
|
|
|
ty::mk_nil(ccx.tcx)),
|
2011-06-15 11:19:50 -07:00
|
|
|
ty::mk_imm_box(ccx.tcx,
|
2011-06-02 17:40:12 -07:00
|
|
|
ty::mk_nil(ccx.tcx))]);
|
|
|
|
}
|
2011-04-15 10:18:23 -07:00
|
|
|
case (_) { ret typ; }
|
|
|
|
}
|
|
|
|
}
|
2011-06-09 11:20:47 -07:00
|
|
|
ret ty::fold_ty(ccx.tcx, ty::fm_general(bind simplifier(ccx, _)), typ);
|
2011-04-15 10:18:23 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-04 15:08:33 -08:00
|
|
|
// Computes the size of the data part of a non-dynamically-sized tag.
|
2011-05-31 18:24:06 -07:00
|
|
|
fn static_size_of_tag(&@crate_ctxt cx, &span sp, &ty::t t) -> uint {
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_has_dynamic_size(cx.tcx, t)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.tcx.sess.span_err(sp,
|
|
|
|
"dynamically sized type passed to " +
|
|
|
|
"static_size_of_tag()");
|
2011-03-04 15:08:33 -08:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
if (cx.tag_sizes.contains_key(t)) { ret cx.tag_sizes.get(t); }
|
2011-03-06 13:56:38 -05:00
|
|
|
auto tid;
|
2011-05-12 17:24:54 +02:00
|
|
|
let vec[ty::t] subtys;
|
|
|
|
alt (ty::struct(cx.tcx, t)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_tag(?tid_, ?subtys_)) { tid = tid_; subtys = subtys_; }
|
2011-03-04 15:08:33 -08:00
|
|
|
case (_) {
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.tcx.sess.span_err(sp,
|
|
|
|
"non-tag passed to " +
|
|
|
|
"static_size_of_tag()");
|
2011-03-04 15:08:33 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Compute max(variant sizes).
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-04 15:08:33 -08:00
|
|
|
auto max_size = 0u;
|
2011-05-19 17:21:21 -07:00
|
|
|
auto variants = ty::tag_variants(cx.tcx, tid);
|
|
|
|
for (ty::variant_info variant in variants) {
|
2011-05-12 17:24:54 +02:00
|
|
|
auto tup_ty = simplify_type(cx, ty::mk_imm_tup(cx.tcx, variant.args));
|
2011-03-09 12:22:08 -08:00
|
|
|
// Perform any type parameter substitutions.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
tup_ty = ty::substitute_type_params(cx.tcx, subtys, tup_ty);
|
2011-03-04 15:08:33 -08:00
|
|
|
// Here we possibly do a recursive call.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto this_size = llsize_of_real(cx, type_of(cx, sp, tup_ty));
|
|
|
|
if (max_size < this_size) { max_size = this_size; }
|
2011-03-04 15:08:33 -08:00
|
|
|
}
|
|
|
|
cx.tag_sizes.insert(t, max_size);
|
|
|
|
ret max_size;
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn dynamic_size_of(&@block_ctxt cx, ty::t t) -> result {
|
|
|
|
fn align_elements(&@block_ctxt cx, &vec[ty::t] elts) -> result {
|
2011-03-01 16:01:33 -08:00
|
|
|
//
|
|
|
|
// C padding rules:
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// - Pad after each element so that next element is aligned.
|
|
|
|
// - Pad after final structure member so that whole structure
|
|
|
|
// is aligned to max alignment of interior.
|
|
|
|
//
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-01 16:01:33 -08:00
|
|
|
auto off = C_int(0);
|
|
|
|
auto max_align = C_int(1);
|
|
|
|
auto bcx = cx;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ty::t e in elts) {
|
2011-03-01 16:01:33 -08:00
|
|
|
auto elt_align = align_of(bcx, e);
|
|
|
|
bcx = elt_align.bcx;
|
|
|
|
auto elt_size = size_of(bcx, e);
|
|
|
|
bcx = elt_size.bcx;
|
|
|
|
auto aligned_off = align_to(bcx, off, elt_align.val);
|
2011-04-26 20:39:25 +00:00
|
|
|
off = bcx.build.Add(aligned_off, elt_size.val);
|
2011-03-01 16:01:33 -08:00
|
|
|
max_align = umax(bcx, max_align, elt_align.val);
|
|
|
|
}
|
|
|
|
off = align_to(bcx, off, max_align);
|
|
|
|
ret res(bcx, off);
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
|
|
|
|
case (ty::ty_param(?p)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto szptr =
|
|
|
|
field_of_tydesc(cx, t, false, abi::tydesc_field_size);
|
2011-01-31 15:03:05 -08:00
|
|
|
ret res(szptr.bcx, szptr.bcx.build.Load(szptr.val));
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_tup(?elts)) {
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ty::t] tys = [];
|
2011-06-15 11:19:50 -07:00
|
|
|
for (ty::mt mt in elts) { tys += [mt.ty]; }
|
2011-03-17 17:39:47 -07:00
|
|
|
ret align_elements(cx, tys);
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_rec(?flds)) {
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ty::t] tys = [];
|
2011-06-15 11:19:50 -07:00
|
|
|
for (ty::field f in flds) { tys += [f.mt.ty]; }
|
2011-03-01 16:01:33 -08:00
|
|
|
ret align_elements(cx, tys);
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_tag(?tid, ?tps)) {
|
2011-03-01 16:37:17 -08:00
|
|
|
auto bcx = cx;
|
|
|
|
// Compute max(variant sizes).
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-28 18:04:52 -07:00
|
|
|
let ValueRef max_size = alloca(bcx, T_int());
|
2011-03-01 16:37:17 -08:00
|
|
|
bcx.build.Store(C_int(0), max_size);
|
2011-05-19 17:21:21 -07:00
|
|
|
auto variants = ty::tag_variants(bcx.fcx.lcx.ccx.tcx, tid);
|
|
|
|
for (ty::variant_info variant in variants) {
|
2011-04-01 11:36:52 -07:00
|
|
|
// Perform type substitution on the raw argument types.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
let vec[ty::t] raw_tys = variant.args;
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ty::t] tys = [];
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ty::t raw_ty in raw_tys) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto t =
|
|
|
|
ty::substitute_type_params(cx.fcx.lcx.ccx.tcx, tps,
|
|
|
|
raw_ty);
|
2011-05-16 18:21:22 -07:00
|
|
|
tys += [t];
|
2011-03-09 16:07:55 -08:00
|
|
|
}
|
2011-03-01 16:37:17 -08:00
|
|
|
auto rslt = align_elements(bcx, tys);
|
|
|
|
bcx = rslt.bcx;
|
|
|
|
auto this_size = rslt.val;
|
|
|
|
auto old_max_size = bcx.build.Load(max_size);
|
|
|
|
bcx.build.Store(umax(bcx, this_size, old_max_size), max_size);
|
|
|
|
}
|
2011-03-01 16:49:05 -08:00
|
|
|
auto max_size_val = bcx.build.Load(max_size);
|
|
|
|
auto total_size = bcx.build.Add(max_size_val, llsize_of(T_int()));
|
|
|
|
ret res(bcx, total_size);
|
2011-03-01 16:37:17 -08:00
|
|
|
}
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn dynamic_align_of(&@block_ctxt cx, &ty::t t) -> result {
|
|
|
|
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
|
|
|
|
case (ty::ty_param(?p)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto aptr =
|
|
|
|
field_of_tydesc(cx, t, false, abi::tydesc_field_align);
|
2011-01-31 15:03:05 -08:00
|
|
|
ret res(aptr.bcx, aptr.bcx.build.Load(aptr.val));
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_tup(?elts)) {
|
2011-01-18 15:38:35 -08:00
|
|
|
auto a = C_int(1);
|
2011-01-31 15:03:05 -08:00
|
|
|
auto bcx = cx;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ty::mt e in elts) {
|
2011-03-17 17:39:47 -07:00
|
|
|
auto align = align_of(bcx, e.ty);
|
2011-01-31 15:03:05 -08:00
|
|
|
bcx = align.bcx;
|
|
|
|
a = umax(bcx, a, align.val);
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
2011-01-31 15:03:05 -08:00
|
|
|
ret res(bcx, a);
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_rec(?flds)) {
|
2011-01-18 15:38:35 -08:00
|
|
|
auto a = C_int(1);
|
2011-01-31 15:03:05 -08:00
|
|
|
auto bcx = cx;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ty::field f in flds) {
|
2011-03-17 17:39:47 -07:00
|
|
|
auto align = align_of(bcx, f.mt.ty);
|
2011-01-31 15:03:05 -08:00
|
|
|
bcx = align.bcx;
|
|
|
|
a = umax(bcx, a, align.val);
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
2011-01-31 15:03:05 -08:00
|
|
|
ret res(bcx, a);
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_tag(_, _)) {
|
2011-03-07 18:03:33 -08:00
|
|
|
ret res(cx, C_int(1)); // FIXME: stub
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-07 18:03:33 -08:00
|
|
|
}
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-01-19 16:29:14 -08:00
|
|
|
// Replacement for the LLVM 'GEP' instruction when field-indexing into a
|
2011-03-04 15:08:33 -08:00
|
|
|
// tuple-like structure (tup, rec) with a static index. This one is driven off
|
2011-05-12 17:24:54 +02:00
|
|
|
// ty::struct and knows what to do when it runs into a ty_param stuck in the
|
2011-03-04 15:08:33 -08:00
|
|
|
// middle of the thing it's GEP'ing into. Much like size_of and align_of,
|
|
|
|
// above.
|
2011-06-15 11:19:50 -07:00
|
|
|
fn GEP_tup_like(&@block_ctxt cx, &ty::t t, ValueRef base, &vec[int] ixs) ->
|
|
|
|
result {
|
2011-05-12 17:24:54 +02:00
|
|
|
assert (ty::type_is_tup_like(cx.fcx.lcx.ccx.tcx, t));
|
2011-01-19 16:29:14 -08:00
|
|
|
// It might be a static-known type. Handle this.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ValueRef] v = [];
|
2011-06-15 11:19:50 -07:00
|
|
|
for (int i in ixs) { v += [C_int(i)]; }
|
2011-01-31 15:03:05 -08:00
|
|
|
ret res(cx, cx.build.GEP(base, v));
|
2011-01-19 16:29:14 -08:00
|
|
|
}
|
|
|
|
// It is a dynamic-containing type that, if we convert directly to an LLVM
|
|
|
|
// TypeRef, will be all wrong; there's no proper LLVM type to represent
|
|
|
|
// it, and the lowering function will stick in i8* values for each
|
|
|
|
// ty_param, which is not right; the ty_params are all of some dynamic
|
|
|
|
// size.
|
|
|
|
//
|
|
|
|
// What we must do instead is sadder. We must look through the indices
|
|
|
|
// manually and split the input type into a prefix and a target. We then
|
|
|
|
// measure the prefix size, bump the input pointer by that amount, and
|
|
|
|
// cast to a pointer-to-target type.
|
|
|
|
|
|
|
|
// Given a type, an index vector and an element number N in that vector,
|
|
|
|
// calculate index X and the type that results by taking the first X-1
|
|
|
|
// elements of the type and splitting the Xth off. Return the prefix as
|
|
|
|
// well as the innermost Xth type.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn split_type(&@crate_ctxt ccx, &ty::t t, &vec[int] ixs, uint n) ->
|
|
|
|
rec(vec[ty::t] prefix, ty::t target) {
|
2011-05-17 20:41:41 +02:00
|
|
|
let uint len = vec::len[int](ixs);
|
2011-05-12 17:24:54 +02:00
|
|
|
// We don't support 0-index or 1-index GEPs: The former is nonsense
|
2011-01-19 16:29:14 -08:00
|
|
|
// and the latter would only be meaningful if we supported non-0
|
|
|
|
// values for the 0th index (we don't).
|
|
|
|
|
2011-05-02 17:47:24 -07:00
|
|
|
assert (len > 1u);
|
2011-01-19 16:29:14 -08:00
|
|
|
if (n == 0u) {
|
|
|
|
// Since we're starting from a value that's a pointer to a
|
|
|
|
// *single* structure, the first index (in GEP-ese) should just be
|
|
|
|
// 0, to yield the pointee.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-02 17:47:24 -07:00
|
|
|
assert (ixs.(n) == 0);
|
2011-06-15 11:19:50 -07:00
|
|
|
ret split_type(ccx, t, ixs, n + 1u);
|
2011-01-19 16:29:14 -08:00
|
|
|
}
|
2011-05-02 17:47:24 -07:00
|
|
|
assert (n < len);
|
2011-01-19 16:29:14 -08:00
|
|
|
let int ix = ixs.(n);
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ty::t] prefix = [];
|
2011-01-19 16:29:14 -08:00
|
|
|
let int i = 0;
|
|
|
|
while (i < ix) {
|
2011-05-17 20:41:41 +02:00
|
|
|
vec::push[ty::t](prefix,
|
2011-06-15 11:19:50 -07:00
|
|
|
ty::get_element_type(ccx.tcx, t, i as uint));
|
|
|
|
i += 1;
|
2011-01-19 16:29:14 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
auto selected = ty::get_element_type(ccx.tcx, t, i as uint);
|
2011-06-15 11:19:50 -07:00
|
|
|
if (n == len - 1u) {
|
2011-01-19 16:29:14 -08:00
|
|
|
// We are at the innermost index.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
ret rec(prefix=prefix, target=selected);
|
2011-01-19 16:29:14 -08:00
|
|
|
} else {
|
|
|
|
// Not the innermost index; call self recursively to dig deeper.
|
|
|
|
// Once we get an inner result, append it current prefix and
|
|
|
|
// return to caller.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
auto inner = split_type(ccx, selected, ixs, n + 1u);
|
2011-01-19 16:29:14 -08:00
|
|
|
prefix += inner.prefix;
|
|
|
|
ret rec(prefix=prefix with inner);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// We make a fake prefix tuple-type here; luckily for measuring sizes
|
|
|
|
// the tuple parens are associative so it doesn't matter that we've
|
|
|
|
// flattened the incoming structure.
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
auto s = split_type(cx.fcx.lcx.ccx, t, ixs, 0u);
|
2011-05-12 17:24:54 +02:00
|
|
|
auto prefix_ty = ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, s.prefix);
|
2011-01-31 15:03:05 -08:00
|
|
|
auto bcx = cx;
|
|
|
|
auto sz = size_of(bcx, prefix_ty);
|
|
|
|
bcx = sz.bcx;
|
|
|
|
auto raw = bcx.build.PointerCast(base, T_ptr(T_i8()));
|
2011-05-16 18:21:22 -07:00
|
|
|
auto bumped = bcx.build.GEP(raw, [sz.val]);
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, s.target)) {
|
2011-03-03 14:02:29 -08:00
|
|
|
ret res(bcx, bumped);
|
2011-01-19 16:29:14 -08:00
|
|
|
}
|
2011-05-18 15:35:16 -07:00
|
|
|
auto typ = T_ptr(type_of(bcx.fcx.lcx.ccx, bcx.sp, s.target));
|
2011-03-03 14:02:29 -08:00
|
|
|
ret res(bcx, bcx.build.PointerCast(bumped, typ));
|
2011-01-19 16:29:14 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-04 15:08:33 -08:00
|
|
|
// Replacement for the LLVM 'GEP' instruction when field indexing into a tag.
|
|
|
|
// This function uses GEP_tup_like() above and automatically performs casts as
|
|
|
|
// appropriate. @llblobptr is the data part of a tag value; its actual type is
|
|
|
|
// meaningless, as it will be cast away.
|
2011-06-15 11:19:50 -07:00
|
|
|
fn GEP_tag(@block_ctxt cx, ValueRef llblobptr, &ast::def_id tag_id,
|
|
|
|
&ast::def_id variant_id, &vec[ty::t] ty_substs, int ix) -> result {
|
|
|
|
auto variant =
|
|
|
|
ty::tag_variant_with_id(cx.fcx.lcx.ccx.tcx, tag_id, variant_id);
|
2011-03-04 15:08:33 -08:00
|
|
|
// Synthesize a tuple type so that GEP_tup_like() can work its magic.
|
|
|
|
// Separately, store the type of the element we're interested in.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-01 11:36:52 -07:00
|
|
|
auto arg_tys = variant.args;
|
2011-05-12 17:24:54 +02:00
|
|
|
auto elem_ty = ty::mk_nil(cx.fcx.lcx.ccx.tcx); // typestate infelicity
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-04 15:08:33 -08:00
|
|
|
auto i = 0;
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ty::t] true_arg_tys = [];
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ty::t aty in arg_tys) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto arg_ty =
|
|
|
|
ty::substitute_type_params(cx.fcx.lcx.ccx.tcx, ty_substs, aty);
|
2011-05-16 18:21:22 -07:00
|
|
|
true_arg_tys += [arg_ty];
|
2011-06-15 11:19:50 -07:00
|
|
|
if (i == ix) { elem_ty = arg_ty; }
|
2011-03-04 15:08:33 -08:00
|
|
|
i += 1;
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
auto tup_ty = ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, true_arg_tys);
|
2011-03-04 15:08:33 -08:00
|
|
|
// Cast the blob pointer to the appropriate type, if we need to (i.e. if
|
|
|
|
// the blob pointer isn't dynamically sized).
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-04 15:08:33 -08:00
|
|
|
let ValueRef llunionptr;
|
2011-05-12 17:24:54 +02:00
|
|
|
if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, tup_ty)) {
|
2011-05-18 15:35:16 -07:00
|
|
|
auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, tup_ty);
|
2011-03-04 15:08:33 -08:00
|
|
|
llunionptr = cx.build.TruncOrBitCast(llblobptr, T_ptr(llty));
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { llunionptr = llblobptr; }
|
2011-03-04 15:08:33 -08:00
|
|
|
// Do the GEP_tup_like().
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto rslt = GEP_tup_like(cx, tup_ty, llunionptr, [0, ix]);
|
2011-03-04 15:08:33 -08:00
|
|
|
// Cast the result to the appropriate type, if necessary.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-04 15:08:33 -08:00
|
|
|
auto val;
|
2011-05-12 17:24:54 +02:00
|
|
|
if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, elem_ty)) {
|
2011-05-18 15:35:16 -07:00
|
|
|
auto llelemty = type_of(rslt.bcx.fcx.lcx.ccx, cx.sp, elem_ty);
|
2011-03-04 15:08:33 -08:00
|
|
|
val = rslt.bcx.build.PointerCast(rslt.val, T_ptr(llelemty));
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { val = rslt.val; }
|
2011-03-04 15:08:33 -08:00
|
|
|
ret res(rslt.bcx, val);
|
|
|
|
}
|
|
|
|
|
2011-01-19 16:29:14 -08:00
|
|
|
|
2011-06-03 17:16:28 -07:00
|
|
|
// trans_raw_malloc: expects a type indicating which pointer type we want and
|
|
|
|
// a size indicating how much space we want malloc'd.
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_raw_malloc(&@block_ctxt cx, TypeRef llptr_ty, ValueRef llsize) ->
|
|
|
|
result {
|
2010-12-02 17:43:05 -08:00
|
|
|
// FIXME: need a table to collect tydesc globals.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-10 14:03:47 -07:00
|
|
|
auto tydesc = C_null(T_ptr(T_tydesc(cx.fcx.lcx.ccx.tn)));
|
2011-06-15 11:19:50 -07:00
|
|
|
auto rval =
|
|
|
|
cx.build.Call(cx.fcx.lcx.ccx.upcalls.malloc,
|
|
|
|
[cx.fcx.lltaskptr, llsize, tydesc]);
|
2011-05-10 14:03:47 -07:00
|
|
|
ret res(cx, cx.build.PointerCast(rval, llptr_ty));
|
2011-03-02 17:24:22 -08:00
|
|
|
}
|
|
|
|
|
2011-06-03 17:16:28 -07:00
|
|
|
|
|
|
|
// trans_malloc_boxed: expects an unboxed type and returns a pointer to enough
|
|
|
|
// space for something of that type, along with space for a reference count;
|
|
|
|
// in other words, it allocates a box for something of that type.
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_malloc_boxed(&@block_ctxt cx, ty::t t) -> result {
|
2011-03-07 14:05:16 -08:00
|
|
|
// Synthesize a fake box type structurally so we have something
|
|
|
|
// to measure the size of.
|
2011-06-03 17:16:28 -07:00
|
|
|
|
|
|
|
// We synthesize two types here because we want both the type of the
|
|
|
|
// pointer and the pointee. boxed_body is the type that we measure the
|
|
|
|
// size of; box_ptr is the type that's converted to a TypeRef and used as
|
|
|
|
// the pointer cast target in trans_raw_malloc.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
auto boxed_body =
|
|
|
|
ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx,
|
|
|
|
// The mk_int here is the space being
|
|
|
|
// reserved for the refcount.
|
|
|
|
[ty::mk_int(cx.fcx.lcx.ccx.tcx), t]);
|
2011-05-12 17:24:54 +02:00
|
|
|
auto box_ptr = ty::mk_imm_box(cx.fcx.lcx.ccx.tcx, t);
|
2011-03-07 14:05:16 -08:00
|
|
|
auto sz = size_of(cx, boxed_body);
|
2011-06-03 17:16:28 -07:00
|
|
|
// Grab the TypeRef type of box_ptr, because that's what trans_raw_malloc
|
|
|
|
// wants.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, box_ptr);
|
2011-03-07 14:05:16 -08:00
|
|
|
ret trans_raw_malloc(sz.bcx, llty, sz.val);
|
2010-12-02 17:43:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-20 10:23:37 -08:00
|
|
|
// Type descriptor and type glue stuff
|
|
|
|
|
|
|
|
// Given a type and a field index into its corresponding type descriptor,
|
|
|
|
// returns an LLVM ValueRef of that field from the tydesc, generating the
|
|
|
|
// tydesc if necessary.
|
2011-06-15 11:19:50 -07:00
|
|
|
fn field_of_tydesc(&@block_ctxt cx, &ty::t t, bool escapes, int field) ->
|
|
|
|
result {
|
2011-05-12 15:42:12 -07:00
|
|
|
auto ti = none[@tydesc_info];
|
|
|
|
auto tydesc = get_tydesc(cx, t, escapes, ti);
|
2011-01-31 15:03:05 -08:00
|
|
|
ret res(tydesc.bcx,
|
2011-05-16 18:21:22 -07:00
|
|
|
tydesc.bcx.build.GEP(tydesc.val, [C_int(0), C_int(field)]));
|
2010-12-20 10:23:37 -08:00
|
|
|
}
|
2010-12-10 15:02:23 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-01-27 17:07:52 -08:00
|
|
|
// Given a type containing ty params, build a vector containing a ValueRef for
|
2011-04-12 15:09:50 -07:00
|
|
|
// each of the ty params it uses (from the current frame) and a vector of the
|
|
|
|
// indices of the ty params present in the type. This is used solely for
|
2011-01-27 17:07:52 -08:00
|
|
|
// constructing derived tydescs.
|
2011-05-12 17:24:54 +02:00
|
|
|
fn linearize_ty_params(&@block_ctxt cx, &ty::t t) ->
|
2011-06-15 11:19:50 -07:00
|
|
|
tup(vec[uint], vec[ValueRef]) {
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ValueRef] param_vals = [];
|
|
|
|
let vec[uint] param_defs = [];
|
2011-06-15 11:19:50 -07:00
|
|
|
type rr =
|
|
|
|
rec(@block_ctxt cx,
|
|
|
|
mutable vec[ValueRef] vals,
|
|
|
|
mutable vec[uint] defs);
|
2011-01-27 17:07:52 -08:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn linearizer(@rr r, ty::t t) {
|
2011-06-15 11:19:50 -07:00
|
|
|
alt (ty::struct(r.cx.fcx.lcx.ccx.tcx, t)) {
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_param(?pid)) {
|
2011-04-15 12:23:00 -07:00
|
|
|
let bool seen = false;
|
2011-06-15 11:19:50 -07:00
|
|
|
for (uint d in r.defs) { if (d == pid) { seen = true; } }
|
2011-04-15 12:23:00 -07:00
|
|
|
if (!seen) {
|
2011-05-16 18:21:22 -07:00
|
|
|
r.vals += [r.cx.fcx.lltydescs.(pid)];
|
|
|
|
r.defs += [pid];
|
2011-04-15 12:23:00 -07:00
|
|
|
}
|
2011-01-27 17:07:52 -08:00
|
|
|
}
|
2011-04-15 12:23:00 -07:00
|
|
|
case (_) { }
|
2011-01-27 17:07:52 -08:00
|
|
|
}
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
auto x = @rec(cx=cx, mutable vals=param_vals, mutable defs=param_defs);
|
2011-04-15 12:23:00 -07:00
|
|
|
auto f = bind linearizer(x, _);
|
2011-05-12 17:24:54 +02:00
|
|
|
ty::walk_ty(cx.fcx.lcx.ccx.tcx, f, t);
|
2011-01-27 17:07:52 -08:00
|
|
|
ret tup(x.defs, x.vals);
|
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn trans_stack_local_derived_tydesc(&@block_ctxt cx, ValueRef llsz,
|
2011-06-15 11:19:50 -07:00
|
|
|
ValueRef llalign, ValueRef llroottydesc,
|
|
|
|
ValueRef llparamtydescs) -> ValueRef {
|
2011-05-06 11:35:04 -07:00
|
|
|
auto llmyroottydesc = alloca(cx, T_tydesc(cx.fcx.lcx.ccx.tn));
|
2011-05-02 15:28:22 -07:00
|
|
|
// By convention, desc 0 is the root descriptor.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-02 15:28:22 -07:00
|
|
|
llroottydesc = cx.build.Load(llroottydesc);
|
2011-05-06 11:35:04 -07:00
|
|
|
cx.build.Store(llroottydesc, llmyroottydesc);
|
2011-05-02 15:28:22 -07:00
|
|
|
// Store a pointer to the rest of the descriptors.
|
2011-05-08 16:24:24 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llfirstparam = cx.build.GEP(llparamtydescs, [C_int(0), C_int(0)]);
|
2011-05-02 15:28:22 -07:00
|
|
|
cx.build.Store(llfirstparam,
|
2011-05-16 18:21:22 -07:00
|
|
|
cx.build.GEP(llmyroottydesc, [C_int(0), C_int(0)]));
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.build.Store(llsz, cx.build.GEP(llmyroottydesc, [C_int(0), C_int(1)]));
|
2011-05-06 11:35:04 -07:00
|
|
|
cx.build.Store(llalign,
|
2011-05-16 18:21:22 -07:00
|
|
|
cx.build.GEP(llmyroottydesc, [C_int(0), C_int(2)]));
|
2011-05-11 11:56:49 -07:00
|
|
|
ret llmyroottydesc;
|
2011-05-02 15:28:22 -07:00
|
|
|
}
|
|
|
|
|
2011-05-12 15:42:12 -07:00
|
|
|
fn get_derived_tydesc(&@block_ctxt cx, &ty::t t, bool escapes,
|
|
|
|
&mutable option::t[@tydesc_info] static_ti) -> result {
|
2011-05-11 11:56:49 -07:00
|
|
|
alt (cx.fcx.derived_tydescs.find(t)) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(?info)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-11 11:56:49 -07:00
|
|
|
// If the tydesc escapes in this context, the cached derived
|
|
|
|
// tydesc also has to be one that was marked as escaping.
|
|
|
|
if (!(escapes && !info.escapes)) { ret res(cx, info.lltydesc); }
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (none) {/* fall through */ }
|
2011-05-11 11:56:49 -07:00
|
|
|
}
|
2011-05-12 15:42:12 -07:00
|
|
|
cx.fcx.lcx.ccx.stats.n_derived_tydescs += 1u;
|
2011-05-11 11:56:49 -07:00
|
|
|
auto bcx = new_raw_block_ctxt(cx.fcx, cx.fcx.llderivedtydescs);
|
2011-05-12 17:24:54 +02:00
|
|
|
let uint n_params = ty::count_ty_params(bcx.fcx.lcx.ccx.tcx, t);
|
2011-05-11 11:56:49 -07:00
|
|
|
auto tys = linearize_ty_params(bcx, t);
|
2011-05-17 20:41:41 +02:00
|
|
|
assert (n_params == vec::len[uint](tys._0));
|
|
|
|
assert (n_params == vec::len[ValueRef](tys._1));
|
2011-05-12 15:42:12 -07:00
|
|
|
auto root_ti = get_static_tydesc(bcx, t, tys._0);
|
|
|
|
static_ti = some[@tydesc_info](root_ti);
|
|
|
|
lazily_emit_all_tydesc_glue(cx, static_ti);
|
|
|
|
auto root = root_ti.tydesc;
|
2011-05-06 10:38:38 -07:00
|
|
|
auto sz = size_of(bcx, t);
|
|
|
|
bcx = sz.bcx;
|
|
|
|
auto align = align_of(bcx, t);
|
|
|
|
bcx = align.bcx;
|
|
|
|
auto v;
|
|
|
|
if (escapes) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto tydescs =
|
|
|
|
alloca(bcx, /* for root*/
|
|
|
|
T_array(T_ptr(T_tydesc(bcx.fcx.lcx.ccx.tn)),
|
|
|
|
1u + n_params));
|
2011-05-06 11:35:04 -07:00
|
|
|
auto i = 0;
|
2011-05-16 18:21:22 -07:00
|
|
|
auto tdp = bcx.build.GEP(tydescs, [C_int(0), C_int(i)]);
|
2011-05-11 11:56:49 -07:00
|
|
|
bcx.build.Store(root, tdp);
|
2011-05-06 11:35:04 -07:00
|
|
|
i += 1;
|
|
|
|
for (ValueRef td in tys._1) {
|
2011-05-16 18:21:22 -07:00
|
|
|
auto tdp = bcx.build.GEP(tydescs, [C_int(0), C_int(i)]);
|
2011-05-11 11:56:49 -07:00
|
|
|
bcx.build.Store(td, tdp);
|
2011-05-06 11:35:04 -07:00
|
|
|
i += 1;
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
auto lltydescsptr =
|
|
|
|
bcx.build.PointerCast(tydescs,
|
|
|
|
T_ptr(T_ptr(T_tydesc(bcx.fcx.lcx.ccx.tn))));
|
|
|
|
auto td_val =
|
|
|
|
bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.get_type_desc,
|
|
|
|
[bcx.fcx.lltaskptr, C_null(T_ptr(T_nil())), sz.val,
|
|
|
|
align.val, C_int(1u + n_params as int),
|
|
|
|
lltydescsptr]);
|
2011-05-11 11:56:49 -07:00
|
|
|
v = td_val;
|
2011-05-06 10:38:38 -07:00
|
|
|
} else {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llparamtydescs =
|
|
|
|
alloca(bcx,
|
|
|
|
T_array(T_ptr(T_tydesc(bcx.fcx.lcx.ccx.tn)), n_params));
|
2011-05-13 16:09:17 -04:00
|
|
|
auto i = 0;
|
|
|
|
for (ValueRef td in tys._1) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto tdp = bcx.build.GEP(llparamtydescs, [C_int(0), C_int(i)]);
|
2011-05-13 16:09:17 -04:00
|
|
|
bcx.build.Store(td, tdp);
|
|
|
|
i += 1;
|
2011-05-06 11:35:04 -07:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
v =
|
|
|
|
trans_stack_local_derived_tydesc(bcx, sz.val, align.val, root,
|
2011-05-13 16:09:17 -04:00
|
|
|
llparamtydescs);
|
2011-05-06 10:38:38 -07:00
|
|
|
}
|
2011-05-11 11:56:49 -07:00
|
|
|
bcx.fcx.derived_tydescs.insert(t, rec(lltydesc=v, escapes=escapes));
|
|
|
|
ret res(cx, v);
|
2011-05-06 10:38:38 -07:00
|
|
|
}
|
|
|
|
|
2011-05-12 15:42:12 -07:00
|
|
|
fn get_tydesc(&@block_ctxt cx, &ty::t t, bool escapes,
|
|
|
|
&mutable option::t[@tydesc_info] static_ti) -> result {
|
2010-12-20 15:23:24 -08:00
|
|
|
// Is the supplied type a type param? If so, return the passed-in tydesc.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::type_param(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(?id)) { ret res(cx, cx.fcx.lltydescs.(id)); }
|
2011-06-15 11:19:50 -07:00
|
|
|
case (none) {/* fall through */ }
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
2010-12-20 15:23:24 -08:00
|
|
|
// Does it contain a type param? If so, generate a derived tydesc.
|
2011-01-28 15:28:20 -08:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_contains_params(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-05-12 15:42:12 -07:00
|
|
|
ret get_derived_tydesc(cx, t, escapes, static_ti);
|
2010-12-20 15:23:24 -08:00
|
|
|
}
|
|
|
|
// Otherwise, generate a tydesc if necessary, and return it.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[uint] tps = [];
|
2011-05-12 15:42:12 -07:00
|
|
|
auto info = get_static_tydesc(cx, t, tps);
|
|
|
|
static_ti = some[@tydesc_info](info);
|
|
|
|
ret res(cx, info.tydesc);
|
2011-04-26 17:19:44 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn get_static_tydesc(&@block_ctxt cx, &ty::t t, &vec[uint] ty_params) ->
|
|
|
|
@tydesc_info {
|
2011-04-26 17:19:44 -07:00
|
|
|
alt (cx.fcx.lcx.ccx.tydescs.find(t)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (some(?info)) { ret info; }
|
2011-05-31 00:39:19 -04:00
|
|
|
case (none) {
|
2011-05-12 15:42:12 -07:00
|
|
|
cx.fcx.lcx.ccx.stats.n_static_tydescs += 1u;
|
2011-05-18 15:35:16 -07:00
|
|
|
auto info = declare_tydesc(cx.fcx.lcx, cx.sp, t, ty_params);
|
2011-04-27 16:03:45 +00:00
|
|
|
cx.fcx.lcx.ccx.tydescs.insert(t, info);
|
2011-04-26 17:19:44 -07:00
|
|
|
ret info;
|
|
|
|
}
|
2010-12-20 15:23:24 -08:00
|
|
|
}
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
|
|
|
|
2011-05-20 14:57:52 -07:00
|
|
|
fn set_no_inline(ValueRef f) {
|
2011-06-15 11:19:50 -07:00
|
|
|
llvm::LLVMAddFunctionAttr(f,
|
|
|
|
lib::llvm::LLVMNoInlineAttribute as
|
|
|
|
lib::llvm::llvm::Attribute);
|
2011-05-20 14:57:52 -07:00
|
|
|
}
|
|
|
|
|
2011-05-24 13:47:27 -04:00
|
|
|
fn set_uwtable(ValueRef f) {
|
2011-06-15 11:19:50 -07:00
|
|
|
llvm::LLVMAddFunctionAttr(f,
|
|
|
|
lib::llvm::LLVMUWTableAttribute as
|
|
|
|
lib::llvm::llvm::Attribute);
|
2011-05-24 13:47:27 -04:00
|
|
|
}
|
|
|
|
|
2011-05-20 14:57:52 -07:00
|
|
|
fn set_always_inline(ValueRef f) {
|
2011-06-15 11:19:50 -07:00
|
|
|
llvm::LLVMAddFunctionAttr(f,
|
|
|
|
lib::llvm::LLVMAlwaysInlineAttribute as
|
|
|
|
lib::llvm::llvm::Attribute);
|
2011-05-20 14:57:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn set_glue_inlining(&@local_ctxt cx, ValueRef f, &ty::t t) {
|
|
|
|
if (ty::type_is_structural(cx.ccx.tcx, t)) {
|
|
|
|
set_no_inline(f);
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { set_always_inline(f); }
|
2011-05-20 14:57:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-05-12 15:42:12 -07:00
|
|
|
// Generates the declaration for (but doesn't emit) a type descriptor.
|
2011-06-15 11:19:50 -07:00
|
|
|
fn declare_tydesc(&@local_ctxt cx, &span sp, &ty::t t, vec[uint] ty_params) ->
|
|
|
|
@tydesc_info {
|
2011-06-09 09:48:16 -07:00
|
|
|
log "+++ declare_tydesc " + ty_to_str(cx.ccx.tcx, t);
|
2011-04-17 14:24:45 +02:00
|
|
|
auto ccx = cx.ccx;
|
2011-03-02 16:23:14 -08:00
|
|
|
auto llsize;
|
|
|
|
auto llalign;
|
2011-05-12 17:24:54 +02:00
|
|
|
if (!ty::type_has_dynamic_size(ccx.tcx, t)) {
|
2011-05-18 15:35:16 -07:00
|
|
|
auto llty = type_of(ccx, sp, t);
|
2011-03-02 16:23:14 -08:00
|
|
|
llsize = llsize_of(llty);
|
|
|
|
llalign = llalign_of(llty);
|
|
|
|
} else {
|
|
|
|
// These will be overwritten as the derived tydesc is generated, so
|
|
|
|
// we create placeholder values.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-02 16:23:14 -08:00
|
|
|
llsize = C_int(0);
|
|
|
|
llalign = C_int(0);
|
|
|
|
}
|
2011-05-10 17:58:11 -07:00
|
|
|
auto name;
|
|
|
|
if (cx.ccx.sess.get_opts().debuginfo) {
|
2011-06-07 17:54:22 -07:00
|
|
|
name = mangle_internal_name_by_type_only(cx.ccx, t, "tydesc");
|
2011-05-10 17:58:11 -07:00
|
|
|
name = sanitize(name);
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { name = mangle_internal_name_by_seq(cx.ccx, "tydesc"); }
|
|
|
|
auto gvar =
|
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, T_tydesc(ccx.tn), str::buf(name));
|
|
|
|
auto info =
|
|
|
|
@rec(ty=t,
|
|
|
|
tydesc=gvar,
|
|
|
|
size=llsize,
|
|
|
|
align=llalign,
|
|
|
|
mutable take_glue=none[ValueRef],
|
|
|
|
mutable drop_glue=none[ValueRef],
|
|
|
|
mutable free_glue=none[ValueRef],
|
|
|
|
mutable cmp_glue=none[ValueRef],
|
|
|
|
ty_params=ty_params);
|
2011-06-09 09:48:16 -07:00
|
|
|
log "--- declare_tydesc " + ty_to_str(cx.ccx.tcx, t);
|
2011-04-26 17:19:44 -07:00
|
|
|
ret info;
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
|
|
|
|
2011-04-18 10:56:52 -07:00
|
|
|
tag make_generic_glue_helper_fn {
|
2011-06-15 11:19:50 -07:00
|
|
|
mgghf_single(fn(&@block_ctxt, ValueRef, &ty::t) );
|
2011-04-18 12:44:50 -07:00
|
|
|
mgghf_cmp;
|
2011-04-18 10:56:52 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn declare_generic_glue(&@local_ctxt cx, &ty::t t, TypeRef llfnty, &str name)
|
|
|
|
-> ValueRef {
|
2011-05-04 15:36:42 -07:00
|
|
|
auto fn_nm;
|
2011-05-04 16:53:42 -07:00
|
|
|
if (cx.ccx.sess.get_opts().debuginfo) {
|
2011-06-15 11:19:50 -07:00
|
|
|
fn_nm = mangle_internal_name_by_type_only(cx.ccx, t, "glue_" + name);
|
2011-05-04 15:36:42 -07:00
|
|
|
fn_nm = sanitize(fn_nm);
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { fn_nm = mangle_internal_name_by_seq(cx.ccx, "glue_" + name); }
|
2011-06-14 15:54:58 -07:00
|
|
|
auto llfn = decl_cdecl_fn(cx.ccx.llmod, fn_nm, llfnty);
|
2011-05-20 14:57:52 -07:00
|
|
|
set_glue_inlining(cx, llfn, t);
|
2011-03-20 15:05:13 -07:00
|
|
|
ret llfn;
|
2011-03-04 17:22:43 -08:00
|
|
|
}
|
2010-12-10 15:02:23 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn make_generic_glue(&@local_ctxt cx, &span sp, &ty::t t, ValueRef llfn,
|
2011-05-11 04:58:46 +00:00
|
|
|
&make_generic_glue_helper_fn helper,
|
|
|
|
&vec[uint] ty_params) -> ValueRef {
|
2011-05-18 15:35:16 -07:00
|
|
|
auto fcx = new_fn_ctxt(cx, sp, llfn);
|
2011-06-15 11:19:50 -07:00
|
|
|
llvm::LLVMSetLinkage(llfn,
|
|
|
|
lib::llvm::LLVMInternalLinkage as llvm::Linkage);
|
2011-05-12 15:42:12 -07:00
|
|
|
cx.ccx.stats.n_glues_created += 1u;
|
2011-04-19 11:25:40 -07:00
|
|
|
// Any nontrivial glue is with values passed *by alias*; this is a
|
|
|
|
// requirement since in many contexts glue is invoked indirectly and
|
|
|
|
// the caller has no idea if it's dealing with something that can be
|
|
|
|
// passed by value.
|
2011-04-12 12:06:20 -07:00
|
|
|
|
2011-04-19 11:25:40 -07:00
|
|
|
auto llty;
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_has_dynamic_size(cx.ccx.tcx, t)) {
|
2011-04-19 11:25:40 -07:00
|
|
|
llty = T_ptr(T_i8());
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { llty = T_ptr(type_of(cx.ccx, sp, t)); }
|
2011-05-17 20:41:41 +02:00
|
|
|
auto ty_param_count = vec::len[uint](ty_params);
|
2011-05-12 17:24:54 +02:00
|
|
|
auto lltyparams = llvm::LLVMGetParam(llfn, 3u);
|
2011-05-11 11:56:49 -07:00
|
|
|
auto copy_args_bcx = new_raw_block_ctxt(fcx, fcx.llcopyargs);
|
2011-05-17 20:41:41 +02:00
|
|
|
auto lltydescs = vec::empty_mut[ValueRef]();
|
2011-04-19 11:25:40 -07:00
|
|
|
auto p = 0u;
|
|
|
|
while (p < ty_param_count) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llparam = copy_args_bcx.build.GEP(lltyparams, [C_int(p as int)]);
|
2011-05-11 11:56:49 -07:00
|
|
|
llparam = copy_args_bcx.build.Load(llparam);
|
2011-05-17 20:41:41 +02:00
|
|
|
vec::grow_set[ValueRef](lltydescs, ty_params.(p), 0 as ValueRef,
|
2011-04-19 11:25:40 -07:00
|
|
|
llparam);
|
|
|
|
p += 1u;
|
|
|
|
}
|
2011-05-17 20:41:41 +02:00
|
|
|
fcx.lltydescs = vec::freeze[ValueRef](lltydescs);
|
2011-05-11 11:56:49 -07:00
|
|
|
auto bcx = new_top_block_ctxt(fcx);
|
|
|
|
auto lltop = bcx.llbb;
|
2011-05-12 17:24:54 +02:00
|
|
|
auto llrawptr0 = llvm::LLVMGetParam(llfn, 4u);
|
2011-04-19 11:25:40 -07:00
|
|
|
auto llval0 = bcx.build.BitCast(llrawptr0, llty);
|
|
|
|
alt (helper) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (mgghf_single(?single_fn)) { single_fn(bcx, llval0, t); }
|
2011-04-19 11:25:40 -07:00
|
|
|
case (mgghf_cmp) {
|
2011-05-12 17:24:54 +02:00
|
|
|
auto llrawptr1 = llvm::LLVMGetParam(llfn, 5u);
|
2011-04-19 15:22:57 -07:00
|
|
|
auto llval1 = bcx.build.BitCast(llrawptr1, llty);
|
2011-05-12 17:24:54 +02:00
|
|
|
auto llcmpval = llvm::LLVMGetParam(llfn, 6u);
|
2011-04-19 11:25:40 -07:00
|
|
|
make_cmp_glue(bcx, llval0, llval1, t, llcmpval);
|
2011-04-18 10:56:52 -07:00
|
|
|
}
|
2010-12-17 18:20:10 -08:00
|
|
|
}
|
2011-05-11 11:56:49 -07:00
|
|
|
finish_fn(fcx, lltop);
|
2010-12-10 15:02:23 -08:00
|
|
|
ret llfn;
|
|
|
|
}
|
|
|
|
|
2011-05-12 15:42:12 -07:00
|
|
|
fn emit_tydescs(&@crate_ctxt ccx) {
|
|
|
|
for each (@tup(ty::t, @tydesc_info) pair in ccx.tydescs.items()) {
|
|
|
|
auto glue_fn_ty = T_ptr(T_glue_fn(ccx.tn));
|
|
|
|
auto cmp_fn_ty = T_ptr(T_cmp_glue_fn(ccx.tn));
|
|
|
|
auto ti = pair._1;
|
2011-06-15 11:19:50 -07:00
|
|
|
auto take_glue =
|
|
|
|
alt ({ ti.take_glue }) {
|
|
|
|
case (none) {
|
|
|
|
ccx.stats.n_null_glues += 1u;
|
|
|
|
C_null(glue_fn_ty)
|
|
|
|
}
|
|
|
|
case (some(?v)) { ccx.stats.n_real_glues += 1u; v }
|
|
|
|
};
|
|
|
|
auto drop_glue =
|
|
|
|
alt ({ ti.drop_glue }) {
|
|
|
|
case (none) {
|
|
|
|
ccx.stats.n_null_glues += 1u;
|
|
|
|
C_null(glue_fn_ty)
|
|
|
|
}
|
|
|
|
case (some(?v)) { ccx.stats.n_real_glues += 1u; v }
|
|
|
|
};
|
|
|
|
auto free_glue =
|
|
|
|
alt ({ ti.free_glue }) {
|
|
|
|
case (none) {
|
|
|
|
ccx.stats.n_null_glues += 1u;
|
|
|
|
C_null(glue_fn_ty)
|
|
|
|
}
|
|
|
|
case (some(?v)) { ccx.stats.n_real_glues += 1u; v }
|
|
|
|
};
|
|
|
|
auto cmp_glue =
|
|
|
|
alt ({ ti.cmp_glue }) {
|
|
|
|
case (none) {
|
|
|
|
ccx.stats.n_null_glues += 1u;
|
|
|
|
C_null(cmp_fn_ty)
|
|
|
|
}
|
|
|
|
case (some(?v)) { ccx.stats.n_real_glues += 1u; v }
|
|
|
|
};
|
|
|
|
auto tydesc =
|
|
|
|
C_struct([C_null(T_ptr(T_ptr(T_tydesc(ccx.tn)))), ti.size,
|
|
|
|
ti.align, take_glue, // take_glue
|
|
|
|
drop_glue, // drop_glue
|
|
|
|
free_glue, // free_glue
|
|
|
|
C_null(glue_fn_ty), // sever_glue
|
|
|
|
C_null(glue_fn_ty), // mark_glue
|
|
|
|
C_null(glue_fn_ty), // obj_drop_glue
|
|
|
|
C_null(glue_fn_ty), // is_stateful
|
|
|
|
cmp_glue]); // cmp_glue
|
2011-05-12 15:42:12 -07:00
|
|
|
|
|
|
|
auto gvar = ti.tydesc;
|
|
|
|
llvm::LLVMSetInitializer(gvar, tydesc);
|
|
|
|
llvm::LLVMSetGlobalConstant(gvar, True);
|
2011-06-15 11:19:50 -07:00
|
|
|
llvm::LLVMSetLinkage(gvar,
|
|
|
|
lib::llvm::LLVMInternalLinkage as llvm::Linkage);
|
2011-05-12 15:42:12 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn make_take_glue(&@block_ctxt cx, ValueRef v, &ty::t t) {
|
2011-04-12 12:06:20 -07:00
|
|
|
// NB: v is an *alias* of type t here, not a direct value.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-19 11:17:01 -07:00
|
|
|
auto bcx;
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_is_boxed(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-04-19 11:17:01 -07:00
|
|
|
bcx = incr_refcnt_of_boxed(cx, cx.build.Load(v)).bcx;
|
2011-05-12 17:24:54 +02:00
|
|
|
} else if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
bcx = iter_structural_ty(cx, v, t, bind take_ty(_, _, _)).bcx;
|
|
|
|
} else { bcx = cx; }
|
2011-04-19 11:17:01 -07:00
|
|
|
bcx.build.RetVoid();
|
2010-12-10 16:13:52 -08:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn incr_refcnt_of_boxed(&@block_ctxt cx, ValueRef box_ptr) -> result {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto rc_ptr =
|
|
|
|
cx.build.GEP(box_ptr, [C_int(0), C_int(abi::box_rc_field_refcnt)]);
|
2010-12-10 16:13:52 -08:00
|
|
|
auto rc = cx.build.Load(rc_ptr);
|
|
|
|
auto rc_adj_cx = new_sub_block_ctxt(cx, "rc++");
|
|
|
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
2011-06-15 11:19:50 -07:00
|
|
|
auto const_test =
|
|
|
|
cx.build.ICmp(lib::llvm::LLVMIntEQ, C_int(abi::const_refcount as int),
|
|
|
|
rc);
|
2010-12-10 16:13:52 -08:00
|
|
|
cx.build.CondBr(const_test, next_cx.llbb, rc_adj_cx.llbb);
|
|
|
|
rc = rc_adj_cx.build.Add(rc, C_int(1));
|
|
|
|
rc_adj_cx.build.Store(rc, rc_ptr);
|
|
|
|
rc_adj_cx.build.Br(next_cx.llbb);
|
|
|
|
ret res(next_cx, C_nil());
|
|
|
|
}
|
|
|
|
|
2011-05-18 17:28:08 -07:00
|
|
|
fn make_free_glue(&@block_ctxt cx, ValueRef v0, &ty::t t) {
|
|
|
|
// NB: v is an *alias* of type t here, not a direct value.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-19 11:17:01 -07:00
|
|
|
auto rslt;
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
|
|
|
|
case (ty::ty_str) {
|
2011-04-12 12:06:20 -07:00
|
|
|
auto v = cx.build.Load(v0);
|
2011-05-18 17:28:08 -07:00
|
|
|
rslt = trans_non_gc_free(cx, v);
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_vec(_)) {
|
2011-04-12 12:06:20 -07:00
|
|
|
auto v = cx.build.Load(v0);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto res = iter_sequence(cx, v, t, bind drop_ty(_, _, _));
|
2011-05-18 17:28:08 -07:00
|
|
|
// FIXME: switch gc/non-gc on layer of the type.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-18 17:28:08 -07:00
|
|
|
rslt = trans_non_gc_free(res.bcx, v);
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_box(?body_mt)) {
|
2011-04-12 12:06:20 -07:00
|
|
|
auto v = cx.build.Load(v0);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto body =
|
|
|
|
cx.build.GEP(v, [C_int(0), C_int(abi::box_rc_field_body)]);
|
2011-05-18 17:28:08 -07:00
|
|
|
auto body_ty = body_mt.ty;
|
|
|
|
auto body_val = load_if_immediate(cx, body, body_ty);
|
|
|
|
auto res = drop_ty(cx, body_val, body_ty);
|
|
|
|
// FIXME: switch gc/non-gc on layer of the type.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-18 17:28:08 -07:00
|
|
|
rslt = trans_non_gc_free(res.bcx, v);
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_port(_)) {
|
2011-04-12 12:06:20 -07:00
|
|
|
auto v = cx.build.Load(v0);
|
2011-05-18 17:28:08 -07:00
|
|
|
cx.build.Call(cx.fcx.lcx.ccx.upcalls.del_port,
|
|
|
|
[cx.fcx.lltaskptr,
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.build.PointerCast(v, T_opaque_port_ptr())]);
|
2011-05-18 17:28:08 -07:00
|
|
|
rslt = res(cx, C_int(0));
|
2011-03-16 21:49:15 -04:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_chan(_)) {
|
2011-04-12 12:06:20 -07:00
|
|
|
auto v = cx.build.Load(v0);
|
2011-05-18 17:28:08 -07:00
|
|
|
cx.build.Call(cx.fcx.lcx.ccx.upcalls.del_chan,
|
|
|
|
[cx.fcx.lltaskptr,
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.build.PointerCast(v, T_opaque_chan_ptr())]);
|
2011-05-18 17:28:08 -07:00
|
|
|
rslt = res(cx, C_int(0));
|
2011-03-16 21:49:15 -04:00
|
|
|
}
|
2011-05-24 12:18:42 -07:00
|
|
|
case (ty::ty_task) {
|
|
|
|
// TODO: call upcall_kill
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-24 12:18:42 -07:00
|
|
|
rslt = res(cx, C_nil());
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_obj(_)) {
|
2010-12-31 13:01:45 -08:00
|
|
|
auto box_cell =
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.build.GEP(v0, [C_int(0), C_int(abi::obj_field_box)]);
|
2011-05-18 17:28:08 -07:00
|
|
|
auto b = cx.build.Load(box_cell);
|
|
|
|
auto body =
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.build.GEP(b, [C_int(0), C_int(abi::box_rc_field_body)]);
|
2011-05-18 17:28:08 -07:00
|
|
|
auto tydescptr =
|
|
|
|
cx.build.GEP(body,
|
2011-06-15 11:19:50 -07:00
|
|
|
[C_int(0), C_int(abi::obj_body_elt_tydesc)]);
|
2011-05-18 17:28:08 -07:00
|
|
|
auto tydesc = cx.build.Load(tydescptr);
|
|
|
|
auto cx_ = maybe_call_dtor(cx, v0);
|
|
|
|
// Call through the obj's own fields-drop glue first.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-18 17:28:08 -07:00
|
|
|
auto ti = none[@tydesc_info];
|
|
|
|
call_tydesc_glue_full(cx_, body, tydesc,
|
|
|
|
abi::tydesc_field_drop_glue, ti);
|
|
|
|
// Then free the body.
|
|
|
|
// FIXME: switch gc/non-gc on layer of the type.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-18 17:28:08 -07:00
|
|
|
rslt = trans_non_gc_free(cx_, b);
|
2010-12-31 13:01:45 -08:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_fn(_, _, _, _, _)) {
|
2011-01-07 16:26:30 -08:00
|
|
|
auto box_cell =
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.build.GEP(v0, [C_int(0), C_int(abi::fn_field_box)]);
|
2011-05-18 17:28:08 -07:00
|
|
|
auto v = cx.build.Load(box_cell);
|
|
|
|
// Call through the closure's own fields-drop glue first.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-18 17:28:08 -07:00
|
|
|
auto body =
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.build.GEP(v, [C_int(0), C_int(abi::box_rc_field_body)]);
|
2011-05-18 17:28:08 -07:00
|
|
|
auto bindings =
|
|
|
|
cx.build.GEP(body,
|
2011-06-15 11:19:50 -07:00
|
|
|
[C_int(0), C_int(abi::closure_elt_bindings)]);
|
2011-05-18 17:28:08 -07:00
|
|
|
auto tydescptr =
|
|
|
|
cx.build.GEP(body,
|
2011-06-15 11:19:50 -07:00
|
|
|
[C_int(0), C_int(abi::closure_elt_tydesc)]);
|
2011-05-18 17:28:08 -07:00
|
|
|
auto ti = none[@tydesc_info];
|
|
|
|
call_tydesc_glue_full(cx, bindings, cx.build.Load(tydescptr),
|
|
|
|
abi::tydesc_field_drop_glue, ti);
|
|
|
|
// Then free the body.
|
|
|
|
// FIXME: switch gc/non-gc on layer of the type.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-18 17:28:08 -07:00
|
|
|
rslt = trans_non_gc_free(cx, v);
|
|
|
|
}
|
|
|
|
case (_) { rslt = res(cx, C_nil()); }
|
|
|
|
}
|
|
|
|
rslt.bcx.build.RetVoid();
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn maybe_free_ivec_heap_part(&@block_ctxt cx, ValueRef v0, ty::t unit_ty) ->
|
|
|
|
result {
|
2011-06-14 14:37:47 -07:00
|
|
|
auto llunitty = type_of_or_i8(cx, unit_ty);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto stack_len =
|
|
|
|
cx.build.Load(cx.build.InBoundsGEP(v0,
|
|
|
|
[C_int(0),
|
|
|
|
C_uint(abi::ivec_elt_len)]));
|
2011-06-14 14:37:47 -07:00
|
|
|
auto maybe_on_heap_cx = new_sub_block_ctxt(cx, "maybe_on_heap");
|
|
|
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
2011-06-15 11:19:50 -07:00
|
|
|
auto maybe_on_heap =
|
|
|
|
cx.build.ICmp(lib::llvm::LLVMIntEQ, stack_len, C_int(0));
|
2011-06-14 14:37:47 -07:00
|
|
|
cx.build.CondBr(maybe_on_heap, maybe_on_heap_cx.llbb, next_cx.llbb);
|
|
|
|
// Might be on the heap. Load the heap pointer and free it. (It's ok to
|
|
|
|
// free a null pointer.)
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
auto stub_ptr =
|
|
|
|
maybe_on_heap_cx.build.PointerCast(v0, T_ptr(T_ivec_heap(llunitty)));
|
|
|
|
auto heap_ptr =
|
|
|
|
{
|
|
|
|
auto v = [C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)];
|
|
|
|
auto m = maybe_on_heap_cx.build.InBoundsGEP(stub_ptr, v);
|
|
|
|
maybe_on_heap_cx.build.Load(m)
|
|
|
|
};
|
2011-06-14 14:37:47 -07:00
|
|
|
auto after_free_cx = trans_non_gc_free(maybe_on_heap_cx, heap_ptr).bcx;
|
|
|
|
after_free_cx.build.Br(next_cx.llbb);
|
|
|
|
ret res(next_cx, C_nil());
|
|
|
|
}
|
|
|
|
|
2011-05-18 17:28:08 -07:00
|
|
|
fn make_drop_glue(&@block_ctxt cx, ValueRef v0, &ty::t t) {
|
|
|
|
// NB: v0 is an *alias* of type t here, not a direct value.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-18 17:28:08 -07:00
|
|
|
auto rslt;
|
|
|
|
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_str) { rslt = decr_refcnt_maybe_free(cx, v0, v0, t); }
|
|
|
|
case (ty::ty_vec(_)) { rslt = decr_refcnt_maybe_free(cx, v0, v0, t); }
|
2011-06-14 14:37:47 -07:00
|
|
|
case (ty::ty_ivec(?tm)) {
|
|
|
|
rslt = iter_structural_ty(cx, v0, t, drop_ty);
|
|
|
|
rslt = maybe_free_ivec_heap_part(rslt.bcx, v0, tm.ty);
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_box(_)) { rslt = decr_refcnt_maybe_free(cx, v0, v0, t); }
|
2011-05-18 17:28:08 -07:00
|
|
|
case (ty::ty_port(_)) {
|
|
|
|
rslt = decr_refcnt_maybe_free(cx, v0, v0, t);
|
|
|
|
}
|
|
|
|
case (ty::ty_chan(_)) {
|
|
|
|
rslt = decr_refcnt_maybe_free(cx, v0, v0, t);
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_task) { rslt = decr_refcnt_maybe_free(cx, v0, v0, t); }
|
2011-05-18 17:28:08 -07:00
|
|
|
case (ty::ty_obj(_)) {
|
|
|
|
auto box_cell =
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.build.GEP(v0, [C_int(0), C_int(abi::obj_field_box)]);
|
2011-05-18 17:28:08 -07:00
|
|
|
rslt = decr_refcnt_maybe_free(cx, box_cell, v0, t);
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_fn(_, _, _, _, _)) {
|
2011-05-18 17:28:08 -07:00
|
|
|
auto box_cell =
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.build.GEP(v0, [C_int(0), C_int(abi::fn_field_box)]);
|
2011-05-18 17:28:08 -07:00
|
|
|
rslt = decr_refcnt_maybe_free(cx, box_cell, v0, t);
|
2011-01-07 16:26:30 -08:00
|
|
|
}
|
2010-12-10 15:02:23 -08:00
|
|
|
case (_) {
|
2011-05-19 18:28:09 -07:00
|
|
|
if (ty::type_has_pointers(cx.fcx.lcx.ccx.tcx, t) &&
|
2011-06-15 11:19:50 -07:00
|
|
|
ty::type_is_structural(cx.fcx.lcx.ccx.tcx, t)) {
|
|
|
|
rslt = iter_structural_ty(cx, v0, t, bind drop_ty(_, _, _));
|
|
|
|
} else { rslt = res(cx, C_nil()); }
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
|
|
|
}
|
2011-04-19 11:17:01 -07:00
|
|
|
rslt.bcx.build.RetVoid();
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn decr_refcnt_maybe_free(&@block_ctxt cx, ValueRef box_ptr_alias,
|
|
|
|
ValueRef full_alias, &ty::t t) -> result {
|
2010-12-06 17:46:35 -08:00
|
|
|
auto load_rc_cx = new_sub_block_ctxt(cx, "load rc");
|
2010-11-10 17:46:49 -08:00
|
|
|
auto rc_adj_cx = new_sub_block_ctxt(cx, "rc--");
|
2011-05-18 17:28:08 -07:00
|
|
|
auto free_cx = new_sub_block_ctxt(cx, "free");
|
2010-11-10 17:46:49 -08:00
|
|
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
2011-05-18 17:28:08 -07:00
|
|
|
auto box_ptr = cx.build.Load(box_ptr_alias);
|
2010-12-06 17:46:35 -08:00
|
|
|
auto null_test = cx.build.IsNull(box_ptr);
|
|
|
|
cx.build.CondBr(null_test, next_cx.llbb, load_rc_cx.llbb);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto rc_ptr =
|
|
|
|
load_rc_cx.build.GEP(box_ptr,
|
|
|
|
[C_int(0), C_int(abi::box_rc_field_refcnt)]);
|
2010-12-06 17:46:35 -08:00
|
|
|
auto rc = load_rc_cx.build.Load(rc_ptr);
|
|
|
|
auto const_test =
|
2011-05-12 17:24:54 +02:00
|
|
|
load_rc_cx.build.ICmp(lib::llvm::LLVMIntEQ,
|
|
|
|
C_int(abi::const_refcount as int), rc);
|
2010-12-06 17:46:35 -08:00
|
|
|
load_rc_cx.build.CondBr(const_test, next_cx.llbb, rc_adj_cx.llbb);
|
2010-11-09 17:49:20 -08:00
|
|
|
rc = rc_adj_cx.build.Sub(rc, C_int(1));
|
|
|
|
rc_adj_cx.build.Store(rc, rc_ptr);
|
2011-05-12 17:24:54 +02:00
|
|
|
auto zero_test = rc_adj_cx.build.ICmp(lib::llvm::LLVMIntEQ, C_int(0), rc);
|
2011-05-18 17:28:08 -07:00
|
|
|
rc_adj_cx.build.CondBr(zero_test, free_cx.llbb, next_cx.llbb);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto free_res =
|
|
|
|
free_ty(free_cx, load_if_immediate(free_cx, full_alias, t), t);
|
2011-05-18 17:28:08 -07:00
|
|
|
free_res.bcx.build.Br(next_cx.llbb);
|
|
|
|
auto t_else = T_nil();
|
|
|
|
auto v_else = C_nil();
|
2011-06-15 11:19:50 -07:00
|
|
|
auto phi =
|
|
|
|
next_cx.build.Phi(t_else, [v_else, v_else, v_else, free_res.val],
|
|
|
|
[cx.llbb, load_rc_cx.llbb, rc_adj_cx.llbb,
|
|
|
|
free_res.bcx.llbb]);
|
2010-10-04 15:55:12 -07:00
|
|
|
ret res(next_cx, phi);
|
2010-10-01 18:25:42 -07:00
|
|
|
}
|
|
|
|
|
2011-04-19 15:22:57 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
// Structural comparison: a rather involved form of glue.
|
2011-05-11 04:58:46 +00:00
|
|
|
fn maybe_name_value(&@crate_ctxt cx, ValueRef v, &str s) {
|
2011-05-10 16:43:34 -07:00
|
|
|
if (cx.sess.get_opts().save_temps) {
|
2011-05-17 20:41:41 +02:00
|
|
|
llvm::LLVMSetValueName(v, str::buf(s));
|
2011-05-10 16:43:34 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn make_cmp_glue(&@block_ctxt cx, ValueRef lhs0, ValueRef rhs0, &ty::t t,
|
2011-04-19 15:22:57 -07:00
|
|
|
ValueRef llop) {
|
|
|
|
auto lhs = load_if_immediate(cx, lhs0, t);
|
|
|
|
auto rhs = load_if_immediate(cx, rhs0, t);
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_is_scalar(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-04-19 15:22:57 -07:00
|
|
|
make_scalar_cmp_glue(cx, lhs, rhs, t, llop);
|
2011-05-12 17:24:54 +02:00
|
|
|
} else if (ty::type_is_box(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-05-16 18:21:22 -07:00
|
|
|
lhs = cx.build.GEP(lhs, [C_int(0), C_int(abi::box_rc_field_body)]);
|
|
|
|
rhs = cx.build.GEP(rhs, [C_int(0), C_int(abi::box_rc_field_body)]);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto t_inner =
|
|
|
|
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
|
|
|
|
case (ty::ty_box(?ti)) { ti.ty }
|
|
|
|
};
|
2011-05-12 15:42:12 -07:00
|
|
|
auto rslt = call_cmp_glue(cx, lhs, rhs, t_inner, llop);
|
2011-04-19 15:22:57 -07:00
|
|
|
rslt.bcx.build.Store(rslt.val, cx.fcx.llretptr);
|
|
|
|
rslt.bcx.build.RetVoid();
|
2011-06-15 11:19:50 -07:00
|
|
|
} else if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, t) ||
|
|
|
|
ty::type_is_sequence(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-04-19 15:22:57 -07:00
|
|
|
auto scx = new_sub_block_ctxt(cx, "structural compare start");
|
|
|
|
auto next = new_sub_block_ctxt(cx, "structural compare end");
|
|
|
|
cx.build.Br(scx.llbb);
|
|
|
|
/*
|
|
|
|
* We're doing lexicographic comparison here. We start with the
|
|
|
|
* assumption that the two input elements are equal. Depending on
|
|
|
|
* operator, this means that the result is either true or false;
|
|
|
|
* equality produces 'true' for ==, <= and >=. It produces 'false' for
|
|
|
|
* !=, < and >.
|
|
|
|
*
|
|
|
|
* We then move one element at a time through the structure checking
|
2011-05-12 17:24:54 +02:00
|
|
|
* for pairwise element equality: If we have equality, our assumption
|
2011-04-19 15:22:57 -07:00
|
|
|
* about overall sequence equality is not modified, so we have to move
|
|
|
|
* to the next element.
|
|
|
|
*
|
|
|
|
* If we do not have pairwise element equality, we have reached an
|
|
|
|
* element that 'decides' the lexicographic comparison. So we exit the
|
|
|
|
* loop with a flag that indicates the true/false sense of that
|
|
|
|
* decision, by testing the element again with the operator we're
|
|
|
|
* interested in.
|
|
|
|
*
|
|
|
|
* When we're lucky, LLVM should be able to fold some of these two
|
|
|
|
* tests together (as they're applied to the same operands and in some
|
|
|
|
* cases are sometimes redundant). But we don't bother trying to
|
|
|
|
* optimize combinations like that, at this level.
|
|
|
|
*/
|
|
|
|
|
|
|
|
auto flag = alloca(scx, T_i1());
|
2011-05-10 16:43:34 -07:00
|
|
|
maybe_name_value(cx.fcx.lcx.ccx, flag, "flag");
|
2011-04-19 15:22:57 -07:00
|
|
|
auto r;
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_is_sequence(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-04-19 15:22:57 -07:00
|
|
|
// If we hit == all the way through the minimum-shared-length
|
|
|
|
// section, default to judging the relative sequence lengths.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
r =
|
|
|
|
compare_numerical_values(scx, vec_fill(scx, lhs),
|
|
|
|
vec_fill(scx, rhs), unsigned_int,
|
2011-06-02 16:23:52 -07:00
|
|
|
llop);
|
2011-04-19 15:22:57 -07:00
|
|
|
r.bcx.build.Store(r.val, flag);
|
|
|
|
} else {
|
|
|
|
// == and <= default to true if they find == all the way. <
|
|
|
|
// defaults to false if it finds == all the way.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
auto result_if_equal =
|
|
|
|
scx.build.ICmp(lib::llvm::LLVMIntNE, llop,
|
|
|
|
C_u8(abi::cmp_glue_op_lt));
|
2011-04-19 15:22:57 -07:00
|
|
|
scx.build.Store(result_if_equal, flag);
|
|
|
|
r = res(scx, C_nil());
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
fn inner(@block_ctxt last_cx, bool load_inner, ValueRef flag,
|
|
|
|
ValueRef llop, &@block_ctxt cx, ValueRef av0, ValueRef bv0,
|
2011-05-12 17:24:54 +02:00
|
|
|
ty::t t) -> result {
|
2011-04-19 15:22:57 -07:00
|
|
|
auto cnt_cx = new_sub_block_ctxt(cx, "continue_comparison");
|
|
|
|
auto stop_cx = new_sub_block_ctxt(cx, "stop_comparison");
|
|
|
|
auto av = av0;
|
|
|
|
auto bv = bv0;
|
|
|
|
if (load_inner) {
|
|
|
|
// If `load_inner` is true, then the pointer type will always
|
|
|
|
// be i8, because the data part of a vector always has type
|
|
|
|
// i8[]. So we need to cast it to the proper type.
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
if (!ty::type_has_dynamic_size(last_cx.fcx.lcx.ccx.tcx, t)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llelemty =
|
|
|
|
T_ptr(type_of(last_cx.fcx.lcx.ccx, last_cx.sp, t));
|
2011-04-19 15:22:57 -07:00
|
|
|
av = cx.build.PointerCast(av, llelemty);
|
|
|
|
bv = cx.build.PointerCast(bv, llelemty);
|
|
|
|
}
|
|
|
|
av = load_if_immediate(cx, av, t);
|
|
|
|
bv = load_if_immediate(cx, bv, t);
|
|
|
|
}
|
|
|
|
// First 'eq' comparison: if so, continue to next elts.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto eq_r =
|
|
|
|
call_cmp_glue(cx, av, bv, t, C_u8(abi::cmp_glue_op_eq));
|
|
|
|
eq_r.bcx.build.CondBr(eq_r.val, cnt_cx.llbb, stop_cx.llbb);
|
2011-04-19 15:22:57 -07:00
|
|
|
// Second 'op' comparison: find out how this elt-pair decides.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-19 15:22:57 -07:00
|
|
|
auto stop_r = call_cmp_glue(stop_cx, av, bv, t, llop);
|
|
|
|
stop_r.bcx.build.Store(stop_r.val, flag);
|
|
|
|
stop_r.bcx.build.Br(last_cx.llbb);
|
|
|
|
ret res(cnt_cx, C_nil());
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
r =
|
|
|
|
iter_structural_ty_full(r.bcx, lhs, rhs, t,
|
|
|
|
bind inner(next, false, flag, llop, _,
|
|
|
|
_, _, _));
|
2011-04-19 15:22:57 -07:00
|
|
|
} else {
|
|
|
|
auto lhs_p0 = vec_p0(r.bcx, lhs);
|
|
|
|
auto rhs_p0 = vec_p0(r.bcx, rhs);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto min_len =
|
|
|
|
umin(r.bcx, vec_fill(r.bcx, lhs), vec_fill(r.bcx, rhs));
|
2011-05-16 18:21:22 -07:00
|
|
|
auto rhs_lim = r.bcx.build.GEP(rhs_p0, [min_len]);
|
2011-05-12 17:24:54 +02:00
|
|
|
auto elt_ty = ty::sequence_element_type(cx.fcx.lcx.ccx.tcx, t);
|
2011-04-19 15:22:57 -07:00
|
|
|
r = size_of(r.bcx, elt_ty);
|
2011-06-15 11:19:50 -07:00
|
|
|
r =
|
|
|
|
iter_sequence_raw(r.bcx, lhs_p0, rhs_p0, rhs_lim, r.val,
|
|
|
|
bind inner(next, true, flag, llop, _, _, _,
|
|
|
|
elt_ty));
|
2011-04-19 15:22:57 -07:00
|
|
|
}
|
|
|
|
r.bcx.build.Br(next.llbb);
|
|
|
|
auto v = next.build.Load(flag);
|
|
|
|
next.build.Store(v, cx.fcx.llretptr);
|
|
|
|
next.build.RetVoid();
|
|
|
|
} else {
|
|
|
|
// FIXME: compare obj, fn by pointer?
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
trans_fail(cx, none[common::span],
|
2011-04-22 17:00:46 -07:00
|
|
|
"attempt to compare values of type " +
|
2011-06-15 11:19:50 -07:00
|
|
|
ty_to_str(cx.fcx.lcx.ccx.tcx, t));
|
2011-04-19 15:22:57 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-02 16:23:52 -07:00
|
|
|
// Used only for creating scalar comparsion glue.
|
2011-06-15 11:19:50 -07:00
|
|
|
tag numerical_type { signed_int; unsigned_int; floating_point; }
|
|
|
|
|
2011-06-02 16:23:52 -07:00
|
|
|
|
2011-04-19 15:22:57 -07:00
|
|
|
// A helper function to create scalar comparison glue.
|
2011-06-15 11:19:50 -07:00
|
|
|
fn make_scalar_cmp_glue(&@block_ctxt cx, ValueRef lhs, ValueRef rhs, &ty::t t,
|
|
|
|
ValueRef llop) {
|
2011-06-02 16:23:52 -07:00
|
|
|
// assert ty::type_is_scalar(cx.fcx.lcx.ccx.tcx, t);
|
2011-04-19 15:22:57 -07:00
|
|
|
|
2011-06-02 16:23:52 -07:00
|
|
|
// In most cases, we need to know whether to do signed, unsigned, or float
|
|
|
|
// comparison.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-02 16:23:52 -07:00
|
|
|
auto f = bind make_numerical_cmp_glue(cx, lhs, rhs, _, llop);
|
2011-04-19 15:22:57 -07:00
|
|
|
|
2011-06-02 16:23:52 -07:00
|
|
|
// FIXME: this could be a lot shorter if we could combine multiple cases
|
|
|
|
// of alt expressions (issue #449).
|
|
|
|
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_nil) {
|
2011-06-02 16:23:52 -07:00
|
|
|
cx.build.Store(C_bool(true), cx.fcx.llretptr);
|
|
|
|
cx.build.RetVoid();
|
|
|
|
}
|
|
|
|
case (ty::ty_bool) { f(unsigned_int); }
|
|
|
|
case (ty::ty_int) { f(signed_int); }
|
|
|
|
case (ty::ty_float) { f(floating_point); }
|
|
|
|
case (ty::ty_uint) { f(unsigned_int); }
|
|
|
|
case (ty::ty_machine(_)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-02 16:23:52 -07:00
|
|
|
// Floating point machine types
|
|
|
|
if (ty::type_is_fp(cx.fcx.lcx.ccx.tcx, t)) {
|
|
|
|
f(floating_point);
|
2011-06-15 11:19:50 -07:00
|
|
|
} else if (
|
|
|
|
// Signed, integral machine types
|
|
|
|
ty::type_is_signed(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-06-02 16:23:52 -07:00
|
|
|
f(signed_int);
|
2011-06-15 11:19:50 -07:00
|
|
|
} else
|
|
|
|
// Unsigned, integral machine types
|
|
|
|
{
|
|
|
|
f(unsigned_int);
|
2011-06-02 16:23:52 -07:00
|
|
|
}
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_char) { f(unsigned_int); }
|
|
|
|
case (ty::ty_type) {
|
2011-06-02 16:23:52 -07:00
|
|
|
trans_fail(cx, none[common::span],
|
|
|
|
"attempt to compare values of type type");
|
|
|
|
}
|
|
|
|
case (ty::ty_native) {
|
|
|
|
trans_fail(cx, none[common::span],
|
|
|
|
"attempt to compare values of type native");
|
|
|
|
}
|
|
|
|
case (_) {
|
|
|
|
// Should never get here, because t is scalar.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
cx.fcx.lcx.ccx.sess.bug("non-scalar type passed to " +
|
|
|
|
"make_scalar_cmp_glue");
|
2011-06-02 16:23:52 -07:00
|
|
|
}
|
2011-04-19 15:22:57 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-02 16:23:52 -07:00
|
|
|
// A helper function to compare numerical values.
|
|
|
|
fn compare_numerical_values(&@block_ctxt cx, ValueRef lhs, ValueRef rhs,
|
|
|
|
numerical_type nt, ValueRef llop) -> result {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto eq_cmp;
|
|
|
|
auto lt_cmp;
|
|
|
|
auto le_cmp;
|
2011-06-02 16:23:52 -07:00
|
|
|
alt (nt) {
|
|
|
|
case (floating_point) {
|
|
|
|
eq_cmp = lib::llvm::LLVMRealUEQ;
|
|
|
|
lt_cmp = lib::llvm::LLVMRealULT;
|
|
|
|
le_cmp = lib::llvm::LLVMRealULE;
|
|
|
|
}
|
|
|
|
case (signed_int) {
|
|
|
|
eq_cmp = lib::llvm::LLVMIntEQ;
|
|
|
|
lt_cmp = lib::llvm::LLVMIntSLT;
|
|
|
|
le_cmp = lib::llvm::LLVMIntSLE;
|
|
|
|
}
|
|
|
|
case (unsigned_int) {
|
|
|
|
eq_cmp = lib::llvm::LLVMIntEQ;
|
|
|
|
lt_cmp = lib::llvm::LLVMIntULT;
|
|
|
|
le_cmp = lib::llvm::LLVMIntULE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// FIXME: This wouldn't be necessary if we could bind methods off of
|
|
|
|
// objects and therefore abstract over FCmp and ICmp (issue #435). Then
|
|
|
|
// we could just write, e.g., "cmp_fn = bind cx.build.FCmp(_, _, _);" in
|
|
|
|
// the above, and "auto eq_result = cmp_fn(eq_cmp, lhs, rhs);" in the
|
|
|
|
// below.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
fn generic_cmp(&@block_ctxt cx, numerical_type nt, uint op, ValueRef lhs,
|
|
|
|
ValueRef rhs) -> ValueRef {
|
2011-06-02 16:23:52 -07:00
|
|
|
let ValueRef r;
|
|
|
|
if (nt == floating_point) {
|
|
|
|
r = cx.build.FCmp(op, lhs, rhs);
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { r = cx.build.ICmp(op, lhs, rhs); }
|
2011-06-02 16:23:52 -07:00
|
|
|
ret r;
|
2011-04-19 15:22:57 -07:00
|
|
|
}
|
|
|
|
auto last_cx = new_sub_block_ctxt(cx, "last");
|
|
|
|
auto eq_cx = new_sub_block_ctxt(cx, "eq");
|
2011-06-02 16:23:52 -07:00
|
|
|
auto eq_result = generic_cmp(eq_cx, nt, eq_cmp, lhs, rhs);
|
2011-04-19 15:22:57 -07:00
|
|
|
eq_cx.build.Br(last_cx.llbb);
|
|
|
|
auto lt_cx = new_sub_block_ctxt(cx, "lt");
|
2011-06-02 16:23:52 -07:00
|
|
|
auto lt_result = generic_cmp(lt_cx, nt, lt_cmp, lhs, rhs);
|
2011-04-19 15:22:57 -07:00
|
|
|
lt_cx.build.Br(last_cx.llbb);
|
|
|
|
auto le_cx = new_sub_block_ctxt(cx, "le");
|
2011-06-02 16:23:52 -07:00
|
|
|
auto le_result = generic_cmp(le_cx, nt, le_cmp, lhs, rhs);
|
2011-04-19 15:22:57 -07:00
|
|
|
le_cx.build.Br(last_cx.llbb);
|
|
|
|
auto unreach_cx = new_sub_block_ctxt(cx, "unreach");
|
|
|
|
unreach_cx.build.Unreachable();
|
|
|
|
auto llswitch = cx.build.Switch(llop, unreach_cx.llbb, 3u);
|
2011-05-12 17:24:54 +02:00
|
|
|
llvm::LLVMAddCase(llswitch, C_u8(abi::cmp_glue_op_eq), eq_cx.llbb);
|
|
|
|
llvm::LLVMAddCase(llswitch, C_u8(abi::cmp_glue_op_lt), lt_cx.llbb);
|
|
|
|
llvm::LLVMAddCase(llswitch, C_u8(abi::cmp_glue_op_le), le_cx.llbb);
|
2011-04-19 15:22:57 -07:00
|
|
|
auto last_result =
|
2011-05-16 18:21:22 -07:00
|
|
|
last_cx.build.Phi(T_i1(), [eq_result, lt_result, le_result],
|
|
|
|
[eq_cx.llbb, lt_cx.llbb, le_cx.llbb]);
|
2011-04-19 15:22:57 -07:00
|
|
|
ret res(last_cx, last_result);
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-02 16:23:52 -07:00
|
|
|
// A helper function to create numerical comparison glue.
|
|
|
|
fn make_numerical_cmp_glue(&@block_ctxt cx, ValueRef lhs, ValueRef rhs,
|
2011-06-15 11:19:50 -07:00
|
|
|
numerical_type nt, ValueRef llop) {
|
2011-06-02 16:23:52 -07:00
|
|
|
auto r = compare_numerical_values(cx, lhs, rhs, nt, llop);
|
2011-04-19 15:22:57 -07:00
|
|
|
r.bcx.build.Store(r.val, r.bcx.fcx.llretptr);
|
|
|
|
r.bcx.build.RetVoid();
|
2011-04-18 10:56:52 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-10 19:35:59 -07:00
|
|
|
// Returns the length of an interior vector and a pointer to its first
|
|
|
|
// element, in that order.
|
|
|
|
fn get_ivec_len_and_data(&@block_ctxt bcx, ValueRef v, ty::t unit_ty) ->
|
2011-06-15 11:19:50 -07:00
|
|
|
tup(ValueRef, ValueRef, @block_ctxt) {
|
2011-06-10 19:35:59 -07:00
|
|
|
auto llunitty = type_of_or_i8(bcx, unit_ty);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto stack_len =
|
|
|
|
bcx.build.Load(bcx.build.InBoundsGEP(v,
|
|
|
|
[C_int(0),
|
|
|
|
C_uint(abi::ivec_elt_len)]));
|
|
|
|
auto stack_elem =
|
|
|
|
bcx.build.InBoundsGEP(v,
|
|
|
|
[C_int(0), C_uint(abi::ivec_elt_elems),
|
|
|
|
C_int(0)]);
|
2011-06-10 19:35:59 -07:00
|
|
|
auto on_heap = bcx.build.ICmp(lib::llvm::LLVMIntEQ, stack_len, C_int(0));
|
|
|
|
auto on_heap_cx = new_sub_block_ctxt(bcx, "on_heap");
|
|
|
|
auto next_cx = new_sub_block_ctxt(bcx, "next");
|
|
|
|
bcx.build.CondBr(on_heap, on_heap_cx.llbb, next_cx.llbb);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto heap_stub =
|
|
|
|
on_heap_cx.build.PointerCast(v, T_ptr(T_ivec_heap(llunitty)));
|
|
|
|
auto heap_ptr =
|
|
|
|
{
|
|
|
|
auto v = [C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)];
|
|
|
|
on_heap_cx.build.Load(on_heap_cx.build.InBoundsGEP(heap_stub, v))
|
|
|
|
};
|
2011-06-10 19:35:59 -07:00
|
|
|
// Check whether the heap pointer is null. If it is, the vector length is
|
|
|
|
// truly zero.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-10 19:35:59 -07:00
|
|
|
auto llstubty = T_ivec_heap(llunitty);
|
|
|
|
auto llheapptrty = struct_elt(llstubty, abi::ivec_heap_stub_elt_ptr);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto heap_ptr_is_null =
|
|
|
|
on_heap_cx.build.ICmp(lib::llvm::LLVMIntEQ, heap_ptr,
|
|
|
|
C_null(T_ptr(llheapptrty)));
|
2011-06-10 19:35:59 -07:00
|
|
|
auto zero_len_cx = new_sub_block_ctxt(bcx, "zero_len");
|
|
|
|
auto nonzero_len_cx = new_sub_block_ctxt(bcx, "nonzero_len");
|
|
|
|
on_heap_cx.build.CondBr(heap_ptr_is_null, zero_len_cx.llbb,
|
|
|
|
nonzero_len_cx.llbb);
|
|
|
|
// Technically this context is unnecessary, but it makes this function
|
|
|
|
// clearer.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-10 19:35:59 -07:00
|
|
|
auto zero_len = C_int(0);
|
2011-06-12 00:44:43 -07:00
|
|
|
auto zero_elem = C_null(T_ptr(llunitty));
|
2011-06-10 19:35:59 -07:00
|
|
|
zero_len_cx.build.Br(next_cx.llbb);
|
|
|
|
// If we're here, then we actually have a heapified vector.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
auto heap_len =
|
|
|
|
{
|
|
|
|
auto v = [C_int(0), C_uint(abi::ivec_heap_elt_len)];
|
|
|
|
auto m = nonzero_len_cx.build.InBoundsGEP(heap_ptr,v);
|
|
|
|
nonzero_len_cx.build.Load(m)
|
|
|
|
};
|
|
|
|
auto heap_elem =
|
2011-06-11 23:32:21 -07:00
|
|
|
nonzero_len_cx.build.InBoundsGEP(heap_ptr,
|
2011-06-15 11:19:50 -07:00
|
|
|
[C_int(0),
|
|
|
|
C_uint(abi::ivec_heap_elt_elems),
|
|
|
|
C_int(0)]);
|
2011-06-10 19:35:59 -07:00
|
|
|
nonzero_len_cx.build.Br(next_cx.llbb);
|
|
|
|
// Now we can figure out the length of `v` and get a pointer to its first
|
|
|
|
// element.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
auto len =
|
|
|
|
next_cx.build.Phi(T_int(), [stack_len, zero_len, heap_len],
|
|
|
|
[bcx.llbb, zero_len_cx.llbb, nonzero_len_cx.llbb]);
|
|
|
|
auto elem =
|
|
|
|
next_cx.build.Phi(T_ptr(llunitty), [stack_elem, zero_elem, heap_elem],
|
|
|
|
[bcx.llbb, zero_len_cx.llbb, nonzero_len_cx.llbb]);
|
2011-06-10 19:35:59 -07:00
|
|
|
ret tup(len, elem, next_cx);
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
type val_pair_fn = fn(&@block_ctxt, ValueRef, ValueRef) -> result ;
|
2011-03-06 22:37:14 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
type val_and_ty_fn = fn(&@block_ctxt, ValueRef, ty::t) -> result ;
|
2010-11-24 16:55:45 -08:00
|
|
|
|
2011-02-28 17:49:26 -08:00
|
|
|
type val_pair_and_ty_fn =
|
2011-06-15 11:19:50 -07:00
|
|
|
fn(&@block_ctxt, ValueRef, ValueRef, ty::t) -> result ;
|
|
|
|
|
2011-02-28 17:49:26 -08:00
|
|
|
|
2010-12-20 16:23:49 -08:00
|
|
|
// Iterates through the elements of a structural type.
|
2011-06-15 11:19:50 -07:00
|
|
|
fn iter_structural_ty(&@block_ctxt cx, ValueRef v, &ty::t t, val_and_ty_fn f)
|
|
|
|
-> result {
|
|
|
|
fn adaptor_fn(val_and_ty_fn f, &@block_ctxt cx, ValueRef av, ValueRef bv,
|
2011-05-12 17:24:54 +02:00
|
|
|
ty::t t) -> result {
|
2011-02-28 17:49:26 -08:00
|
|
|
ret f(cx, av, t);
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
be iter_structural_ty_full(cx, v, v, t, bind adaptor_fn(f, _, _, _, _));
|
2011-02-28 17:49:26 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn iter_structural_ty_full(&@block_ctxt cx, ValueRef av, ValueRef bv,
|
|
|
|
&ty::t t, &val_pair_and_ty_fn f) -> result {
|
|
|
|
fn iter_boxpp(@block_ctxt cx, ValueRef box_a_cell, ValueRef box_b_cell,
|
2011-05-11 04:58:46 +00:00
|
|
|
&val_pair_and_ty_fn f) -> result {
|
2011-02-28 17:49:26 -08:00
|
|
|
auto box_a_ptr = cx.build.Load(box_a_cell);
|
|
|
|
auto box_b_ptr = cx.build.Load(box_b_cell);
|
2011-05-12 17:24:54 +02:00
|
|
|
auto tnil = ty::mk_nil(cx.fcx.lcx.ccx.tcx);
|
|
|
|
auto tbox = ty::mk_imm_box(cx.fcx.lcx.ccx.tcx, tnil);
|
2010-12-20 17:28:07 -08:00
|
|
|
auto inner_cx = new_sub_block_ctxt(cx, "iter box");
|
|
|
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
2011-02-28 17:49:26 -08:00
|
|
|
auto null_test = cx.build.IsNull(box_a_ptr);
|
2010-12-20 17:28:07 -08:00
|
|
|
cx.build.CondBr(null_test, next_cx.llbb, inner_cx.llbb);
|
2011-02-28 17:49:26 -08:00
|
|
|
auto r = f(inner_cx, box_a_ptr, box_b_ptr, tbox);
|
2010-12-20 17:28:07 -08:00
|
|
|
r.bcx.build.Br(next_cx.llbb);
|
2011-04-26 20:39:25 +00:00
|
|
|
ret res(next_cx, C_nil());
|
2010-12-20 17:28:07 -08:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
fn iter_ivec(@block_ctxt bcx, ValueRef av, ValueRef bv, ty::t unit_ty,
|
2011-06-10 19:35:59 -07:00
|
|
|
&val_pair_and_ty_fn f) -> result {
|
|
|
|
// FIXME: "unimplemented rebinding existing function" workaround
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-10 19:35:59 -07:00
|
|
|
fn adapter(&@block_ctxt bcx, ValueRef av, ValueRef bv, ty::t unit_ty,
|
|
|
|
val_pair_and_ty_fn f) -> result {
|
|
|
|
ret f(bcx, av, bv, unit_ty);
|
|
|
|
}
|
|
|
|
auto llunitty = type_of_or_i8(bcx, unit_ty);
|
|
|
|
auto rslt = size_of(bcx, unit_ty);
|
|
|
|
auto unit_sz = rslt.val;
|
|
|
|
bcx = rslt.bcx;
|
|
|
|
auto a_len_and_data = get_ivec_len_and_data(bcx, av, unit_ty);
|
|
|
|
auto a_len = a_len_and_data._0;
|
|
|
|
auto a_elem = a_len_and_data._1;
|
|
|
|
bcx = a_len_and_data._2;
|
|
|
|
auto b_len_and_data = get_ivec_len_and_data(bcx, bv, unit_ty);
|
|
|
|
auto b_len = b_len_and_data._0;
|
|
|
|
auto b_elem = b_len_and_data._1;
|
|
|
|
bcx = b_len_and_data._2;
|
|
|
|
// Calculate the last pointer address we want to handle.
|
2011-06-12 00:44:43 -07:00
|
|
|
// TODO: Optimize this when the size of the unit type is statically
|
|
|
|
// known to not use pointer casts, which tend to confuse LLVM.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-10 19:35:59 -07:00
|
|
|
auto len = umin(bcx, a_len, b_len);
|
|
|
|
auto b_elem_i8 = bcx.build.PointerCast(b_elem, T_ptr(T_i8()));
|
|
|
|
auto b_end_i8 = bcx.build.GEP(b_elem_i8, [len]);
|
|
|
|
auto b_end = bcx.build.PointerCast(b_end_i8, T_ptr(llunitty));
|
|
|
|
// Now perform the iteration.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-10 19:35:59 -07:00
|
|
|
auto vpf = bind adapter(_, _, _, unit_ty, f);
|
|
|
|
ret iter_sequence_raw(bcx, a_elem, b_elem, b_end, unit_sz, vpf);
|
|
|
|
}
|
|
|
|
let result r = res(cx, C_nil());
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
|
|
|
|
case (ty::ty_tup(?args)) {
|
2010-11-24 16:55:45 -08:00
|
|
|
let int i = 0;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ty::mt arg in args) {
|
2011-05-16 18:21:22 -07:00
|
|
|
r = GEP_tup_like(r.bcx, t, av, [0, i]);
|
2011-03-02 16:31:20 -08:00
|
|
|
auto elt_a = r.val;
|
2011-05-16 18:21:22 -07:00
|
|
|
r = GEP_tup_like(r.bcx, t, bv, [0, i]);
|
2011-03-02 16:31:20 -08:00
|
|
|
auto elt_b = r.val;
|
2011-06-15 11:19:50 -07:00
|
|
|
r =
|
|
|
|
f(r.bcx, load_if_immediate(r.bcx, elt_a, arg.ty),
|
|
|
|
load_if_immediate(r.bcx, elt_b, arg.ty), arg.ty);
|
2010-11-24 16:55:45 -08:00
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_rec(?fields)) {
|
2010-12-01 17:08:46 -08:00
|
|
|
let int i = 0;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ty::field fld in fields) {
|
2011-05-16 18:21:22 -07:00
|
|
|
r = GEP_tup_like(r.bcx, t, av, [0, i]);
|
2011-03-02 16:31:20 -08:00
|
|
|
auto llfld_a = r.val;
|
2011-05-16 18:21:22 -07:00
|
|
|
r = GEP_tup_like(r.bcx, t, bv, [0, i]);
|
2011-03-02 16:31:20 -08:00
|
|
|
auto llfld_b = r.val;
|
2011-06-15 11:19:50 -07:00
|
|
|
r =
|
|
|
|
f(r.bcx, load_if_immediate(r.bcx, llfld_a, fld.mt.ty),
|
2011-04-12 12:06:20 -07:00
|
|
|
load_if_immediate(r.bcx, llfld_b, fld.mt.ty),
|
2011-03-17 17:39:47 -07:00
|
|
|
fld.mt.ty);
|
2010-12-01 17:08:46 -08:00
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_tag(?tid, ?tps)) {
|
2011-05-19 17:21:21 -07:00
|
|
|
auto variants = ty::tag_variants(cx.fcx.lcx.ccx.tcx, tid);
|
|
|
|
auto n_variants = vec::len[ty::variant_info](variants);
|
2011-03-07 18:03:33 -08:00
|
|
|
// Cast the tags to types we can GEP into.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
auto lltagty = T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn);
|
2011-03-07 18:03:33 -08:00
|
|
|
auto av_tag = cx.build.PointerCast(av, lltagty);
|
|
|
|
auto bv_tag = cx.build.PointerCast(bv, lltagty);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto lldiscrim_a_ptr = cx.build.GEP(av_tag, [C_int(0), C_int(0)]);
|
|
|
|
auto llunion_a_ptr = cx.build.GEP(av_tag, [C_int(0), C_int(1)]);
|
2011-02-28 17:49:26 -08:00
|
|
|
auto lldiscrim_a = cx.build.Load(lldiscrim_a_ptr);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto lldiscrim_b_ptr = cx.build.GEP(bv_tag, [C_int(0), C_int(0)]);
|
|
|
|
auto llunion_b_ptr = cx.build.GEP(bv_tag, [C_int(0), C_int(1)]);
|
2011-02-28 17:49:26 -08:00
|
|
|
auto lldiscrim_b = cx.build.Load(lldiscrim_b_ptr);
|
2011-03-01 13:00:50 -08:00
|
|
|
// NB: we must hit the discriminant first so that structural
|
|
|
|
// comparison know not to proceed when the discriminants differ.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto bcx = cx;
|
|
|
|
bcx =
|
|
|
|
f(bcx, lldiscrim_a, lldiscrim_b,
|
|
|
|
ty::mk_int(cx.fcx.lcx.ccx.tcx)).bcx;
|
2011-03-01 13:00:50 -08:00
|
|
|
auto unr_cx = new_sub_block_ctxt(bcx, "tag-iter-unr");
|
2010-12-02 19:30:06 -08:00
|
|
|
unr_cx.build.Unreachable();
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llswitch =
|
|
|
|
bcx.build.Switch(lldiscrim_a, unr_cx.llbb, n_variants);
|
2011-03-01 13:00:50 -08:00
|
|
|
auto next_cx = new_sub_block_ctxt(bcx, "tag-iter-next");
|
2010-12-02 19:30:06 -08:00
|
|
|
auto i = 0u;
|
2011-05-19 17:21:21 -07:00
|
|
|
for (ty::variant_info variant in variants) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto variant_cx =
|
|
|
|
new_sub_block_ctxt(bcx,
|
|
|
|
"tag-iter-variant-" +
|
|
|
|
uint::to_str(i, 10u));
|
2011-05-12 17:24:54 +02:00
|
|
|
llvm::LLVMAddCase(llswitch, C_int(i as int), variant_cx.llbb);
|
2011-05-17 20:41:41 +02:00
|
|
|
if (vec::len[ty::t](variant.args) > 0u) {
|
2011-02-25 17:14:48 -08:00
|
|
|
// N-ary variant.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-01 11:36:52 -07:00
|
|
|
auto fn_ty = variant.ctor_ty;
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(bcx.fcx.lcx.ccx.tcx, fn_ty)) {
|
2011-06-09 09:48:16 -07:00
|
|
|
case (ty::ty_fn(_, ?args, _, _, _)) {
|
2011-03-18 18:33:21 -07:00
|
|
|
auto j = 0;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ty::arg a in args) {
|
2011-05-16 18:21:22 -07:00
|
|
|
auto v = [C_int(0), C_int(j as int)];
|
2011-06-15 11:19:50 -07:00
|
|
|
auto rslt =
|
|
|
|
GEP_tag(variant_cx, llunion_a_ptr, tid,
|
|
|
|
variant.id, tps, j);
|
2011-03-18 18:33:21 -07:00
|
|
|
auto llfldp_a = rslt.val;
|
|
|
|
variant_cx = rslt.bcx;
|
2011-06-15 11:19:50 -07:00
|
|
|
rslt =
|
|
|
|
GEP_tag(variant_cx, llunion_b_ptr, tid,
|
|
|
|
variant.id, tps, j);
|
2011-03-18 18:33:21 -07:00
|
|
|
auto llfldp_b = rslt.val;
|
|
|
|
variant_cx = rslt.bcx;
|
2011-06-15 11:19:50 -07:00
|
|
|
auto tcx = cx.fcx.lcx.ccx.tcx;
|
|
|
|
auto ty_subst =
|
|
|
|
ty::substitute_type_params(tcx,
|
|
|
|
tps, a.ty);
|
2011-02-28 17:49:26 -08:00
|
|
|
auto llfld_a =
|
2011-06-15 11:19:50 -07:00
|
|
|
load_if_immediate(variant_cx, llfldp_a,
|
|
|
|
ty_subst);
|
2011-02-28 17:49:26 -08:00
|
|
|
auto llfld_b =
|
2011-06-15 11:19:50 -07:00
|
|
|
load_if_immediate(variant_cx, llfldp_b,
|
|
|
|
ty_subst);
|
|
|
|
auto res =
|
|
|
|
f(variant_cx, llfld_a, llfld_b, ty_subst);
|
2011-02-25 17:14:48 -08:00
|
|
|
variant_cx = res.bcx;
|
2011-03-18 18:33:21 -07:00
|
|
|
j += 1;
|
2010-12-03 12:31:25 -08:00
|
|
|
}
|
|
|
|
}
|
2010-12-02 19:30:06 -08:00
|
|
|
}
|
2011-02-25 17:14:48 -08:00
|
|
|
variant_cx.build.Br(next_cx.llbb);
|
|
|
|
} else {
|
|
|
|
// Nullary variant; nothing to do.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-02-25 17:14:48 -08:00
|
|
|
variant_cx.build.Br(next_cx.llbb);
|
2010-12-02 19:30:06 -08:00
|
|
|
}
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
ret res(next_cx, C_nil());
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_fn(_, _, _, _, _)) {
|
2011-02-28 17:49:26 -08:00
|
|
|
auto box_cell_a =
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.build.GEP(av, [C_int(0), C_int(abi::fn_field_box)]);
|
2011-02-28 17:49:26 -08:00
|
|
|
auto box_cell_b =
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.build.GEP(bv, [C_int(0), C_int(abi::fn_field_box)]);
|
2011-02-28 17:49:26 -08:00
|
|
|
ret iter_boxpp(cx, box_cell_a, box_cell_b, f);
|
2010-12-20 16:23:49 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_obj(_)) {
|
2011-02-28 17:49:26 -08:00
|
|
|
auto box_cell_a =
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.build.GEP(av, [C_int(0), C_int(abi::obj_field_box)]);
|
2011-02-28 17:49:26 -08:00
|
|
|
auto box_cell_b =
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.build.GEP(bv, [C_int(0), C_int(abi::obj_field_box)]);
|
2011-02-28 17:49:26 -08:00
|
|
|
ret iter_boxpp(cx, box_cell_a, box_cell_b, f);
|
2010-12-20 16:23:49 -08:00
|
|
|
}
|
2011-06-10 19:35:59 -07:00
|
|
|
case (ty::ty_ivec(?unit_tm)) {
|
|
|
|
ret iter_ivec(cx, av, bv, unit_tm.ty, f);
|
|
|
|
}
|
|
|
|
case (ty::ty_istr) {
|
|
|
|
auto unit_ty = ty::mk_mach(cx.fcx.lcx.ccx.tcx, common::ty_u8);
|
|
|
|
ret iter_ivec(cx, av, bv, unit_ty, f);
|
|
|
|
}
|
2010-12-01 17:08:46 -08:00
|
|
|
case (_) {
|
2011-04-17 14:24:45 +02:00
|
|
|
cx.fcx.lcx.ccx.sess.unimpl("type in iter_structural_ty_full");
|
2010-12-01 17:08:46 -08:00
|
|
|
}
|
2010-11-09 17:49:20 -08:00
|
|
|
}
|
2010-11-24 16:55:45 -08:00
|
|
|
ret r;
|
2010-11-09 17:49:20 -08:00
|
|
|
}
|
|
|
|
|
2011-03-03 17:27:35 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
// Iterates through a pointer range, until the src* hits the src_lim*.
|
|
|
|
fn iter_sequence_raw(@block_ctxt cx, ValueRef dst,
|
|
|
|
// elt*
|
|
|
|
ValueRef src,
|
|
|
|
// elt*
|
|
|
|
ValueRef src_lim,
|
|
|
|
// elt*
|
|
|
|
ValueRef elt_sz, &val_pair_fn f) -> result {
|
2011-03-03 17:27:35 -08:00
|
|
|
auto bcx = cx;
|
2011-03-09 20:14:19 -08:00
|
|
|
let ValueRef dst_int = vp2i(bcx, dst);
|
2011-03-03 17:27:35 -08:00
|
|
|
let ValueRef src_int = vp2i(bcx, src);
|
|
|
|
let ValueRef src_lim_int = vp2i(bcx, src_lim);
|
|
|
|
auto cond_cx = new_scope_block_ctxt(cx, "sequence-iter cond");
|
|
|
|
auto body_cx = new_scope_block_ctxt(cx, "sequence-iter body");
|
|
|
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
|
|
|
bcx.build.Br(cond_cx.llbb);
|
2011-06-15 11:19:50 -07:00
|
|
|
let ValueRef dst_curr = cond_cx.build.Phi(T_int(), [dst_int], [bcx.llbb]);
|
|
|
|
let ValueRef src_curr = cond_cx.build.Phi(T_int(), [src_int], [bcx.llbb]);
|
|
|
|
auto end_test =
|
|
|
|
cond_cx.build.ICmp(lib::llvm::LLVMIntULT, src_curr, src_lim_int);
|
2011-03-03 17:27:35 -08:00
|
|
|
cond_cx.build.CondBr(end_test, body_cx.llbb, next_cx.llbb);
|
2011-03-09 20:14:19 -08:00
|
|
|
auto dst_curr_ptr = vi2p(body_cx, dst_curr, T_ptr(T_i8()));
|
2011-03-06 22:37:14 -08:00
|
|
|
auto src_curr_ptr = vi2p(body_cx, src_curr, T_ptr(T_i8()));
|
2011-03-09 20:14:19 -08:00
|
|
|
auto body_res = f(body_cx, dst_curr_ptr, src_curr_ptr);
|
2011-03-03 17:27:35 -08:00
|
|
|
body_cx = body_res.bcx;
|
2011-03-09 20:14:19 -08:00
|
|
|
auto dst_next = body_cx.build.Add(dst_curr, elt_sz);
|
2011-03-06 22:37:14 -08:00
|
|
|
auto src_next = body_cx.build.Add(src_curr, elt_sz);
|
2011-03-03 17:27:35 -08:00
|
|
|
body_cx.build.Br(cond_cx.llbb);
|
2011-06-15 11:19:50 -07:00
|
|
|
cond_cx.build.AddIncomingToPhi(dst_curr, [dst_next], [body_cx.llbb]);
|
|
|
|
cond_cx.build.AddIncomingToPhi(src_curr, [src_next], [body_cx.llbb]);
|
2011-03-03 17:27:35 -08:00
|
|
|
ret res(next_cx, C_nil());
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn iter_sequence_inner(&@block_ctxt cx, ValueRef src,
|
|
|
|
// elt*
|
|
|
|
ValueRef src_lim,
|
|
|
|
& // elt*
|
|
|
|
ty::t elt_ty, &val_and_ty_fn f) -> result {
|
|
|
|
fn adaptor_fn(val_and_ty_fn f, ty::t elt_ty, &@block_ctxt cx,
|
|
|
|
ValueRef dst, ValueRef src) -> result {
|
2011-03-18 16:04:16 -07:00
|
|
|
auto llptrty;
|
2011-05-12 17:24:54 +02:00
|
|
|
if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, elt_ty)) {
|
2011-05-18 15:35:16 -07:00
|
|
|
auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, elt_ty);
|
2011-03-18 16:04:16 -07:00
|
|
|
llptrty = T_ptr(llty);
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { llptrty = T_ptr(T_ptr(T_i8())); }
|
2011-03-18 16:04:16 -07:00
|
|
|
auto p = cx.build.PointerCast(src, llptrty);
|
2011-04-12 12:06:20 -07:00
|
|
|
ret f(cx, load_if_immediate(cx, p, elt_ty), elt_ty);
|
2011-03-03 17:27:35 -08:00
|
|
|
}
|
2011-03-06 22:37:14 -08:00
|
|
|
auto elt_sz = size_of(cx, elt_ty);
|
2011-03-09 20:14:19 -08:00
|
|
|
be iter_sequence_raw(elt_sz.bcx, src, src, src_lim, elt_sz.val,
|
|
|
|
bind adaptor_fn(f, elt_ty, _, _, _));
|
2011-03-03 17:27:35 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-24 16:55:45 -08:00
|
|
|
// Iterates through the elements of a vec or str.
|
2011-06-15 11:19:50 -07:00
|
|
|
fn iter_sequence(@block_ctxt cx, ValueRef v, &ty::t t, &val_and_ty_fn f) ->
|
|
|
|
result {
|
|
|
|
fn iter_sequence_body(@block_ctxt cx, ValueRef v, &ty::t elt_ty,
|
|
|
|
&val_and_ty_fn f, bool trailing_null) -> result {
|
|
|
|
auto p0 = cx.build.GEP(v, [C_int(0), C_int(abi::vec_elt_data)]);
|
|
|
|
auto lenptr = cx.build.GEP(v, [C_int(0), C_int(abi::vec_elt_fill)]);
|
2011-03-18 16:04:16 -07:00
|
|
|
auto llunit_ty;
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, elt_ty)) {
|
2011-03-18 16:04:16 -07:00
|
|
|
llunit_ty = T_i8();
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { llunit_ty = type_of(cx.fcx.lcx.ccx, cx.sp, elt_ty); }
|
2011-01-31 15:03:05 -08:00
|
|
|
auto bcx = cx;
|
|
|
|
auto len = bcx.build.Load(lenptr);
|
2010-11-24 16:55:45 -08:00
|
|
|
if (trailing_null) {
|
2011-03-03 17:27:35 -08:00
|
|
|
auto unit_sz = size_of(bcx, elt_ty);
|
|
|
|
bcx = unit_sz.bcx;
|
2011-01-31 15:03:05 -08:00
|
|
|
len = bcx.build.Sub(len, unit_sz.val);
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
auto p1 =
|
|
|
|
vi2p(bcx, bcx.build.Add(vp2i(bcx, p0), len), T_ptr(llunit_ty));
|
2011-04-26 20:39:25 +00:00
|
|
|
ret iter_sequence_inner(bcx, p0, p1, elt_ty, f);
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
|
|
|
|
case (ty::ty_vec(?elt)) {
|
2011-03-17 17:39:47 -07:00
|
|
|
ret iter_sequence_body(cx, v, elt.ty, f, false);
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_str) {
|
|
|
|
auto et = ty::mk_mach(cx.fcx.lcx.ccx.tcx, common::ty_u8);
|
2010-12-13 17:48:33 -08:00
|
|
|
ret iter_sequence_body(cx, v, et, f, true);
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
2011-05-10 19:52:22 -07:00
|
|
|
case (_) {
|
|
|
|
cx.fcx.lcx.ccx.sess.bug("unexpected type in " +
|
2011-06-15 11:19:50 -07:00
|
|
|
"trans::iter_sequence: " +
|
|
|
|
ty_to_str(cx.fcx.lcx.ccx.tcx, t));
|
2011-05-10 19:52:22 -07:00
|
|
|
}
|
2010-11-09 17:49:20 -08:00
|
|
|
}
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
|
|
|
|
2011-05-12 15:42:12 -07:00
|
|
|
fn lazily_emit_all_tydesc_glue(&@block_ctxt cx,
|
|
|
|
&option::t[@tydesc_info] static_ti) {
|
|
|
|
lazily_emit_tydesc_glue(cx, abi::tydesc_field_take_glue, static_ti);
|
|
|
|
lazily_emit_tydesc_glue(cx, abi::tydesc_field_drop_glue, static_ti);
|
2011-05-18 17:28:08 -07:00
|
|
|
lazily_emit_tydesc_glue(cx, abi::tydesc_field_free_glue, static_ti);
|
2011-05-12 15:42:12 -07:00
|
|
|
lazily_emit_tydesc_glue(cx, abi::tydesc_field_cmp_glue, static_ti);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn lazily_emit_all_generic_info_tydesc_glues(&@block_ctxt cx,
|
|
|
|
&generic_info gi) {
|
2011-06-15 11:19:50 -07:00
|
|
|
for (option::t[@tydesc_info] ti in gi.static_tis) {
|
2011-05-12 15:42:12 -07:00
|
|
|
lazily_emit_all_tydesc_glue(cx, ti);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn lazily_emit_tydesc_glue(&@block_ctxt cx, int field,
|
|
|
|
&option::t[@tydesc_info] static_ti) {
|
|
|
|
alt (static_ti) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (none) { }
|
|
|
|
case (some(?ti)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
if (field == abi::tydesc_field_take_glue) {
|
|
|
|
alt ({ ti.take_glue }) {
|
|
|
|
case (some(_)) { }
|
2011-05-31 00:39:19 -04:00
|
|
|
case (none) {
|
2011-05-12 15:42:12 -07:00
|
|
|
log #fmt("+++ lazily_emit_tydesc_glue TAKE %s",
|
2011-06-09 09:48:16 -07:00
|
|
|
ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
|
2011-05-12 15:42:12 -07:00
|
|
|
auto lcx = cx.fcx.lcx;
|
|
|
|
auto glue_fn =
|
|
|
|
declare_generic_glue(lcx, ti.ty,
|
|
|
|
T_glue_fn(lcx.ccx.tn),
|
|
|
|
"take");
|
|
|
|
ti.take_glue = some[ValueRef](glue_fn);
|
|
|
|
auto tg = make_take_glue;
|
2011-05-18 15:35:16 -07:00
|
|
|
make_generic_glue(lcx, cx.sp, ti.ty, glue_fn,
|
2011-05-12 15:42:12 -07:00
|
|
|
mgghf_single(tg), ti.ty_params);
|
|
|
|
log #fmt("--- lazily_emit_tydesc_glue TAKE %s",
|
2011-06-09 09:48:16 -07:00
|
|
|
ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
|
2011-05-12 15:42:12 -07:00
|
|
|
}
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
} else if (field == abi::tydesc_field_drop_glue) {
|
|
|
|
alt ({ ti.drop_glue }) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(_)) { }
|
|
|
|
case (none) {
|
2011-05-12 15:42:12 -07:00
|
|
|
log #fmt("+++ lazily_emit_tydesc_glue DROP %s",
|
2011-06-09 09:48:16 -07:00
|
|
|
ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
|
2011-05-12 15:42:12 -07:00
|
|
|
auto lcx = cx.fcx.lcx;
|
|
|
|
auto glue_fn =
|
|
|
|
declare_generic_glue(lcx, ti.ty,
|
|
|
|
T_glue_fn(lcx.ccx.tn),
|
|
|
|
"drop");
|
|
|
|
ti.drop_glue = some[ValueRef](glue_fn);
|
|
|
|
auto dg = make_drop_glue;
|
2011-05-18 15:35:16 -07:00
|
|
|
make_generic_glue(lcx, cx.sp, ti.ty, glue_fn,
|
2011-05-12 15:42:12 -07:00
|
|
|
mgghf_single(dg), ti.ty_params);
|
|
|
|
log #fmt("--- lazily_emit_tydesc_glue DROP %s",
|
2011-06-09 09:48:16 -07:00
|
|
|
ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
|
2011-05-12 15:42:12 -07:00
|
|
|
}
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
} else if (field == abi::tydesc_field_free_glue) {
|
|
|
|
alt ({ ti.free_glue }) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(_)) { }
|
|
|
|
case (none) {
|
2011-05-18 17:28:08 -07:00
|
|
|
log #fmt("+++ lazily_emit_tydesc_glue FREE %s",
|
2011-06-09 09:48:16 -07:00
|
|
|
ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
|
2011-05-18 17:28:08 -07:00
|
|
|
auto lcx = cx.fcx.lcx;
|
|
|
|
auto glue_fn =
|
|
|
|
declare_generic_glue(lcx, ti.ty,
|
|
|
|
T_glue_fn(lcx.ccx.tn),
|
|
|
|
"free");
|
|
|
|
ti.free_glue = some[ValueRef](glue_fn);
|
|
|
|
auto dg = make_free_glue;
|
2011-05-18 18:01:20 -07:00
|
|
|
make_generic_glue(lcx, cx.sp, ti.ty, glue_fn,
|
2011-05-18 17:28:08 -07:00
|
|
|
mgghf_single(dg), ti.ty_params);
|
|
|
|
log #fmt("--- lazily_emit_tydesc_glue FREE %s",
|
2011-06-09 09:48:16 -07:00
|
|
|
ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
|
2011-05-18 17:28:08 -07:00
|
|
|
}
|
|
|
|
}
|
2011-05-12 15:42:12 -07:00
|
|
|
} else if (field == abi::tydesc_field_cmp_glue) {
|
2011-06-15 11:19:50 -07:00
|
|
|
alt ({ ti.cmp_glue }) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(_)) { }
|
|
|
|
case (none) {
|
2011-05-12 15:42:12 -07:00
|
|
|
log #fmt("+++ lazily_emit_tydesc_glue CMP %s",
|
2011-06-09 09:48:16 -07:00
|
|
|
ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
|
2011-05-12 15:42:12 -07:00
|
|
|
auto lcx = cx.fcx.lcx;
|
|
|
|
auto glue_fn =
|
|
|
|
declare_generic_glue(lcx, ti.ty,
|
|
|
|
T_cmp_glue_fn(lcx.ccx.tn),
|
|
|
|
"cmp");
|
|
|
|
ti.cmp_glue = some[ValueRef](glue_fn);
|
2011-05-18 15:35:16 -07:00
|
|
|
make_generic_glue(lcx, cx.sp, ti.ty, glue_fn,
|
2011-05-12 15:42:12 -07:00
|
|
|
mgghf_cmp, ti.ty_params);
|
|
|
|
log #fmt("--- lazily_emit_tydesc_glue CMP %s",
|
2011-06-09 09:48:16 -07:00
|
|
|
ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
|
2011-05-12 15:42:12 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn call_tydesc_glue_full(&@block_ctxt cx, ValueRef v, ValueRef tydesc,
|
|
|
|
int field, &option::t[@tydesc_info] static_ti) {
|
2011-05-12 15:42:12 -07:00
|
|
|
lazily_emit_tydesc_glue(cx, field, static_ti);
|
2011-01-28 14:34:25 -08:00
|
|
|
auto llrawptr = cx.build.BitCast(v, T_ptr(T_i8()));
|
2011-06-15 11:19:50 -07:00
|
|
|
auto lltydescs =
|
|
|
|
cx.build.GEP(tydesc,
|
|
|
|
[C_int(0), C_int(abi::tydesc_field_first_param)]);
|
2011-01-28 14:34:25 -08:00
|
|
|
lltydescs = cx.build.Load(lltydescs);
|
2011-05-16 18:21:22 -07:00
|
|
|
auto llfnptr = cx.build.GEP(tydesc, [C_int(0), C_int(field)]);
|
2011-01-28 14:34:25 -08:00
|
|
|
auto llfn = cx.build.Load(llfnptr);
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.build.Call(llfn,
|
|
|
|
[C_null(T_ptr(T_nil())), cx.fcx.lltaskptr,
|
|
|
|
C_null(T_ptr(T_nil())), lltydescs, llrawptr]);
|
2011-01-28 14:34:25 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn call_tydesc_glue(&@block_ctxt cx, ValueRef v, &ty::t t, int field) ->
|
|
|
|
result {
|
2011-05-12 15:42:12 -07:00
|
|
|
let option::t[@tydesc_info] ti = none[@tydesc_info];
|
2011-05-20 14:57:52 -07:00
|
|
|
auto td = get_tydesc(cx, t, false, ti);
|
2011-06-15 11:19:50 -07:00
|
|
|
call_tydesc_glue_full(td.bcx, spill_if_immediate(td.bcx, v, t), td.val,
|
|
|
|
field, ti);
|
2011-04-26 20:39:25 +00:00
|
|
|
ret res(td.bcx, C_nil());
|
2011-01-28 14:34:25 -08:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn maybe_call_dtor(&@block_ctxt cx, ValueRef v) -> @block_ctxt {
|
2011-05-16 18:21:22 -07:00
|
|
|
auto vtbl = cx.build.GEP(v, [C_int(0), C_int(abi::obj_field_vtbl)]);
|
2011-04-29 13:34:30 +02:00
|
|
|
vtbl = cx.build.Load(vtbl);
|
2011-05-16 18:21:22 -07:00
|
|
|
auto dtor_ptr = cx.build.GEP(vtbl, [C_int(0), C_int(0)]);
|
2011-04-29 13:34:30 +02:00
|
|
|
dtor_ptr = cx.build.Load(dtor_ptr);
|
2011-05-12 17:24:54 +02:00
|
|
|
auto self_t = llvm::LLVMGetElementType(val_ty(v));
|
2011-06-15 11:19:50 -07:00
|
|
|
dtor_ptr =
|
|
|
|
cx.build.BitCast(dtor_ptr,
|
|
|
|
T_ptr(T_dtor(cx.fcx.lcx.ccx, cx.sp, self_t)));
|
2011-04-29 13:34:30 +02:00
|
|
|
auto dtor_cx = new_sub_block_ctxt(cx, "dtor");
|
|
|
|
auto after_cx = new_sub_block_ctxt(cx, "after_dtor");
|
2011-06-15 11:19:50 -07:00
|
|
|
auto test =
|
|
|
|
cx.build.ICmp(lib::llvm::LLVMIntNE, dtor_ptr,
|
|
|
|
C_null(val_ty(dtor_ptr)));
|
2011-04-29 13:34:30 +02:00
|
|
|
cx.build.CondBr(test, dtor_cx.llbb, after_cx.llbb);
|
2011-05-05 02:13:39 +02:00
|
|
|
auto me = dtor_cx.build.Load(v);
|
2011-06-15 11:19:50 -07:00
|
|
|
dtor_cx.build.FastCall(dtor_ptr,
|
|
|
|
[C_null(T_ptr(T_nil())), cx.fcx.lltaskptr, me]);
|
2011-04-29 13:34:30 +02:00
|
|
|
dtor_cx.build.Br(after_cx.llbb);
|
|
|
|
ret after_cx;
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn call_cmp_glue(&@block_ctxt cx, ValueRef lhs, ValueRef rhs, &ty::t t,
|
2011-04-19 15:22:57 -07:00
|
|
|
ValueRef llop) -> result {
|
|
|
|
// We can't use call_tydesc_glue_full() and friends here because compare
|
|
|
|
// glue has a special signature.
|
|
|
|
|
|
|
|
auto lllhs = spill_if_immediate(cx, lhs, t);
|
|
|
|
auto llrhs = spill_if_immediate(cx, rhs, t);
|
|
|
|
auto llrawlhsptr = cx.build.BitCast(lllhs, T_ptr(T_i8()));
|
|
|
|
auto llrawrhsptr = cx.build.BitCast(llrhs, T_ptr(T_i8()));
|
2011-05-12 15:42:12 -07:00
|
|
|
auto ti = none[@tydesc_info];
|
|
|
|
auto r = get_tydesc(cx, t, false, ti);
|
|
|
|
lazily_emit_tydesc_glue(cx, abi::tydesc_field_cmp_glue, ti);
|
2011-04-19 15:22:57 -07:00
|
|
|
auto lltydescs =
|
2011-06-15 11:19:50 -07:00
|
|
|
r.bcx.build.GEP(r.val,
|
|
|
|
[C_int(0), C_int(abi::tydesc_field_first_param)]);
|
2011-04-19 15:22:57 -07:00
|
|
|
lltydescs = r.bcx.build.Load(lltydescs);
|
|
|
|
auto llfnptr =
|
2011-06-15 11:19:50 -07:00
|
|
|
r.bcx.build.GEP(r.val, [C_int(0), C_int(abi::tydesc_field_cmp_glue)]);
|
2011-04-19 15:22:57 -07:00
|
|
|
auto llfn = r.bcx.build.Load(llfnptr);
|
|
|
|
auto llcmpresultptr = r.bcx.build.Alloca(T_i1());
|
2011-06-15 11:19:50 -07:00
|
|
|
let vec[ValueRef] llargs =
|
|
|
|
[llcmpresultptr, r.bcx.fcx.lltaskptr, C_null(T_ptr(T_nil())),
|
|
|
|
lltydescs, llrawlhsptr, llrawrhsptr, llop];
|
2011-06-14 15:54:58 -07:00
|
|
|
r.bcx.build.Call(llfn, llargs);
|
2011-04-19 15:22:57 -07:00
|
|
|
ret res(r.bcx, r.bcx.build.Load(llcmpresultptr));
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn take_ty(&@block_ctxt cx, ValueRef v, ty::t t) -> result {
|
2011-05-20 14:50:57 -07:00
|
|
|
if (ty::type_has_pointers(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-05-20 14:57:52 -07:00
|
|
|
ret call_tydesc_glue(cx, v, t, abi::tydesc_field_take_glue);
|
2010-12-17 18:20:10 -08:00
|
|
|
}
|
2010-11-26 13:03:56 -08:00
|
|
|
ret res(cx, C_nil());
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn drop_slot(&@block_ctxt cx, ValueRef slot, &ty::t t) -> result {
|
2011-04-12 12:06:20 -07:00
|
|
|
auto llptr = load_if_immediate(cx, slot, t);
|
2010-12-17 17:21:56 -08:00
|
|
|
auto re = drop_ty(cx, llptr, t);
|
|
|
|
auto llty = val_ty(slot);
|
2011-05-12 17:24:54 +02:00
|
|
|
auto llelemty = lib::llvm::llvm::LLVMGetElementType(llty);
|
2010-12-17 17:21:56 -08:00
|
|
|
re.bcx.build.Store(C_null(llelemty), slot);
|
|
|
|
ret re;
|
2010-12-02 19:44:24 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn drop_ty(&@block_ctxt cx, ValueRef v, ty::t t) -> result {
|
2011-05-19 18:28:09 -07:00
|
|
|
if (ty::type_has_pointers(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-05-20 14:57:52 -07:00
|
|
|
ret call_tydesc_glue(cx, v, t, abi::tydesc_field_drop_glue);
|
2010-12-17 18:20:10 -08:00
|
|
|
}
|
2010-12-10 15:02:23 -08:00
|
|
|
ret res(cx, C_nil());
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn free_ty(&@block_ctxt cx, ValueRef v, ty::t t) -> result {
|
2011-05-19 18:28:09 -07:00
|
|
|
if (ty::type_has_pointers(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-05-20 14:57:52 -07:00
|
|
|
ret call_tydesc_glue(cx, v, t, abi::tydesc_field_free_glue);
|
2011-05-18 17:28:08 -07:00
|
|
|
}
|
|
|
|
ret res(cx, C_nil());
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn call_memmove(&@block_ctxt cx, ValueRef dst, ValueRef src, ValueRef n_bytes,
|
2011-05-11 04:58:46 +00:00
|
|
|
ValueRef align_bytes) -> result {
|
2011-05-10 11:50:29 -07:00
|
|
|
// FIXME: switch to the 64-bit variant when on such a platform.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-10 11:50:29 -07:00
|
|
|
auto i = cx.fcx.lcx.ccx.intrinsics;
|
2011-05-10 14:22:14 -07:00
|
|
|
assert (i.contains_key("llvm.memmove.p0i8.p0i8.i32"));
|
|
|
|
auto memmove = i.get("llvm.memmove.p0i8.p0i8.i32");
|
2010-11-24 16:55:45 -08:00
|
|
|
auto src_ptr = cx.build.PointerCast(src, T_ptr(T_i8()));
|
|
|
|
auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
|
2011-05-10 11:50:29 -07:00
|
|
|
auto size = cx.build.IntCast(n_bytes, T_i32());
|
|
|
|
auto align =
|
2011-06-15 11:19:50 -07:00
|
|
|
if (lib::llvm::llvm::LLVMIsConstant(align_bytes) == True) {
|
|
|
|
cx.build.IntCast(align_bytes, T_i32())
|
|
|
|
} else { cx.build.IntCast(C_int(0), T_i32()) };
|
2011-05-10 11:50:29 -07:00
|
|
|
auto volatile = C_bool(false);
|
2011-06-15 11:19:50 -07:00
|
|
|
ret res(cx,
|
|
|
|
cx.build.Call(memmove,
|
|
|
|
[dst_ptr, src_ptr, size, align, volatile]));
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn call_bzero(&@block_ctxt cx, ValueRef dst, ValueRef n_bytes,
|
2011-05-10 11:50:29 -07:00
|
|
|
ValueRef align_bytes) -> result {
|
|
|
|
// FIXME: switch to the 64-bit variant when on such a platform.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-10 11:50:29 -07:00
|
|
|
auto i = cx.fcx.lcx.ccx.intrinsics;
|
|
|
|
assert (i.contains_key("llvm.memset.p0i8.i32"));
|
|
|
|
auto memset = i.get("llvm.memset.p0i8.i32");
|
2011-01-18 15:38:35 -08:00
|
|
|
auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
|
2011-05-10 11:50:29 -07:00
|
|
|
auto size = cx.build.IntCast(n_bytes, T_i32());
|
|
|
|
auto align =
|
2011-06-15 11:19:50 -07:00
|
|
|
if (lib::llvm::llvm::LLVMIsConstant(align_bytes) == True) {
|
|
|
|
cx.build.IntCast(align_bytes, T_i32())
|
|
|
|
} else { cx.build.IntCast(C_int(0), T_i32()) };
|
2011-05-10 11:50:29 -07:00
|
|
|
auto volatile = C_bool(false);
|
2011-06-15 11:19:50 -07:00
|
|
|
ret res(cx,
|
|
|
|
cx.build.Call(memset,
|
|
|
|
[dst_ptr, C_u8(0u), size, align, volatile]));
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn memmove_ty(&@block_ctxt cx, ValueRef dst, ValueRef src, &ty::t t) ->
|
|
|
|
result {
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-05-10 11:50:29 -07:00
|
|
|
auto llsz = size_of(cx, t);
|
|
|
|
auto llalign = align_of(llsz.bcx, t);
|
2011-05-10 14:22:14 -07:00
|
|
|
ret call_memmove(llalign.bcx, dst, src, llsz.val, llalign.val);
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { ret res(cx, cx.build.Store(cx.build.Load(src), dst)); }
|
2011-01-17 13:30:29 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
tag copy_action { INIT; DROP_EXISTING; }
|
2011-06-10 13:39:13 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn copy_val(&@block_ctxt cx, copy_action action, ValueRef dst, ValueRef src,
|
|
|
|
&ty::t t) -> result {
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_is_scalar(cx.fcx.lcx.ccx.tcx, t) ||
|
|
|
|
ty::type_is_native(cx.fcx.lcx.ccx.tcx, t)) {
|
2010-11-24 16:55:45 -08:00
|
|
|
ret res(cx, cx.build.Store(src, dst));
|
2011-05-14 19:02:30 -07:00
|
|
|
} else if (ty::type_is_nil(cx.fcx.lcx.ccx.tcx, t) ||
|
2011-06-15 11:19:50 -07:00
|
|
|
ty::type_is_bot(cx.fcx.lcx.ccx.tcx, t)) {
|
2010-11-24 16:55:45 -08:00
|
|
|
ret res(cx, C_nil());
|
2011-05-12 17:24:54 +02:00
|
|
|
} else if (ty::type_is_boxed(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-03-31 02:07:25 -04:00
|
|
|
auto r = take_ty(cx, src, t);
|
2011-01-24 15:26:10 -08:00
|
|
|
if (action == DROP_EXISTING) {
|
2010-12-06 17:46:35 -08:00
|
|
|
r = drop_ty(r.bcx, r.bcx.build.Load(dst), t);
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
|
|
|
ret res(r.bcx, r.bcx.build.Store(src, dst));
|
2011-05-12 17:24:54 +02:00
|
|
|
} else if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, t) ||
|
2011-06-15 11:19:50 -07:00
|
|
|
ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-03-31 02:07:25 -04:00
|
|
|
auto r = take_ty(cx, src, t);
|
2011-06-15 11:19:50 -07:00
|
|
|
if (action == DROP_EXISTING) { r = drop_ty(r.bcx, dst, t); }
|
2011-05-10 14:22:14 -07:00
|
|
|
ret memmove_ty(r.bcx, dst, src, t);
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
2011-05-27 17:58:22 -07:00
|
|
|
cx.fcx.lcx.ccx.sess.bug("unexpected type in trans::copy_val: " +
|
2011-06-15 11:19:50 -07:00
|
|
|
ty_to_str(cx.fcx.lcx.ccx.tcx, t));
|
2010-11-09 17:49:20 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-31 14:36:08 -07:00
|
|
|
// This works like copy_val, except that it deinitializes the source.
|
|
|
|
// Since it needs to zero out the source, src also needs to be an lval.
|
|
|
|
// FIXME: We always zero out the source. Ideally we would detect the
|
|
|
|
// case where a variable is always deinitialized by block exit and thus
|
|
|
|
// doesn't need to be dropped.
|
2011-06-15 11:19:50 -07:00
|
|
|
fn move_val(@block_ctxt cx, copy_action action, ValueRef dst, ValueRef src,
|
2011-06-10 12:02:57 +02:00
|
|
|
&ty::t t) -> result {
|
2011-05-31 14:36:08 -07:00
|
|
|
if (ty::type_is_scalar(cx.fcx.lcx.ccx.tcx, t) ||
|
|
|
|
ty::type_is_native(cx.fcx.lcx.ccx.tcx, t)) {
|
|
|
|
ret res(cx, cx.build.Store(src, dst));
|
|
|
|
} else if (ty::type_is_nil(cx.fcx.lcx.ccx.tcx, t) ||
|
2011-06-15 11:19:50 -07:00
|
|
|
ty::type_is_bot(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-05-31 14:36:08 -07:00
|
|
|
ret res(cx, C_nil());
|
|
|
|
} else if (ty::type_is_boxed(cx.fcx.lcx.ccx.tcx, t)) {
|
|
|
|
if (action == DROP_EXISTING) {
|
|
|
|
cx = drop_ty(cx, cx.build.Load(dst), t).bcx;
|
|
|
|
}
|
|
|
|
auto r = res(cx, cx.build.Store(cx.build.Load(src), dst));
|
|
|
|
ret zero_alloca(r.bcx, src, t);
|
|
|
|
} else if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, t) ||
|
2011-06-15 11:19:50 -07:00
|
|
|
ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
|
|
|
|
if (action == DROP_EXISTING) { cx = drop_ty(cx, dst, t).bcx; }
|
2011-05-31 14:36:08 -07:00
|
|
|
auto r = memmove_ty(cx, dst, cx.build.Load(src), t);
|
|
|
|
ret zero_alloca(r.bcx, src, t);
|
|
|
|
}
|
|
|
|
cx.fcx.lcx.ccx.sess.bug("unexpected type in trans::move_val: " +
|
2011-06-15 11:19:50 -07:00
|
|
|
ty_to_str(cx.fcx.lcx.ccx.tcx, t));
|
2011-05-31 14:36:08 -07:00
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_lit(&@crate_ctxt cx, &ast::lit lit, &ast::ann ann) -> ValueRef {
|
2010-10-05 18:21:44 -07:00
|
|
|
alt (lit.node) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ast::lit_int(?i)) { ret C_int(i); }
|
|
|
|
case (ast::lit_uint(?u)) { ret C_int(u as int); }
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::lit_mach_int(?tm, ?i)) {
|
2010-11-22 17:41:26 -08:00
|
|
|
// FIXME: the entire handling of mach types falls apart
|
|
|
|
// if target int width is larger than host, at the moment;
|
|
|
|
// re-do the mach-int types using 'big' when that works.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-11-22 17:41:26 -08:00
|
|
|
auto t = T_int();
|
2011-05-07 18:54:23 +00:00
|
|
|
auto s = True;
|
2010-11-22 17:41:26 -08:00
|
|
|
alt (tm) {
|
2011-05-12 17:24:54 +02:00
|
|
|
case (common::ty_u8) { t = T_i8(); s = False; }
|
|
|
|
case (common::ty_u16) { t = T_i16(); s = False; }
|
|
|
|
case (common::ty_u32) { t = T_i32(); s = False; }
|
|
|
|
case (common::ty_u64) { t = T_i64(); s = False; }
|
|
|
|
case (common::ty_i8) { t = T_i8(); }
|
|
|
|
case (common::ty_i16) { t = T_i16(); }
|
|
|
|
case (common::ty_i32) { t = T_i32(); }
|
|
|
|
case (common::ty_i64) { t = T_i64(); }
|
2010-11-22 17:41:26 -08:00
|
|
|
}
|
2011-05-07 18:54:23 +00:00
|
|
|
ret C_integral(t, i as uint, s);
|
2010-11-22 17:41:26 -08:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ast::lit_float(?fs)) { ret C_float(fs); }
|
|
|
|
case (ast::lit_mach_float(?tm, ?s)) {
|
2011-03-22 17:25:40 -07:00
|
|
|
auto t = T_float();
|
2011-06-15 11:19:50 -07:00
|
|
|
alt (tm) {
|
|
|
|
case (common::ty_f32) { t = T_f32(); }
|
|
|
|
case (common::ty_f64) { t = T_f64(); }
|
2011-03-22 17:25:40 -07:00
|
|
|
}
|
|
|
|
ret C_floating(s, t);
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::lit_char(?c)) {
|
2011-05-07 18:54:23 +00:00
|
|
|
ret C_integral(T_char(), c as uint, False);
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ast::lit_bool(?b)) { ret C_bool(b); }
|
|
|
|
case (ast::lit_nil) { ret C_nil(); }
|
|
|
|
case (ast::lit_str(?s, _)) { ret C_str(cx, s); }
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-08 21:27:54 -07:00
|
|
|
// Converts an annotation to a type
|
2011-05-12 17:24:54 +02:00
|
|
|
fn node_ann_type(&@crate_ctxt cx, &ast::ann a) -> ty::t {
|
2011-05-19 17:21:21 -07:00
|
|
|
ret ty::ann_to_monotype(cx.tcx, a);
|
2010-11-05 18:31:02 -07:00
|
|
|
}
|
|
|
|
|
2011-05-31 18:24:06 -07:00
|
|
|
fn node_type(&@crate_ctxt cx, &span sp, &ast::ann a) -> TypeRef {
|
2011-05-18 15:35:16 -07:00
|
|
|
ret type_of(cx, sp, node_ann_type(cx, a));
|
2010-11-22 16:27:00 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_unary(&@block_ctxt cx, ast::unop op, &@ast::expr e, &ast::ann a) ->
|
|
|
|
result {
|
2010-10-04 15:55:12 -07:00
|
|
|
auto sub = trans_expr(cx, e);
|
2011-05-19 15:47:15 -07:00
|
|
|
auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
|
2010-09-28 14:01:21 -07:00
|
|
|
alt (op) {
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::not) {
|
2011-06-15 11:19:50 -07:00
|
|
|
sub =
|
|
|
|
autoderef(sub.bcx, sub.val,
|
|
|
|
ty::expr_ty(cx.fcx.lcx.ccx.tcx, e));
|
2011-03-19 15:03:21 -07:00
|
|
|
ret res(sub.bcx, sub.bcx.build.Not(sub.val));
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::neg) {
|
2011-06-15 11:19:50 -07:00
|
|
|
sub =
|
|
|
|
autoderef(sub.bcx, sub.val,
|
|
|
|
ty::expr_ty(cx.fcx.lcx.ccx.tcx, e));
|
|
|
|
if (ty::struct(cx.fcx.lcx.ccx.tcx, e_ty) == ty::ty_float) {
|
2011-03-21 16:21:54 -07:00
|
|
|
ret res(sub.bcx, sub.bcx.build.FNeg(sub.val));
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { ret res(sub.bcx, sub.bcx.build.Neg(sub.val)); }
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::box(_)) {
|
2011-05-19 15:47:15 -07:00
|
|
|
auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
|
2010-12-02 17:43:05 -08:00
|
|
|
auto e_val = sub.val;
|
2011-04-17 14:24:45 +02:00
|
|
|
auto box_ty = node_ann_type(sub.bcx.fcx.lcx.ccx, a);
|
2011-03-07 14:05:16 -08:00
|
|
|
sub = trans_malloc_boxed(sub.bcx, e_ty);
|
|
|
|
find_scope_cx(cx).cleanups +=
|
2011-05-16 18:21:22 -07:00
|
|
|
[clean(bind drop_ty(_, sub.val, box_ty))];
|
2010-12-02 17:43:05 -08:00
|
|
|
auto box = sub.val;
|
2011-06-15 11:19:50 -07:00
|
|
|
auto rc =
|
|
|
|
sub.bcx.build.GEP(box,
|
|
|
|
[C_int(0),
|
|
|
|
C_int(abi::box_rc_field_refcnt)]);
|
|
|
|
auto body =
|
|
|
|
sub.bcx.build.GEP(box,
|
|
|
|
[C_int(0), C_int(abi::box_rc_field_body)]);
|
2010-12-02 17:43:05 -08:00
|
|
|
sub.bcx.build.Store(C_int(1), rc);
|
2011-03-07 16:35:00 -08:00
|
|
|
// Cast the body type to the type of the value. This is needed to
|
|
|
|
// make tags work, since tags have a different LLVM type depending
|
|
|
|
// on whether they're boxed or not.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, e_ty)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llety =
|
|
|
|
T_ptr(type_of(sub.bcx.fcx.lcx.ccx, e.span, e_ty));
|
2011-03-07 16:35:00 -08:00
|
|
|
body = sub.bcx.build.PointerCast(body, llety);
|
|
|
|
}
|
2011-05-27 17:58:22 -07:00
|
|
|
sub = copy_val(sub.bcx, INIT, body, e_val, e_ty);
|
2010-12-02 17:43:05 -08:00
|
|
|
ret res(sub.bcx, box);
|
2010-11-05 18:31:02 -07:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::deref) {
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.fcx.lcx.ccx.sess.bug("deref expressions should have been " +
|
|
|
|
"translated using trans_lval(), not "
|
|
|
|
+ "trans_unary()");
|
2010-12-01 17:08:46 -08:00
|
|
|
}
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_compare(&@block_ctxt cx0, ast::binop op, &ty::t t0, ValueRef lhs0,
|
|
|
|
ValueRef rhs0) -> result {
|
2011-04-19 15:22:57 -07:00
|
|
|
// Autoderef both sides.
|
2011-03-09 20:14:19 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto cx = cx0;
|
2011-03-09 20:14:19 -08:00
|
|
|
auto lhs_r = autoderef(cx, lhs0, t0);
|
|
|
|
auto lhs = lhs_r.val;
|
|
|
|
cx = lhs_r.bcx;
|
|
|
|
auto rhs_r = autoderef(cx, rhs0, t0);
|
|
|
|
auto rhs = rhs_r.val;
|
|
|
|
cx = rhs_r.bcx;
|
2011-04-22 17:00:46 -07:00
|
|
|
auto t = autoderefed_ty(cx.fcx.lcx.ccx, t0);
|
2011-04-19 15:22:57 -07:00
|
|
|
// Determine the operation we need.
|
|
|
|
// FIXME: Use or-patterns when we have them.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-19 15:22:57 -07:00
|
|
|
auto llop;
|
2011-02-28 16:36:08 -08:00
|
|
|
alt (op) {
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::eq) { llop = C_u8(abi::cmp_glue_op_eq); }
|
|
|
|
case (ast::lt) { llop = C_u8(abi::cmp_glue_op_lt); }
|
|
|
|
case (ast::le) { llop = C_u8(abi::cmp_glue_op_le); }
|
|
|
|
case (ast::ne) { llop = C_u8(abi::cmp_glue_op_eq); }
|
|
|
|
case (ast::ge) { llop = C_u8(abi::cmp_glue_op_lt); }
|
|
|
|
case (ast::gt) { llop = C_u8(abi::cmp_glue_op_le); }
|
2011-02-28 16:36:08 -08:00
|
|
|
}
|
2011-04-19 15:22:57 -07:00
|
|
|
auto rslt = call_cmp_glue(cx, lhs, rhs, t, llop);
|
2011-02-28 16:36:08 -08:00
|
|
|
|
2011-04-19 15:22:57 -07:00
|
|
|
// Invert the result if necessary.
|
|
|
|
// FIXME: Use or-patterns when we have them.
|
2011-02-10 19:40:02 -08:00
|
|
|
alt (op) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ast::eq) { ret res(rslt.bcx, rslt.val); }
|
|
|
|
case (ast::lt) { ret res(rslt.bcx, rslt.val); }
|
|
|
|
case (ast::le) { ret res(rslt.bcx, rslt.val); }
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::ne) { ret res(rslt.bcx, rslt.bcx.build.Not(rslt.val)); }
|
|
|
|
case (ast::ge) { ret res(rslt.bcx, rslt.bcx.build.Not(rslt.val)); }
|
|
|
|
case (ast::gt) { ret res(rslt.bcx, rslt.bcx.build.Not(rslt.val)); }
|
2011-02-10 19:40:02 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_vec_append(&@block_ctxt cx, &ty::t t, ValueRef lhs, ValueRef rhs) ->
|
|
|
|
result {
|
2011-05-12 17:24:54 +02:00
|
|
|
auto elt_ty = ty::sequence_element_type(cx.fcx.lcx.ccx.tcx, t);
|
2011-03-03 18:18:51 -08:00
|
|
|
auto skip_null = C_bool(false);
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
|
|
|
|
case (ty::ty_str) { skip_null = C_bool(true); }
|
2011-03-03 18:18:51 -08:00
|
|
|
case (_) { }
|
|
|
|
}
|
|
|
|
auto bcx = cx;
|
2011-05-12 15:42:12 -07:00
|
|
|
auto ti = none[@tydesc_info];
|
|
|
|
auto llvec_tydesc = get_tydesc(bcx, t, false, ti);
|
2011-03-03 18:18:51 -08:00
|
|
|
bcx = llvec_tydesc.bcx;
|
2011-05-12 15:42:12 -07:00
|
|
|
ti = none[@tydesc_info];
|
|
|
|
auto llelt_tydesc = get_tydesc(bcx, elt_ty, false, ti);
|
|
|
|
lazily_emit_tydesc_glue(cx, abi::tydesc_field_take_glue, ti);
|
|
|
|
lazily_emit_tydesc_glue(cx, abi::tydesc_field_drop_glue, ti);
|
2011-05-18 17:28:08 -07:00
|
|
|
lazily_emit_tydesc_glue(cx, abi::tydesc_field_free_glue, ti);
|
2011-03-03 18:18:51 -08:00
|
|
|
bcx = llelt_tydesc.bcx;
|
2011-03-06 12:46:33 -08:00
|
|
|
auto dst = bcx.build.PointerCast(lhs, T_ptr(T_opaque_vec_ptr()));
|
|
|
|
auto src = bcx.build.PointerCast(rhs, T_opaque_vec_ptr());
|
2011-06-15 11:19:50 -07:00
|
|
|
ret res(bcx,
|
|
|
|
bcx.build.Call(cx.fcx.lcx.ccx.upcalls.vec_append,
|
|
|
|
[cx.fcx.lltaskptr, llvec_tydesc.val,
|
|
|
|
llelt_tydesc.val, dst, src, skip_null]));
|
2011-03-02 16:42:09 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-14 18:22:36 -07:00
|
|
|
// Returns a tuple consisting of a pointer to the newly-reserved space and a
|
|
|
|
// block context. Updates the length appropriately.
|
2011-06-13 18:52:04 -07:00
|
|
|
fn reserve_ivec_space(&@block_ctxt cx, TypeRef llunitty, ValueRef v,
|
2011-06-15 11:19:50 -07:00
|
|
|
ValueRef len_needed) -> result {
|
|
|
|
auto stack_len_ptr =
|
|
|
|
cx.build.InBoundsGEP(v, [C_int(0), C_uint(abi::ivec_elt_len)]);
|
2011-06-13 18:52:04 -07:00
|
|
|
auto stack_len = cx.build.Load(stack_len_ptr);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto alen =
|
|
|
|
cx.build.Load(cx.build.InBoundsGEP(v,
|
|
|
|
[C_int(0),
|
|
|
|
C_uint(abi::ivec_elt_alen)]));
|
2011-06-13 18:52:04 -07:00
|
|
|
// There are four cases we have to consider:
|
|
|
|
// (1) On heap, no resize necessary.
|
|
|
|
// (2) On heap, need to resize.
|
|
|
|
// (3) On stack, no resize necessary.
|
|
|
|
// (4) On stack, need to spill to heap.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto maybe_on_heap =
|
|
|
|
cx.build.ICmp(lib::llvm::LLVMIntEQ, stack_len, C_int(0));
|
2011-06-13 18:52:04 -07:00
|
|
|
auto maybe_on_heap_cx = new_sub_block_ctxt(cx, "maybe_on_heap");
|
|
|
|
auto on_stack_cx = new_sub_block_ctxt(cx, "on_stack");
|
|
|
|
cx.build.CondBr(maybe_on_heap, maybe_on_heap_cx.llbb, on_stack_cx.llbb);
|
|
|
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
|
|
|
// We're possibly on the heap, unless the vector is zero-length.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
auto stub_p = [C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)];
|
|
|
|
|
|
|
|
auto stub_ptr =
|
|
|
|
maybe_on_heap_cx.build.PointerCast(v, T_ptr(T_ivec_heap(llunitty)));
|
|
|
|
auto heap_ptr =
|
|
|
|
{
|
|
|
|
auto m = maybe_on_heap_cx.build.InBoundsGEP(stub_ptr, stub_p);
|
|
|
|
maybe_on_heap_cx.build.Load(m)
|
|
|
|
};
|
|
|
|
auto on_heap =
|
|
|
|
maybe_on_heap_cx.build.ICmp(lib::llvm::LLVMIntNE, heap_ptr,
|
|
|
|
C_null(val_ty(heap_ptr)));
|
2011-06-13 18:52:04 -07:00
|
|
|
auto on_heap_cx = new_sub_block_ctxt(cx, "on_heap");
|
|
|
|
maybe_on_heap_cx.build.CondBr(on_heap, on_heap_cx.llbb, on_stack_cx.llbb);
|
|
|
|
// We're definitely on the heap. Check whether we need to resize.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
auto heap_len_ptr =
|
|
|
|
on_heap_cx.build.InBoundsGEP(heap_ptr,
|
|
|
|
[C_int(0),
|
|
|
|
C_uint(abi::ivec_heap_elt_len)]);
|
2011-06-13 18:52:04 -07:00
|
|
|
auto heap_len = on_heap_cx.build.Load(heap_len_ptr);
|
|
|
|
auto new_heap_len = on_heap_cx.build.Add(heap_len, len_needed);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto heap_len_unscaled =
|
|
|
|
on_heap_cx.build.UDiv(heap_len, llsize_of(llunitty));
|
|
|
|
auto heap_no_resize_needed =
|
|
|
|
on_heap_cx.build.ICmp(lib::llvm::LLVMIntULE, new_heap_len, alen);
|
2011-06-13 18:52:04 -07:00
|
|
|
auto heap_no_resize_cx = new_sub_block_ctxt(cx, "heap_no_resize");
|
|
|
|
auto heap_resize_cx = new_sub_block_ctxt(cx, "heap_resize");
|
|
|
|
on_heap_cx.build.CondBr(heap_no_resize_needed, heap_no_resize_cx.llbb,
|
|
|
|
heap_resize_cx.llbb);
|
|
|
|
// Case (1): We're on the heap and don't need to resize.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
auto heap_data_no_resize =
|
|
|
|
heap_no_resize_cx.build.InBoundsGEP(heap_ptr,
|
|
|
|
[C_int(0),
|
|
|
|
C_uint(abi::ivec_heap_elt_elems),
|
|
|
|
heap_len_unscaled]);
|
2011-06-14 18:22:36 -07:00
|
|
|
heap_no_resize_cx.build.Store(new_heap_len, heap_len_ptr);
|
2011-06-13 18:52:04 -07:00
|
|
|
heap_no_resize_cx.build.Br(next_cx.llbb);
|
|
|
|
// Case (2): We're on the heap and need to resize. This path is rare, so
|
|
|
|
// we delegate to cold glue.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
{
|
|
|
|
auto p = heap_resize_cx.build.PointerCast(v, T_ptr(T_opaque_ivec()));
|
|
|
|
heap_resize_cx.build.Call(cx.fcx.lcx.ccx.upcalls.ivec_resize,
|
|
|
|
[cx.fcx.lltaskptr, p, new_heap_len]);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto heap_ptr_resize =
|
|
|
|
{
|
|
|
|
auto m = heap_resize_cx.build.InBoundsGEP(stub_ptr, stub_p);
|
|
|
|
heap_resize_cx.build.Load(m)
|
|
|
|
};
|
|
|
|
auto heap_data_resize =
|
|
|
|
heap_resize_cx.build.InBoundsGEP(heap_ptr_resize,
|
|
|
|
[C_int(0),
|
|
|
|
C_uint(abi::ivec_heap_elt_elems),
|
|
|
|
heap_len_unscaled]);
|
|
|
|
heap_resize_cx.build.Br(next_cx.llbb);
|
2011-06-13 18:52:04 -07:00
|
|
|
// We're on the stack. Check whether we need to spill to the heap.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-13 18:52:04 -07:00
|
|
|
auto new_stack_len = on_stack_cx.build.Add(stack_len, len_needed);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto stack_no_spill_needed =
|
|
|
|
on_stack_cx.build.ICmp(lib::llvm::LLVMIntULE, new_stack_len, alen);
|
|
|
|
auto stack_len_unscaled =
|
|
|
|
on_stack_cx.build.UDiv(stack_len, llsize_of(llunitty));
|
2011-06-13 18:52:04 -07:00
|
|
|
auto stack_no_spill_cx = new_sub_block_ctxt(cx, "stack_no_spill");
|
|
|
|
auto stack_spill_cx = new_sub_block_ctxt(cx, "stack_spill");
|
|
|
|
on_stack_cx.build.CondBr(stack_no_spill_needed, stack_no_spill_cx.llbb,
|
|
|
|
stack_spill_cx.llbb);
|
|
|
|
// Case (3): We're on the stack and don't need to spill.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
auto stack_data_no_spill =
|
|
|
|
stack_no_spill_cx.build.InBoundsGEP(v,
|
|
|
|
[C_int(0),
|
|
|
|
C_uint(abi::ivec_elt_elems),
|
|
|
|
stack_len_unscaled]);
|
2011-06-14 18:22:36 -07:00
|
|
|
stack_no_spill_cx.build.Store(new_stack_len, stack_len_ptr);
|
2011-06-13 18:52:04 -07:00
|
|
|
stack_no_spill_cx.build.Br(next_cx.llbb);
|
|
|
|
// Case (4): We're on the stack and need to spill. Like case (2), this
|
|
|
|
// path is rare, so we delegate to cold glue.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
{
|
|
|
|
auto p = stack_spill_cx.build.PointerCast(v, T_ptr(T_opaque_ivec()));
|
|
|
|
stack_spill_cx.build.Call(cx.fcx.lcx.ccx.upcalls.ivec_spill,
|
|
|
|
[cx.fcx.lltaskptr, p, new_stack_len]);
|
|
|
|
}
|
|
|
|
auto spill_stub =
|
|
|
|
stack_spill_cx.build.PointerCast(v, T_ptr(T_ivec_heap(llunitty)));
|
|
|
|
auto heap_ptr_spill =
|
|
|
|
stack_spill_cx.build.Load(stack_spill_cx.build.InBoundsGEP(spill_stub,
|
|
|
|
stub_p));
|
|
|
|
auto heap_len_ptr_spill =
|
|
|
|
stack_spill_cx.build.InBoundsGEP(heap_ptr_spill,
|
|
|
|
[C_int(0),
|
|
|
|
C_uint(abi::ivec_heap_elt_len)]);
|
|
|
|
auto heap_data_spill =
|
|
|
|
stack_spill_cx.build.InBoundsGEP(heap_ptr_spill,
|
|
|
|
[C_int(0),
|
|
|
|
C_uint(abi::ivec_heap_elt_elems),
|
|
|
|
stack_len_unscaled]);
|
2011-06-13 18:52:04 -07:00
|
|
|
stack_spill_cx.build.Br(next_cx.llbb);
|
|
|
|
// Phi together the different data pointers to get the result.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
auto data_ptr =
|
|
|
|
next_cx.build.Phi(T_ptr(llunitty),
|
|
|
|
[heap_data_no_resize, heap_data_resize,
|
|
|
|
stack_data_no_spill, heap_data_spill],
|
|
|
|
[heap_no_resize_cx.llbb, heap_resize_cx.llbb,
|
|
|
|
stack_no_spill_cx.llbb, stack_spill_cx.llbb]);
|
2011-06-14 18:22:36 -07:00
|
|
|
ret res(next_cx, data_ptr);
|
2011-06-13 18:52:04 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_ivec_append(&@block_ctxt cx, &ty::t t, ValueRef lhs, ValueRef rhs) ->
|
|
|
|
result {
|
2011-06-13 18:52:04 -07:00
|
|
|
auto unit_ty = ty::sequence_element_type(cx.fcx.lcx.ccx.tcx, t);
|
|
|
|
auto llunitty = type_of_or_i8(cx, unit_ty);
|
|
|
|
auto skip_null;
|
|
|
|
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
|
|
|
|
case (ty::ty_istr) { skip_null = true; }
|
|
|
|
case (ty::ty_ivec(_)) { skip_null = false; }
|
|
|
|
case (_) {
|
|
|
|
cx.fcx.lcx.ccx.tcx.sess.bug("non-istr/ivec in trans_ivec_append");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Gather the various type descriptors we'll need.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-13 18:52:04 -07:00
|
|
|
auto rslt = get_tydesc(cx, t, false, none);
|
|
|
|
auto vec_tydesc = rslt.val;
|
|
|
|
auto bcx = rslt.bcx;
|
|
|
|
rslt = get_tydesc(bcx, unit_ty, false, none);
|
|
|
|
auto unit_tydesc = rslt.val;
|
|
|
|
bcx = rslt.bcx;
|
|
|
|
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_take_glue, none);
|
|
|
|
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, none);
|
|
|
|
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, none);
|
|
|
|
auto rhs_len_and_data = get_ivec_len_and_data(bcx, rhs, unit_ty);
|
|
|
|
auto rhs_len = rhs_len_and_data._0;
|
|
|
|
auto rhs_data = rhs_len_and_data._1;
|
|
|
|
bcx = rhs_len_and_data._2;
|
2011-06-14 18:22:36 -07:00
|
|
|
rslt = reserve_ivec_space(bcx, llunitty, lhs, rhs_len);
|
|
|
|
auto lhs_data = rslt.val;
|
|
|
|
bcx = rslt.bcx;
|
2011-06-13 18:52:04 -07:00
|
|
|
// Work out the end pointer.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-13 18:52:04 -07:00
|
|
|
auto lhs_unscaled_idx = bcx.build.UDiv(rhs_len, llsize_of(llunitty));
|
|
|
|
auto lhs_end = bcx.build.InBoundsGEP(lhs_data, [lhs_unscaled_idx]);
|
|
|
|
// Now emit the copy loop.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-13 18:52:04 -07:00
|
|
|
auto dest_ptr = alloca(bcx, T_ptr(llunitty));
|
|
|
|
bcx.build.Store(lhs_data, dest_ptr);
|
|
|
|
auto src_ptr = alloca(bcx, T_ptr(llunitty));
|
|
|
|
bcx.build.Store(rhs_data, src_ptr);
|
|
|
|
auto copy_loop_header_cx = new_sub_block_ctxt(bcx, "copy_loop_header");
|
|
|
|
bcx.build.Br(copy_loop_header_cx.llbb);
|
|
|
|
auto copy_dest_ptr = copy_loop_header_cx.build.Load(dest_ptr);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto not_yet_at_end =
|
|
|
|
copy_loop_header_cx.build.ICmp(lib::llvm::LLVMIntNE, copy_dest_ptr,
|
|
|
|
lhs_end);
|
2011-06-13 18:52:04 -07:00
|
|
|
auto copy_loop_body_cx = new_sub_block_ctxt(bcx, "copy_loop_body");
|
|
|
|
auto next_cx = new_sub_block_ctxt(bcx, "next");
|
|
|
|
copy_loop_header_cx.build.CondBr(not_yet_at_end, copy_loop_body_cx.llbb,
|
|
|
|
next_cx.llbb);
|
|
|
|
auto copy_src_ptr = copy_loop_body_cx.build.Load(src_ptr);
|
|
|
|
rslt = copy_val(copy_loop_body_cx, INIT, copy_dest_ptr, copy_src_ptr, t);
|
|
|
|
auto post_copy_cx = rslt.bcx;
|
|
|
|
// Increment both pointers.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-13 18:52:04 -07:00
|
|
|
post_copy_cx.build.Store(post_copy_cx.build.InBoundsGEP(copy_dest_ptr,
|
2011-06-15 11:19:50 -07:00
|
|
|
[C_int(1)]),
|
|
|
|
dest_ptr);
|
2011-06-13 18:52:04 -07:00
|
|
|
post_copy_cx.build.Store(post_copy_cx.build.InBoundsGEP(copy_src_ptr,
|
2011-06-15 11:19:50 -07:00
|
|
|
[C_int(1)]),
|
|
|
|
src_ptr);
|
2011-06-13 18:52:04 -07:00
|
|
|
post_copy_cx.build.Br(copy_loop_header_cx.llbb);
|
|
|
|
ret res(next_cx, C_nil());
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_vec_add(&@block_ctxt cx, &ty::t t, ValueRef lhs, ValueRef rhs) ->
|
|
|
|
result {
|
2011-03-02 16:42:09 -08:00
|
|
|
auto r = alloc_ty(cx, t);
|
2011-03-06 12:46:33 -08:00
|
|
|
auto tmp = r.val;
|
2011-05-27 17:58:22 -07:00
|
|
|
r = copy_val(r.bcx, INIT, tmp, lhs, t);
|
2011-03-06 15:12:33 -08:00
|
|
|
auto bcx = trans_vec_append(r.bcx, t, tmp, rhs).bcx;
|
2011-04-12 12:06:20 -07:00
|
|
|
tmp = load_if_immediate(bcx, tmp, t);
|
2011-06-15 11:19:50 -07:00
|
|
|
find_scope_cx(cx).cleanups += [clean(bind drop_ty(_, tmp, t))];
|
2011-03-07 00:13:56 -08:00
|
|
|
ret res(bcx, tmp);
|
2011-03-02 16:42:09 -08:00
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_eager_binop(&@block_ctxt cx, ast::binop op, &ty::t intype,
|
2011-02-28 16:36:08 -08:00
|
|
|
ValueRef lhs, ValueRef rhs) -> result {
|
2011-03-21 16:21:54 -07:00
|
|
|
auto is_float = false;
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(cx.fcx.lcx.ccx.tcx, intype)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_float) { is_float = true; }
|
|
|
|
case (_) { is_float = false; }
|
2011-03-21 16:21:54 -07:00
|
|
|
}
|
2010-12-08 14:50:47 -08:00
|
|
|
alt (op) {
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::add) {
|
|
|
|
if (ty::type_is_sequence(cx.fcx.lcx.ccx.tcx, intype)) {
|
2011-03-03 18:18:51 -08:00
|
|
|
ret trans_vec_add(cx, intype, lhs, rhs);
|
2011-03-02 16:42:09 -08:00
|
|
|
}
|
2011-03-21 16:21:54 -07:00
|
|
|
if (is_float) {
|
|
|
|
ret res(cx, cx.build.FAdd(lhs, rhs));
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { ret res(cx, cx.build.Add(lhs, rhs)); }
|
2011-03-21 16:21:54 -07:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::sub) {
|
2011-03-21 16:21:54 -07:00
|
|
|
if (is_float) {
|
|
|
|
ret res(cx, cx.build.FSub(lhs, rhs));
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { ret res(cx, cx.build.Sub(lhs, rhs)); }
|
2011-03-21 16:21:54 -07:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::mul) {
|
2011-03-21 16:21:54 -07:00
|
|
|
if (is_float) {
|
|
|
|
ret res(cx, cx.build.FMul(lhs, rhs));
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { ret res(cx, cx.build.Mul(lhs, rhs)); }
|
2011-03-02 16:42:09 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::div) {
|
2011-06-15 11:19:50 -07:00
|
|
|
if (is_float) { ret res(cx, cx.build.FDiv(lhs, rhs)); }
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_is_signed(cx.fcx.lcx.ccx.tcx, intype)) {
|
2011-02-28 16:36:08 -08:00
|
|
|
ret res(cx, cx.build.SDiv(lhs, rhs));
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { ret res(cx, cx.build.UDiv(lhs, rhs)); }
|
2011-02-13 00:49:04 -05:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::rem) {
|
2011-06-15 11:19:50 -07:00
|
|
|
if (is_float) { ret res(cx, cx.build.FRem(lhs, rhs)); }
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_is_signed(cx.fcx.lcx.ccx.tcx, intype)) {
|
2011-02-28 16:36:08 -08:00
|
|
|
ret res(cx, cx.build.SRem(lhs, rhs));
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { ret res(cx, cx.build.URem(lhs, rhs)); }
|
2011-02-13 00:49:04 -05:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::bitor) { ret res(cx, cx.build.Or(lhs, rhs)); }
|
|
|
|
case (ast::bitand) { ret res(cx, cx.build.And(lhs, rhs)); }
|
|
|
|
case (ast::bitxor) { ret res(cx, cx.build.Xor(lhs, rhs)); }
|
|
|
|
case (ast::lsl) { ret res(cx, cx.build.Shl(lhs, rhs)); }
|
|
|
|
case (ast::lsr) { ret res(cx, cx.build.LShr(lhs, rhs)); }
|
|
|
|
case (ast::asr) { ret res(cx, cx.build.AShr(lhs, rhs)); }
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { ret trans_compare(cx, op, intype, lhs, rhs); }
|
2010-12-08 14:50:47 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn autoderef(&@block_ctxt cx, ValueRef v, &ty::t t) -> result {
|
2011-01-24 18:03:31 -08:00
|
|
|
let ValueRef v1 = v;
|
2011-05-12 17:24:54 +02:00
|
|
|
let ty::t t1 = t;
|
2011-01-24 18:03:31 -08:00
|
|
|
while (true) {
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t1)) {
|
|
|
|
case (ty::ty_box(?mt)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto body =
|
|
|
|
cx.build.GEP(v1,
|
|
|
|
[C_int(0), C_int(abi::box_rc_field_body)]);
|
2011-03-17 17:39:47 -07:00
|
|
|
t1 = mt.ty;
|
2011-04-07 15:09:45 -07:00
|
|
|
// Since we're changing levels of box indirection, we may have
|
|
|
|
// to cast this pointer, since statically-sized tag types have
|
|
|
|
// different types depending on whether they're behind a box
|
|
|
|
// or not.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, mt.ty)) {
|
2011-05-18 15:35:16 -07:00
|
|
|
auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, mt.ty);
|
2011-04-07 15:09:45 -07:00
|
|
|
v1 = cx.build.PointerCast(body, T_ptr(llty));
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { v1 = body; }
|
2011-04-12 12:06:20 -07:00
|
|
|
v1 = load_if_immediate(cx, v1, t1);
|
2011-01-24 18:03:31 -08:00
|
|
|
}
|
2011-06-07 13:50:30 -07:00
|
|
|
case (_) { break; }
|
2011-01-24 18:03:31 -08:00
|
|
|
}
|
|
|
|
}
|
2011-06-07 13:50:30 -07:00
|
|
|
ret res(cx, v1);
|
2011-01-24 18:03:31 -08:00
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn autoderefed_ty(&@crate_ctxt ccx, &ty::t t) -> ty::t {
|
|
|
|
let ty::t t1 = t;
|
2011-02-28 16:36:08 -08:00
|
|
|
while (true) {
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(ccx.tcx, t1)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_box(?mt)) { t1 = mt.ty; }
|
2011-06-07 13:50:30 -07:00
|
|
|
case (_) { break; }
|
2011-02-28 16:36:08 -08:00
|
|
|
}
|
|
|
|
}
|
2011-06-07 13:50:30 -07:00
|
|
|
ret t1;
|
2011-02-28 16:36:08 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_binary(&@block_ctxt cx, ast::binop op, &@ast::expr a, &@ast::expr b)
|
|
|
|
-> result {
|
2010-10-04 15:55:12 -07:00
|
|
|
|
2010-10-19 17:24:15 -07:00
|
|
|
// First couple cases are lazy:
|
|
|
|
alt (op) {
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::and) {
|
2010-10-19 17:24:15 -07:00
|
|
|
// Lazy-eval and
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto lhs_res = trans_expr(cx, a);
|
|
|
|
lhs_res =
|
|
|
|
autoderef(lhs_res.bcx, lhs_res.val,
|
|
|
|
ty::expr_ty(cx.fcx.lcx.ccx.tcx, a));
|
2010-12-10 15:26:47 -08:00
|
|
|
auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
|
2010-10-19 17:24:15 -07:00
|
|
|
auto rhs_res = trans_expr(rhs_cx, b);
|
2011-06-15 11:19:50 -07:00
|
|
|
rhs_res =
|
|
|
|
autoderef(rhs_res.bcx, rhs_res.val,
|
|
|
|
ty::expr_ty(cx.fcx.lcx.ccx.tcx, b));
|
2010-12-10 15:26:47 -08:00
|
|
|
auto lhs_false_cx = new_scope_block_ctxt(cx, "lhs false");
|
2010-11-12 14:51:11 -08:00
|
|
|
auto lhs_false_res = res(lhs_false_cx, C_bool(false));
|
2011-05-14 19:02:30 -07:00
|
|
|
// The following line ensures that any cleanups for rhs
|
2011-05-16 19:04:45 -07:00
|
|
|
// are done within the block for rhs. This is necessary
|
2011-05-14 19:02:30 -07:00
|
|
|
// because and/or are lazy. So the rhs may never execute,
|
|
|
|
// and the cleanups can't be pushed into later code.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto rhs_bcx = trans_block_cleanups(rhs_res.bcx, rhs_cx);
|
|
|
|
lhs_res.bcx.build.CondBr(lhs_res.val, rhs_cx.llbb,
|
2010-11-12 14:51:11 -08:00
|
|
|
lhs_false_cx.llbb);
|
|
|
|
ret join_results(cx, T_bool(),
|
2011-05-16 19:04:45 -07:00
|
|
|
[lhs_false_res, rec(bcx=rhs_bcx with rhs_res)]);
|
2010-10-19 17:24:15 -07:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::or) {
|
2010-10-19 17:24:15 -07:00
|
|
|
// Lazy-eval or
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto lhs_res = trans_expr(cx, a);
|
|
|
|
lhs_res =
|
|
|
|
autoderef(lhs_res.bcx, lhs_res.val,
|
|
|
|
ty::expr_ty(cx.fcx.lcx.ccx.tcx, a));
|
2010-12-10 15:26:47 -08:00
|
|
|
auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
|
2010-10-19 17:24:15 -07:00
|
|
|
auto rhs_res = trans_expr(rhs_cx, b);
|
2011-06-15 11:19:50 -07:00
|
|
|
rhs_res =
|
|
|
|
autoderef(rhs_res.bcx, rhs_res.val,
|
|
|
|
ty::expr_ty(cx.fcx.lcx.ccx.tcx, b));
|
2010-12-10 15:26:47 -08:00
|
|
|
auto lhs_true_cx = new_scope_block_ctxt(cx, "lhs true");
|
2010-11-12 14:51:11 -08:00
|
|
|
auto lhs_true_res = res(lhs_true_cx, C_bool(true));
|
2011-05-14 19:02:30 -07:00
|
|
|
// see the and case for an explanation
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto rhs_bcx = trans_block_cleanups(rhs_res.bcx, rhs_cx);
|
|
|
|
lhs_res.bcx.build.CondBr(lhs_res.val, lhs_true_cx.llbb,
|
2010-10-19 17:24:15 -07:00
|
|
|
rhs_cx.llbb);
|
2010-11-12 14:51:11 -08:00
|
|
|
ret join_results(cx, T_bool(),
|
2011-05-16 19:04:45 -07:00
|
|
|
[lhs_true_res, rec(bcx=rhs_bcx with rhs_res)]);
|
2010-10-19 17:24:15 -07:00
|
|
|
}
|
2010-12-01 17:08:46 -08:00
|
|
|
case (_) {
|
2010-12-08 14:50:47 -08:00
|
|
|
// Remaining cases are eager:
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-12-08 14:50:47 -08:00
|
|
|
auto lhs = trans_expr(cx, a);
|
2011-05-19 15:47:15 -07:00
|
|
|
auto lhty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, a);
|
2011-02-13 00:49:04 -05:00
|
|
|
lhs = autoderef(lhs.bcx, lhs.val, lhty);
|
2011-01-24 18:03:31 -08:00
|
|
|
auto rhs = trans_expr(lhs.bcx, b);
|
2011-05-19 15:47:15 -07:00
|
|
|
auto rhty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, b);
|
2011-02-13 00:49:04 -05:00
|
|
|
rhs = autoderef(rhs.bcx, rhs.val, rhty);
|
2011-02-28 16:36:08 -08:00
|
|
|
ret trans_eager_binop(rhs.bcx, op,
|
2011-06-15 11:19:50 -07:00
|
|
|
autoderefed_ty(cx.fcx.lcx.ccx, lhty),
|
|
|
|
lhs.val, rhs.val);
|
2010-12-01 17:08:46 -08:00
|
|
|
}
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn join_results(&@block_ctxt parent_cx, TypeRef t, &vec[result] ins) ->
|
|
|
|
result {
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[result] live = [];
|
|
|
|
let vec[ValueRef] vals = [];
|
|
|
|
let vec[BasicBlockRef] bbs = [];
|
2010-11-12 14:51:11 -08:00
|
|
|
for (result r in ins) {
|
2011-06-15 11:19:50 -07:00
|
|
|
if (!is_terminated(r.bcx)) {
|
2011-05-16 18:21:22 -07:00
|
|
|
live += [r];
|
|
|
|
vals += [r.val];
|
|
|
|
bbs += [r.bcx.llbb];
|
2010-11-12 14:51:11 -08:00
|
|
|
}
|
|
|
|
}
|
2011-05-17 20:41:41 +02:00
|
|
|
alt (vec::len[result](live)) {
|
2010-11-12 14:51:11 -08:00
|
|
|
case (0u) {
|
|
|
|
// No incoming edges are live, so we're in dead-code-land.
|
|
|
|
// Arbitrarily pick the first dead edge, since the caller
|
|
|
|
// is just going to propagate it outward.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-17 20:41:41 +02:00
|
|
|
assert (vec::len[result](ins) >= 1u);
|
2010-11-12 14:51:11 -08:00
|
|
|
ret ins.(0);
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) {/* fall through */ }
|
2010-11-12 14:51:11 -08:00
|
|
|
}
|
|
|
|
// We have >1 incoming edges. Make a join block and br+phi them into it.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-11-12 14:51:11 -08:00
|
|
|
auto join_cx = new_sub_block_ctxt(parent_cx, "join");
|
2011-06-15 11:19:50 -07:00
|
|
|
for (result r in live) { r.bcx.build.Br(join_cx.llbb); }
|
2010-11-12 14:51:11 -08:00
|
|
|
auto phi = join_cx.build.Phi(t, vals, bbs);
|
|
|
|
ret res(join_cx, phi);
|
|
|
|
}
|
|
|
|
|
2011-05-31 14:24:04 +02:00
|
|
|
fn join_branches(&@block_ctxt parent_cx, &vec[result] ins) -> @block_ctxt {
|
|
|
|
auto out = new_sub_block_ctxt(parent_cx, "join");
|
|
|
|
for (result r in ins) {
|
2011-06-15 11:19:50 -07:00
|
|
|
if (!is_terminated(r.bcx)) { r.bcx.build.Br(out.llbb); }
|
2011-05-31 14:24:04 +02:00
|
|
|
}
|
|
|
|
ret out;
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
tag out_method { return; save_in(ValueRef); }
|
2011-05-31 14:24:04 +02:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_if(&@block_ctxt cx, &@ast::expr cond, &ast::block thn,
|
|
|
|
&option::t[@ast::expr] els, &ast::ann ann, &out_method output) ->
|
|
|
|
result {
|
2010-10-04 15:55:12 -07:00
|
|
|
auto cond_res = trans_expr(cx, cond);
|
2010-12-02 19:12:34 -08:00
|
|
|
auto then_cx = new_scope_block_ctxt(cx, "then");
|
2011-05-31 14:24:04 +02:00
|
|
|
auto then_res = trans_block(then_cx, thn, output);
|
2010-12-02 19:12:34 -08:00
|
|
|
auto else_cx = new_scope_block_ctxt(cx, "else");
|
2011-03-27 16:29:21 -04:00
|
|
|
auto else_res;
|
|
|
|
auto expr_llty;
|
2010-10-04 15:55:12 -07:00
|
|
|
alt (els) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(?elexpr)) {
|
2011-03-31 00:46:26 -04:00
|
|
|
alt (elexpr.node) {
|
2011-05-19 20:26:42 -04:00
|
|
|
case (ast::expr_if(_, _, _, ?ann)) {
|
|
|
|
// Synthesize a block here to act as the else block
|
|
|
|
// containing an if expression. Needed in order for the
|
|
|
|
// else scope to behave like a normal block scope. A tad
|
|
|
|
// ugly.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
let ast::block_ elseif_blk_ =
|
|
|
|
rec(stmts=[], expr=some[@ast::expr](elexpr), a=ann);
|
|
|
|
auto elseif_blk = rec(node=elseif_blk_, span=elexpr.span);
|
2011-05-31 14:24:04 +02:00
|
|
|
else_res = trans_block(else_cx, elseif_blk, output);
|
2011-03-31 00:46:26 -04:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_block(?blk, _)) {
|
2011-03-31 00:46:26 -04:00
|
|
|
// Calling trans_block directly instead of trans_expr
|
|
|
|
// because trans_expr will create another scope block
|
|
|
|
// context for the block, but we've already got the
|
|
|
|
// 'else' context
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-31 14:24:04 +02:00
|
|
|
else_res = trans_block(else_cx, blk, output);
|
2011-03-31 00:46:26 -04:00
|
|
|
}
|
|
|
|
}
|
2011-04-02 19:12:00 -04:00
|
|
|
// FIXME: This isn't quite right, particularly re: dynamic types
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
auto expr_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann);
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, expr_ty)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
expr_llty = T_typaram_ptr(cx.fcx.lcx.ccx.tn);
|
2011-03-27 20:20:12 -04:00
|
|
|
} else {
|
2011-05-21 14:07:44 -04:00
|
|
|
expr_llty = type_of(cx.fcx.lcx.ccx, elexpr.span, expr_ty);
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, expr_ty)) {
|
2011-03-27 20:20:12 -04:00
|
|
|
expr_llty = T_ptr(expr_llty);
|
|
|
|
}
|
2011-03-27 18:51:25 -04:00
|
|
|
}
|
2011-03-27 16:29:21 -04:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { else_res = res(else_cx, C_nil()); expr_llty = T_nil(); }
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
cond_res.bcx.build.CondBr(cond_res.val, then_cx.llbb, else_cx.llbb);
|
2011-05-31 14:24:04 +02:00
|
|
|
ret res(join_branches(cx, [then_res, else_res]), C_nil());
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_for(&@block_ctxt cx, &@ast::local local, &@ast::expr seq,
|
2011-05-12 17:24:54 +02:00
|
|
|
&ast::block body) -> result {
|
2011-06-15 11:19:50 -07:00
|
|
|
fn inner(&@block_ctxt cx, @ast::local_ local, ValueRef curr, ty::t t,
|
|
|
|
ast::block body, @block_ctxt outer_next_cx) -> result {
|
2011-01-21 07:59:06 -08:00
|
|
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
2011-03-25 16:28:16 +01:00
|
|
|
auto scope_cx =
|
2011-05-12 17:24:54 +02:00
|
|
|
new_loop_scope_block_ctxt(cx, option::some[@block_ctxt](next_cx),
|
2011-03-25 16:28:16 +01:00
|
|
|
outer_next_cx, "for loop scope");
|
2011-01-21 07:59:06 -08:00
|
|
|
cx.build.Br(scope_cx.llbb);
|
|
|
|
auto local_res = alloc_local(scope_cx, local);
|
2011-05-27 17:58:22 -07:00
|
|
|
auto bcx = copy_val(local_res.bcx, INIT, local_res.val, curr, t).bcx;
|
2011-06-15 11:19:50 -07:00
|
|
|
scope_cx.cleanups += [clean(bind drop_slot(_, local_res.val, t))];
|
2011-05-31 14:24:04 +02:00
|
|
|
bcx = trans_block(bcx, body, return).bcx;
|
2011-01-21 07:59:06 -08:00
|
|
|
bcx.build.Br(next_cx.llbb);
|
|
|
|
ret res(next_cx, C_nil());
|
|
|
|
}
|
2011-03-25 16:28:16 +01:00
|
|
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
2011-05-19 15:47:15 -07:00
|
|
|
auto seq_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, seq);
|
2011-01-21 07:59:06 -08:00
|
|
|
auto seq_res = trans_expr(cx, seq);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto it =
|
|
|
|
iter_sequence(seq_res.bcx, seq_res.val, seq_ty,
|
|
|
|
bind inner(_, local.node, _, _, body, next_cx));
|
2011-03-25 16:28:16 +01:00
|
|
|
it.bcx.build.Br(next_cx.llbb);
|
|
|
|
ret res(next_cx, it.val);
|
2011-01-21 07:59:06 -08:00
|
|
|
}
|
|
|
|
|
2011-03-10 16:49:00 -08:00
|
|
|
|
|
|
|
// Iterator translation
|
|
|
|
|
|
|
|
// Searches through a block for all references to locals or upvars in this
|
|
|
|
// frame and returns the list of definition IDs thus found.
|
2011-05-12 17:24:54 +02:00
|
|
|
fn collect_upvars(&@block_ctxt cx, &ast::block bloc,
|
|
|
|
&ast::def_id initial_decl) -> vec[ast::def_id] {
|
2011-06-15 11:19:50 -07:00
|
|
|
type env =
|
|
|
|
@rec(mutable vec[ast::def_id] refs,
|
|
|
|
hashmap[ast::def_id, ()] decls,
|
|
|
|
resolve::def_map def_map);
|
2011-03-10 16:49:00 -08:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn walk_expr(env e, &@ast::expr expr) {
|
2011-04-20 12:35:07 +02:00
|
|
|
alt (expr.node) {
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_path(?path, ?ann)) {
|
2011-05-17 11:30:11 -07:00
|
|
|
alt (e.def_map.get(ann.id)) {
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::def_arg(?did)) {
|
2011-05-17 20:41:41 +02:00
|
|
|
vec::push[ast::def_id](e.refs, did);
|
2011-04-20 12:35:07 +02:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::def_local(?did)) {
|
2011-05-17 20:41:41 +02:00
|
|
|
vec::push[ast::def_id](e.refs, did);
|
2011-04-20 12:35:07 +02:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { }
|
2011-04-20 12:35:07 +02:00
|
|
|
}
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { }
|
2011-03-10 16:49:00 -08:00
|
|
|
}
|
|
|
|
}
|
2011-06-13 17:04:15 -07:00
|
|
|
fn walk_local(env e, &@ast::local local) {
|
|
|
|
e.decls.insert(local.node.id, ());
|
2011-03-10 16:49:00 -08:00
|
|
|
}
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ast::def_id] refs = [];
|
2011-06-15 11:19:50 -07:00
|
|
|
let hashmap[ast::def_id, ()] decls = new_def_hash[()]();
|
2011-03-10 16:49:00 -08:00
|
|
|
decls.insert(initial_decl, ());
|
2011-06-15 11:19:50 -07:00
|
|
|
let env e =
|
|
|
|
@rec(mutable refs=refs,
|
|
|
|
decls=decls,
|
|
|
|
def_map=cx.fcx.lcx.ccx.tcx.def_map);
|
|
|
|
auto visitor =
|
|
|
|
@rec(visit_local_pre=bind walk_local(e, _),
|
|
|
|
visit_expr_pre=bind walk_expr(e, _)
|
|
|
|
with walk::default_visitor());
|
2011-05-12 17:24:54 +02:00
|
|
|
walk::walk_block(*visitor, bloc);
|
2011-03-10 16:49:00 -08:00
|
|
|
// Calculate (refs - decls). This is the set of captured upvars.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ast::def_id] result = [];
|
2011-06-10 16:39:09 +02:00
|
|
|
for (ast::def_id ref_id_ in e.refs) {
|
|
|
|
auto ref_id = ref_id_;
|
2011-06-15 11:19:50 -07:00
|
|
|
if (!decls.contains_key(ref_id)) { result += [ref_id]; }
|
2011-03-10 16:49:00 -08:00
|
|
|
}
|
|
|
|
ret result;
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_for_each(&@block_ctxt cx, &@ast::local local, &@ast::expr seq,
|
2011-05-12 17:24:54 +02:00
|
|
|
&ast::block body) -> result {
|
2011-02-17 12:20:55 -08:00
|
|
|
/*
|
|
|
|
* The translation is a little .. complex here. Code like:
|
|
|
|
*
|
|
|
|
* let ty1 p = ...;
|
|
|
|
*
|
|
|
|
* let ty1 q = ...;
|
|
|
|
*
|
|
|
|
* foreach (ty v in foo(a,b)) { body(p,q,v) }
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Turns into a something like so (C/Rust mishmash):
|
|
|
|
*
|
|
|
|
* type env = { *ty1 p, *ty2 q, ... };
|
|
|
|
*
|
|
|
|
* let env e = { &p, &q, ... };
|
|
|
|
*
|
|
|
|
* fn foreach123_body(env* e, ty v) { body(*(e->p),*(e->q),v) }
|
|
|
|
*
|
|
|
|
* foo([foreach123_body, env*], a, b);
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Step 1: walk body and figure out which references it makes
|
|
|
|
// escape. This could be determined upstream, and probably ought
|
|
|
|
// to be so, eventualy. For first cut, skip this. Null env.
|
|
|
|
|
2011-04-20 17:23:45 +02:00
|
|
|
auto lcx = cx.fcx.lcx;
|
2011-02-17 12:20:55 -08:00
|
|
|
// FIXME: possibly support alias-mode here?
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-13 17:04:15 -07:00
|
|
|
auto decl_ty = node_ann_type(lcx.ccx, local.node.ann);
|
|
|
|
auto decl_id = local.node.id;
|
2011-03-10 16:49:00 -08:00
|
|
|
auto upvars = collect_upvars(cx, body, decl_id);
|
2011-05-17 20:41:41 +02:00
|
|
|
auto upvar_count = vec::len[ast::def_id](upvars);
|
2011-03-11 12:02:51 -08:00
|
|
|
auto llbindingsptr;
|
|
|
|
if (upvar_count > 0u) {
|
|
|
|
// Gather up the upvars.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ValueRef] llbindings = [];
|
|
|
|
let vec[TypeRef] llbindingtys = [];
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ast::def_id did in upvars) {
|
2011-03-11 12:02:51 -08:00
|
|
|
auto llbinding;
|
|
|
|
alt (cx.fcx.lllocals.find(did)) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (none) {
|
2011-03-19 14:26:12 -07:00
|
|
|
alt (cx.fcx.llupvars.find(did)) {
|
|
|
|
case (none[ValueRef]) {
|
|
|
|
llbinding = cx.fcx.llargs.get(did);
|
|
|
|
}
|
|
|
|
case (some[ValueRef](?llval)) { llbinding = llval; }
|
|
|
|
}
|
2011-03-11 12:02:51 -08:00
|
|
|
}
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(?llval)) { llbinding = llval; }
|
2011-03-11 12:02:51 -08:00
|
|
|
}
|
2011-05-16 18:21:22 -07:00
|
|
|
llbindings += [llbinding];
|
|
|
|
llbindingtys += [val_ty(llbinding)];
|
2011-03-11 12:02:51 -08:00
|
|
|
}
|
|
|
|
// Create an array of bindings and copy in aliases to the upvars.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-28 18:04:52 -07:00
|
|
|
llbindingsptr = alloca(cx, T_struct(llbindingtys));
|
2011-03-11 12:02:51 -08:00
|
|
|
auto i = 0u;
|
|
|
|
while (i < upvar_count) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llbindingptr =
|
|
|
|
cx.build.GEP(llbindingsptr, [C_int(0), C_int(i as int)]);
|
2011-03-11 12:02:51 -08:00
|
|
|
cx.build.Store(llbindings.(i), llbindingptr);
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Null bindings.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-11 12:02:51 -08:00
|
|
|
llbindingsptr = C_null(T_ptr(T_i8()));
|
2011-03-10 16:49:00 -08:00
|
|
|
}
|
2011-03-11 12:02:51 -08:00
|
|
|
// Create an environment and populate it with the bindings.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-17 20:41:41 +02:00
|
|
|
auto tydesc_count = vec::len[ValueRef](cx.fcx.lltydescs);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llenvptrty =
|
|
|
|
T_closure_ptr(lcx.ccx.tn, T_ptr(T_nil()), val_ty(llbindingsptr),
|
|
|
|
tydesc_count);
|
2011-05-12 17:24:54 +02:00
|
|
|
auto llenvptr = alloca(cx, llvm::LLVMGetElementType(llenvptrty));
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llbindingsptrptr =
|
|
|
|
cx.build.GEP(llenvptr,
|
|
|
|
[C_int(0), C_int(abi::box_rc_field_body), C_int(2)]);
|
2011-03-11 12:02:51 -08:00
|
|
|
cx.build.Store(llbindingsptr, llbindingsptrptr);
|
2011-04-15 18:14:29 -07:00
|
|
|
// Copy in our type descriptors, in case the iterator body needs to refer
|
|
|
|
// to them.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
auto lltydescsptr =
|
|
|
|
cx.build.GEP(llenvptr,
|
|
|
|
[C_int(0), C_int(abi::box_rc_field_body),
|
|
|
|
C_int(abi::closure_elt_ty_params)]);
|
2011-04-15 18:14:29 -07:00
|
|
|
auto i = 0u;
|
|
|
|
while (i < tydesc_count) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto lltydescptr =
|
|
|
|
cx.build.GEP(lltydescsptr, [C_int(0), C_int(i as int)]);
|
2011-04-15 18:14:29 -07:00
|
|
|
cx.build.Store(cx.fcx.lltydescs.(i), lltydescptr);
|
|
|
|
i += 1u;
|
|
|
|
}
|
2011-03-10 16:49:00 -08:00
|
|
|
// Step 2: Declare foreach body function.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
let str s =
|
|
|
|
mangle_internal_name_by_path_and_seq(lcx.ccx, lcx.path, "foreach");
|
2011-02-17 12:20:55 -08:00
|
|
|
// The 'env' arg entering the body function is a fake env member (as in
|
|
|
|
// the env-part of the normal rust calling convention) that actually
|
|
|
|
// points to a stack allocated env in this frame. We bundle that env
|
|
|
|
// pointer along with the foreach-body-fn pointer into a 'normal' fn pair
|
|
|
|
// and pass it in as a first class fn-arg to the iterator.
|
|
|
|
|
2011-04-23 14:17:44 -07:00
|
|
|
auto iter_body_llty =
|
2011-06-15 11:19:50 -07:00
|
|
|
type_of_fn_full(lcx.ccx, cx.sp, ast::proto_fn, none[TypeRef],
|
2011-06-10 12:03:50 +02:00
|
|
|
[rec(mode=ty::mo_alias(false), ty=decl_ty)],
|
2011-05-12 17:24:54 +02:00
|
|
|
ty::mk_nil(lcx.ccx.tcx), 0u);
|
2011-06-15 11:19:50 -07:00
|
|
|
let ValueRef lliterbody =
|
|
|
|
decl_internal_fastcall_fn(lcx.ccx.llmod, s, iter_body_llty);
|
2011-05-18 15:35:16 -07:00
|
|
|
auto fcx = new_fn_ctxt(lcx, cx.sp, lliterbody);
|
2011-05-11 11:56:49 -07:00
|
|
|
auto copy_args_bcx = new_raw_block_ctxt(fcx, fcx.llcopyargs);
|
2011-03-11 12:02:51 -08:00
|
|
|
// Populate the upvars from the environment.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
auto llremoteenvptr =
|
|
|
|
copy_args_bcx.build.PointerCast(fcx.llenv, llenvptrty);
|
2011-04-26 20:39:25 +00:00
|
|
|
auto llremotebindingsptrptr =
|
2011-05-11 11:56:49 -07:00
|
|
|
copy_args_bcx.build.GEP(llremoteenvptr,
|
2011-06-15 11:19:50 -07:00
|
|
|
[C_int(0), C_int(abi::box_rc_field_body),
|
|
|
|
C_int(abi::closure_elt_bindings)]);
|
2011-05-11 11:56:49 -07:00
|
|
|
auto llremotebindingsptr =
|
|
|
|
copy_args_bcx.build.Load(llremotebindingsptrptr);
|
2011-04-15 18:14:29 -07:00
|
|
|
i = 0u;
|
2011-03-11 12:02:51 -08:00
|
|
|
while (i < upvar_count) {
|
|
|
|
auto upvar_id = upvars.(i);
|
2011-05-11 11:56:49 -07:00
|
|
|
auto llupvarptrptr =
|
|
|
|
copy_args_bcx.build.GEP(llremotebindingsptr,
|
2011-05-16 18:21:22 -07:00
|
|
|
[C_int(0), C_int(i as int)]);
|
2011-05-11 11:56:49 -07:00
|
|
|
auto llupvarptr = copy_args_bcx.build.Load(llupvarptrptr);
|
2011-03-11 12:02:51 -08:00
|
|
|
fcx.llupvars.insert(upvar_id, llupvarptr);
|
|
|
|
i += 1u;
|
|
|
|
}
|
2011-04-15 18:14:29 -07:00
|
|
|
// Populate the type parameters from the environment.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-26 20:39:25 +00:00
|
|
|
auto llremotetydescsptr =
|
2011-05-11 11:56:49 -07:00
|
|
|
copy_args_bcx.build.GEP(llremoteenvptr,
|
2011-06-15 11:19:50 -07:00
|
|
|
[C_int(0), C_int(abi::box_rc_field_body),
|
|
|
|
C_int(abi::closure_elt_ty_params)]);
|
2011-04-15 18:14:29 -07:00
|
|
|
i = 0u;
|
|
|
|
while (i < tydesc_count) {
|
2011-05-11 11:56:49 -07:00
|
|
|
auto llremotetydescptr =
|
2011-06-15 11:19:50 -07:00
|
|
|
copy_args_bcx.build.GEP(llremotetydescsptr,
|
|
|
|
[C_int(0), C_int(i as int)]);
|
2011-05-11 11:56:49 -07:00
|
|
|
auto llremotetydesc = copy_args_bcx.build.Load(llremotetydescptr);
|
2011-05-16 18:21:22 -07:00
|
|
|
fcx.lltydescs += [llremotetydesc];
|
2011-04-15 18:14:29 -07:00
|
|
|
i += 1u;
|
|
|
|
}
|
2011-04-23 14:17:44 -07:00
|
|
|
// Add an upvar for the loop variable alias.
|
2011-03-11 12:02:51 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fcx.llupvars.insert(decl_id, llvm::LLVMGetParam(fcx.llfn, 3u));
|
2011-05-11 11:56:49 -07:00
|
|
|
auto bcx = new_top_block_ctxt(fcx);
|
|
|
|
auto lltop = bcx.llbb;
|
2011-05-31 14:24:04 +02:00
|
|
|
auto r = trans_block(bcx, body, return);
|
2011-05-11 11:56:49 -07:00
|
|
|
finish_fn(fcx, lltop);
|
2011-04-19 16:52:59 -07:00
|
|
|
r.bcx.build.RetVoid();
|
2011-02-17 12:20:55 -08:00
|
|
|
|
2011-02-18 17:30:57 -08:00
|
|
|
// Step 3: Call iter passing [lliterbody, llenv], plus other args.
|
2011-02-17 12:20:55 -08:00
|
|
|
alt (seq.node) {
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_call(?f, ?args, ?ann)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto pair = alloca(cx, T_fn_pair(lcx.ccx.tn, iter_body_llty));
|
|
|
|
auto code_cell =
|
|
|
|
cx.build.GEP(pair, [C_int(0), C_int(abi::fn_field_code)]);
|
2011-02-18 18:04:37 -08:00
|
|
|
cx.build.Store(lliterbody, code_cell);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto env_cell =
|
|
|
|
cx.build.GEP(pair, [C_int(0), C_int(abi::fn_field_box)]);
|
|
|
|
auto llenvblobptr =
|
|
|
|
cx.build.PointerCast(llenvptr,
|
|
|
|
T_opaque_closure_ptr(lcx.ccx.tn));
|
2011-03-11 12:02:51 -08:00
|
|
|
cx.build.Store(llenvblobptr, env_cell);
|
2011-04-20 17:23:45 +02:00
|
|
|
// log "lliterbody: " + val_str(lcx.ccx.tn, lliterbody);
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
r =
|
|
|
|
trans_call(cx, f, some[ValueRef](cx.build.Load(pair)), args,
|
2011-02-18 17:30:57 -08:00
|
|
|
ann);
|
2011-04-19 16:52:59 -07:00
|
|
|
ret res(r.bcx, C_nil());
|
2011-02-17 12:20:55 -08:00
|
|
|
}
|
|
|
|
}
|
2011-02-14 18:17:31 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_while(&@block_ctxt cx, &@ast::expr cond, &ast::block body) ->
|
|
|
|
result {
|
2010-12-02 19:12:34 -08:00
|
|
|
auto cond_cx = new_scope_block_ctxt(cx, "while cond");
|
2010-11-10 17:46:49 -08:00
|
|
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
2011-06-15 11:19:50 -07:00
|
|
|
auto body_cx =
|
|
|
|
new_loop_scope_block_ctxt(cx, option::none[@block_ctxt], next_cx,
|
|
|
|
"while loop body");
|
2011-05-31 14:24:04 +02:00
|
|
|
auto body_res = trans_block(body_cx, body, return);
|
2010-11-04 07:55:33 -07:00
|
|
|
auto cond_res = trans_expr(cond_cx, cond);
|
|
|
|
body_res.bcx.build.Br(cond_cx.llbb);
|
2011-03-10 11:27:51 -08:00
|
|
|
auto cond_bcx = trans_block_cleanups(cond_res.bcx, cond_cx);
|
|
|
|
cond_bcx.build.CondBr(cond_res.val, body_cx.llbb, next_cx.llbb);
|
2010-11-04 07:55:33 -07:00
|
|
|
cx.build.Br(cond_cx.llbb);
|
2010-11-03 11:05:15 -07:00
|
|
|
ret res(next_cx, C_nil());
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_do_while(&@block_ctxt cx, &ast::block body, &@ast::expr cond) ->
|
|
|
|
result {
|
2010-11-10 17:46:49 -08:00
|
|
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
2011-06-15 11:19:50 -07:00
|
|
|
auto body_cx =
|
|
|
|
new_loop_scope_block_ctxt(cx, option::none[@block_ctxt], next_cx,
|
|
|
|
"do-while loop body");
|
2011-05-31 14:24:04 +02:00
|
|
|
auto body_res = trans_block(body_cx, body, return);
|
2010-11-04 07:55:33 -07:00
|
|
|
auto cond_res = trans_expr(body_res.bcx, cond);
|
2011-06-15 11:19:50 -07:00
|
|
|
cond_res.bcx.build.CondBr(cond_res.val, body_cx.llbb, next_cx.llbb);
|
2010-11-04 07:55:33 -07:00
|
|
|
cx.build.Br(body_cx.llbb);
|
2010-11-03 11:05:15 -07:00
|
|
|
ret res(next_cx, body_res.val);
|
|
|
|
}
|
|
|
|
|
2010-12-15 09:38:23 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
// Pattern matching translation
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_pat_match(&@block_ctxt cx, &@ast::pat pat, ValueRef llval,
|
2011-05-10 17:58:22 -07:00
|
|
|
&@block_ctxt next_cx) -> result {
|
2010-12-15 09:38:23 -08:00
|
|
|
alt (pat.node) {
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::pat_wild(_)) { ret res(cx, llval); }
|
|
|
|
case (ast::pat_bind(_, _, _)) { ret res(cx, llval); }
|
|
|
|
case (ast::pat_lit(?lt, ?ann)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto lllit = trans_lit(cx.fcx.lcx.ccx, *lt, ann);
|
2011-06-07 13:50:30 -07:00
|
|
|
auto lltype = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann);
|
2011-05-12 17:24:54 +02:00
|
|
|
auto lleq = trans_compare(cx, ast::eq, lltype, llval, lllit);
|
2011-02-28 16:36:08 -08:00
|
|
|
auto matched_cx = new_sub_block_ctxt(lleq.bcx, "matched_cx");
|
|
|
|
lleq.bcx.build.CondBr(lleq.val, matched_cx.llbb, next_cx.llbb);
|
2011-02-10 19:40:02 -08:00
|
|
|
ret res(matched_cx, llval);
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::pat_tag(?id, ?subpats, ?ann)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto lltagptr =
|
|
|
|
cx.build.PointerCast(llval,
|
|
|
|
T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn));
|
|
|
|
auto lldiscrimptr = cx.build.GEP(lltagptr, [C_int(0), C_int(0)]);
|
2011-03-09 14:29:00 -08:00
|
|
|
auto lldiscrim = cx.build.Load(lldiscrimptr);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto vdef =
|
|
|
|
ast::variant_def_ids(cx.fcx.lcx.ccx.tcx.def_map.get(ann.id));
|
2010-12-15 09:38:23 -08:00
|
|
|
auto variant_tag = 0;
|
2011-05-19 17:21:21 -07:00
|
|
|
auto variants = ty::tag_variants(cx.fcx.lcx.ccx.tcx, vdef._0);
|
2010-12-15 09:38:23 -08:00
|
|
|
auto i = 0;
|
2011-05-19 17:21:21 -07:00
|
|
|
for (ty::variant_info v in variants) {
|
2011-04-01 11:36:52 -07:00
|
|
|
auto this_variant_id = v.id;
|
2011-05-12 13:25:18 +02:00
|
|
|
if (vdef._1._0 == this_variant_id._0 &&
|
2011-06-15 11:19:50 -07:00
|
|
|
vdef._1._1 == this_variant_id._1) {
|
2010-12-15 09:38:23 -08:00
|
|
|
variant_tag = i;
|
|
|
|
}
|
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
auto matched_cx = new_sub_block_ctxt(cx, "matched_cx");
|
2011-06-15 11:19:50 -07:00
|
|
|
auto lleq =
|
|
|
|
cx.build.ICmp(lib::llvm::LLVMIntEQ, lldiscrim,
|
|
|
|
C_int(variant_tag));
|
2010-12-15 09:38:23 -08:00
|
|
|
cx.build.CondBr(lleq, matched_cx.llbb, next_cx.llbb);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto ty_params = ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx, ann);
|
2011-05-17 20:41:41 +02:00
|
|
|
if (vec::len[@ast::pat](subpats) > 0u) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llblobptr =
|
|
|
|
matched_cx.build.GEP(lltagptr, [C_int(0), C_int(1)]);
|
2010-12-15 09:38:23 -08:00
|
|
|
auto i = 0;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (@ast::pat subpat in subpats) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto rslt =
|
|
|
|
GEP_tag(matched_cx, llblobptr, vdef._0, vdef._1,
|
|
|
|
ty_params, i);
|
2011-03-09 15:17:06 -08:00
|
|
|
auto llsubvalptr = rslt.val;
|
|
|
|
matched_cx = rslt.bcx;
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llsubval =
|
|
|
|
load_if_immediate(matched_cx, llsubvalptr,
|
|
|
|
pat_ty(cx.fcx.lcx.ccx.tcx, subpat));
|
|
|
|
auto subpat_res =
|
|
|
|
trans_pat_match(matched_cx, subpat, llsubval,
|
|
|
|
next_cx);
|
2010-12-15 09:38:23 -08:00
|
|
|
matched_cx = subpat_res.bcx;
|
2011-04-27 14:55:55 -07:00
|
|
|
i += 1;
|
2010-12-15 09:38:23 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ret res(matched_cx, llval);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_pat_binding(&@block_ctxt cx, &@ast::pat pat, ValueRef llval,
|
|
|
|
bool bind_alias) -> result {
|
2010-12-15 09:38:23 -08:00
|
|
|
alt (pat.node) {
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::pat_wild(_)) { ret res(cx, llval); }
|
|
|
|
case (ast::pat_lit(_, _)) { ret res(cx, llval); }
|
|
|
|
case (ast::pat_bind(?id, ?def_id, ?ann)) {
|
2011-04-25 03:59:35 +00:00
|
|
|
if (bind_alias) {
|
|
|
|
cx.fcx.lllocals.insert(def_id, llval);
|
|
|
|
ret res(cx, llval);
|
|
|
|
} else {
|
|
|
|
auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
|
|
|
|
auto rslt = alloc_ty(cx, t);
|
|
|
|
auto dst = rslt.val;
|
|
|
|
auto bcx = rslt.bcx;
|
2011-05-10 16:43:34 -07:00
|
|
|
maybe_name_value(cx.fcx.lcx.ccx, dst, id);
|
2011-04-25 03:59:35 +00:00
|
|
|
bcx.fcx.lllocals.insert(def_id, dst);
|
2011-06-15 11:19:50 -07:00
|
|
|
bcx.cleanups += [clean(bind drop_slot(_, dst, t))];
|
2011-05-27 17:58:22 -07:00
|
|
|
ret copy_val(bcx, INIT, dst, llval, t);
|
2011-04-25 03:59:35 +00:00
|
|
|
}
|
2010-12-15 09:38:23 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::pat_tag(_, ?subpats, ?ann)) {
|
2011-05-17 20:41:41 +02:00
|
|
|
if (vec::len[@ast::pat](subpats) == 0u) { ret res(cx, llval); }
|
2011-03-09 15:17:06 -08:00
|
|
|
// Get the appropriate variant for this tag.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto vdef =
|
|
|
|
ast::variant_def_ids(cx.fcx.lcx.ccx.tcx.def_map.get(ann.id));
|
|
|
|
auto lltagptr =
|
|
|
|
cx.build.PointerCast(llval,
|
|
|
|
T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn));
|
2011-05-16 18:21:22 -07:00
|
|
|
auto llblobptr = cx.build.GEP(lltagptr, [C_int(0), C_int(1)]);
|
2011-05-16 11:43:50 -07:00
|
|
|
auto ty_param_substs =
|
2011-06-07 13:50:30 -07:00
|
|
|
ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx, ann);
|
2010-12-15 09:38:23 -08:00
|
|
|
auto this_cx = cx;
|
|
|
|
auto i = 0;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (@ast::pat subpat in subpats) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto rslt =
|
|
|
|
GEP_tag(this_cx, llblobptr, vdef._0, vdef._1,
|
|
|
|
ty_param_substs, i);
|
2011-03-09 15:17:06 -08:00
|
|
|
this_cx = rslt.bcx;
|
2011-06-15 11:19:50 -07:00
|
|
|
auto subpat_res =
|
|
|
|
trans_pat_binding(this_cx, subpat, rslt.val, true);
|
2010-12-15 09:38:23 -08:00
|
|
|
this_cx = subpat_res.bcx;
|
2010-12-15 10:11:33 -08:00
|
|
|
i += 1;
|
2010-12-15 09:38:23 -08:00
|
|
|
}
|
|
|
|
ret res(this_cx, llval);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_alt(&@block_ctxt cx, &@ast::expr expr, &vec[ast::arm] arms,
|
|
|
|
&ast::ann ann, &out_method output) -> result {
|
2010-12-15 09:38:23 -08:00
|
|
|
auto expr_res = trans_expr(cx, expr);
|
|
|
|
auto this_cx = expr_res.bcx;
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[result] arm_results = [];
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ast::arm arm in arms) {
|
2010-12-15 09:38:23 -08:00
|
|
|
auto next_cx = new_sub_block_ctxt(expr_res.bcx, "next");
|
2011-06-15 11:19:50 -07:00
|
|
|
auto match_res =
|
|
|
|
trans_pat_match(this_cx, arm.pat, expr_res.val, next_cx);
|
2010-12-15 09:38:23 -08:00
|
|
|
auto binding_cx = new_scope_block_ctxt(match_res.bcx, "binding");
|
|
|
|
match_res.bcx.build.Br(binding_cx.llbb);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto binding_res =
|
|
|
|
trans_pat_binding(binding_cx, arm.pat, expr_res.val, false);
|
2011-05-31 14:24:04 +02:00
|
|
|
auto block_res = trans_block(binding_res.bcx, arm.block, output);
|
2011-05-16 18:21:22 -07:00
|
|
|
arm_results += [block_res];
|
2010-12-15 09:38:23 -08:00
|
|
|
this_cx = next_cx;
|
|
|
|
}
|
2011-04-02 14:12:19 -04:00
|
|
|
auto default_cx = this_cx;
|
2011-06-15 11:19:50 -07:00
|
|
|
auto default_res =
|
|
|
|
trans_fail(default_cx, some[common::span](expr.span),
|
|
|
|
"non-exhaustive match failure");
|
2011-04-02 19:12:00 -04:00
|
|
|
// FIXME: This isn't quite right, particularly re: dynamic types
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-07 13:50:30 -07:00
|
|
|
auto expr_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann);
|
2011-04-02 19:06:19 -04:00
|
|
|
auto expr_llty;
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, expr_ty)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
expr_llty = T_typaram_ptr(cx.fcx.lcx.ccx.tn);
|
2011-04-02 19:06:19 -04:00
|
|
|
} else {
|
2011-05-18 15:35:16 -07:00
|
|
|
expr_llty = type_of(cx.fcx.lcx.ccx, expr.span, expr_ty);
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, expr_ty)) {
|
2011-04-02 19:06:19 -04:00
|
|
|
expr_llty = T_ptr(expr_llty);
|
|
|
|
}
|
|
|
|
}
|
2011-05-31 14:24:04 +02:00
|
|
|
ret res(join_branches(cx, arm_results), C_nil());
|
2010-12-15 09:38:23 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
type generic_info =
|
|
|
|
rec(ty::t item_type,
|
|
|
|
vec[option::t[@tydesc_info]] static_tis,
|
|
|
|
vec[ValueRef] tydescs);
|
2011-01-14 14:17:57 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
type lval_result =
|
|
|
|
rec(result res,
|
|
|
|
bool is_mem,
|
|
|
|
option::t[generic_info] generic,
|
|
|
|
option::t[ValueRef] llobj,
|
|
|
|
option::t[ty::t] method_ty);
|
2010-12-23 17:31:16 -08:00
|
|
|
|
2011-05-10 17:58:22 -07:00
|
|
|
fn lval_mem(&@block_ctxt cx, ValueRef val) -> lval_result {
|
2010-12-23 17:31:16 -08:00
|
|
|
ret rec(res=res(cx, val),
|
|
|
|
is_mem=true,
|
2011-01-14 14:17:57 -08:00
|
|
|
generic=none[generic_info],
|
2011-04-05 16:17:47 -07:00
|
|
|
llobj=none[ValueRef],
|
2011-05-12 17:24:54 +02:00
|
|
|
method_ty=none[ty::t]);
|
2010-12-23 17:31:16 -08:00
|
|
|
}
|
|
|
|
|
2011-05-10 17:58:22 -07:00
|
|
|
fn lval_val(&@block_ctxt cx, ValueRef val) -> lval_result {
|
2010-12-23 17:31:16 -08:00
|
|
|
ret rec(res=res(cx, val),
|
|
|
|
is_mem=false,
|
2011-01-14 14:17:57 -08:00
|
|
|
generic=none[generic_info],
|
2011-04-05 16:17:47 -07:00
|
|
|
llobj=none[ValueRef],
|
2011-05-12 17:24:54 +02:00
|
|
|
method_ty=none[ty::t]);
|
2010-12-23 17:31:16 -08:00
|
|
|
}
|
2010-10-21 18:13:57 -07:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_external_path(&@block_ctxt cx, &ast::def_id did,
|
|
|
|
&ty::ty_param_count_and_ty tpt) -> lval_result {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto lcx = cx.fcx.lcx;
|
2011-05-12 17:24:54 +02:00
|
|
|
auto name = creader::get_symbol(lcx.ccx.sess, did);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto v =
|
|
|
|
get_extern_const(lcx.ccx.externs, lcx.ccx.llmod, name,
|
|
|
|
type_of_ty_param_count_and_ty(lcx, cx.sp, tpt));
|
2011-03-30 18:15:29 -07:00
|
|
|
ret lval_val(cx, v);
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn lval_generic_fn(&@block_ctxt cx, &ty::ty_param_count_and_ty tpt,
|
|
|
|
&ast::def_id fn_id, &ast::ann ann) -> lval_result {
|
2011-03-30 18:15:29 -07:00
|
|
|
auto lv;
|
2011-04-17 14:24:45 +02:00
|
|
|
if (cx.fcx.lcx.ccx.sess.get_targ_crate_num() == fn_id._0) {
|
2011-03-30 18:15:29 -07:00
|
|
|
// Internal reference.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-02 17:47:24 -07:00
|
|
|
assert (cx.fcx.lcx.ccx.fn_pairs.contains_key(fn_id));
|
2011-04-17 14:24:45 +02:00
|
|
|
lv = lval_val(cx, cx.fcx.lcx.ccx.fn_pairs.get(fn_id));
|
2011-03-30 18:15:29 -07:00
|
|
|
} else {
|
|
|
|
// External reference.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-12 15:09:50 -07:00
|
|
|
lv = trans_external_path(cx, fn_id, tpt);
|
2011-03-30 18:15:29 -07:00
|
|
|
}
|
2011-06-07 13:50:30 -07:00
|
|
|
auto tys = ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx, ann);
|
|
|
|
auto monoty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann);
|
2011-05-17 20:41:41 +02:00
|
|
|
if (vec::len[ty::t](tys) != 0u) {
|
2011-04-26 20:39:25 +00:00
|
|
|
auto bcx = lv.res.bcx;
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ValueRef] tydescs = [];
|
|
|
|
let vec[option::t[@tydesc_info]] tis = [];
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ty::t t in tys) {
|
2011-04-29 14:59:52 -07:00
|
|
|
// TODO: Doesn't always escape.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-12 15:42:12 -07:00
|
|
|
auto ti = none[@tydesc_info];
|
|
|
|
auto td = get_tydesc(bcx, t, true, ti);
|
2011-05-16 18:21:22 -07:00
|
|
|
tis += [ti];
|
2011-01-31 18:06:35 -08:00
|
|
|
bcx = td.bcx;
|
2011-05-17 20:41:41 +02:00
|
|
|
vec::push[ValueRef](tydescs, td.val);
|
2011-01-31 18:06:35 -08:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
auto gen = rec(item_type=tpt._1, static_tis=tis, tydescs=tydescs);
|
|
|
|
lv =
|
|
|
|
rec(res=res(bcx, lv.res.val), generic=some[generic_info](gen)
|
|
|
|
with lv);
|
2011-01-31 18:06:35 -08:00
|
|
|
}
|
|
|
|
ret lv;
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn lookup_discriminant(&@local_ctxt lcx, &ast::def_id tid, &ast::def_id vid)
|
2011-06-15 11:19:50 -07:00
|
|
|
-> ValueRef {
|
2011-04-17 14:24:45 +02:00
|
|
|
alt (lcx.ccx.discrims.find(vid)) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (none) {
|
2011-04-07 11:42:40 -07:00
|
|
|
// It's an external discriminant that we haven't seen yet.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-02 17:47:24 -07:00
|
|
|
assert (lcx.ccx.sess.get_targ_crate_num() != vid._0);
|
2011-05-12 17:24:54 +02:00
|
|
|
auto sym = creader::get_symbol(lcx.ccx.sess, vid);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto gvar =
|
|
|
|
llvm::LLVMAddGlobal(lcx.ccx.llmod, T_int(), str::buf(sym));
|
|
|
|
llvm::LLVMSetLinkage(gvar,
|
|
|
|
lib::llvm::LLVMExternalLinkage as
|
|
|
|
llvm::Linkage);
|
2011-05-12 17:24:54 +02:00
|
|
|
llvm::LLVMSetGlobalConstant(gvar, True);
|
2011-04-17 14:24:45 +02:00
|
|
|
lcx.ccx.discrims.insert(vid, gvar);
|
2011-04-07 11:42:40 -07:00
|
|
|
ret gvar;
|
|
|
|
}
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(?llval)) { ret llval; }
|
2011-04-07 11:42:40 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_path(&@block_ctxt cx, &ast::path p, &ast::ann ann) -> lval_result {
|
2011-05-17 11:30:11 -07:00
|
|
|
alt (cx.fcx.lcx.ccx.tcx.def_map.get(ann.id)) {
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::def_arg(?did)) {
|
2011-05-12 13:25:18 +02:00
|
|
|
alt (cx.fcx.llargs.find(did)) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (none) {
|
2011-05-12 13:25:18 +02:00
|
|
|
assert (cx.fcx.llupvars.contains_key(did));
|
|
|
|
ret lval_mem(cx, cx.fcx.llupvars.get(did));
|
2010-10-19 16:33:11 -07:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (some(?llval)) { ret lval_mem(cx, llval); }
|
2011-05-12 13:25:18 +02:00
|
|
|
}
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::def_local(?did)) {
|
2011-05-12 13:25:18 +02:00
|
|
|
alt (cx.fcx.lllocals.find(did)) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (none) {
|
2011-05-12 13:25:18 +02:00
|
|
|
assert (cx.fcx.llupvars.contains_key(did));
|
|
|
|
ret lval_mem(cx, cx.fcx.llupvars.get(did));
|
2010-12-30 17:01:20 -08:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (some(?llval)) { ret lval_mem(cx, llval); }
|
2011-05-12 13:25:18 +02:00
|
|
|
}
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::def_binding(?did)) {
|
2011-05-12 13:25:18 +02:00
|
|
|
assert (cx.fcx.lllocals.contains_key(did));
|
|
|
|
ret lval_mem(cx, cx.fcx.lllocals.get(did));
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::def_obj_field(?did)) {
|
2011-05-12 13:25:18 +02:00
|
|
|
assert (cx.fcx.llobjfields.contains_key(did));
|
|
|
|
ret lval_mem(cx, cx.fcx.llobjfields.get(did));
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::def_fn(?did)) {
|
2011-05-19 17:21:21 -07:00
|
|
|
auto tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, did);
|
2011-05-12 13:25:18 +02:00
|
|
|
ret lval_generic_fn(cx, tyt, did, ann);
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::def_obj(?did)) {
|
2011-05-19 17:21:21 -07:00
|
|
|
auto tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, did);
|
2011-05-12 13:25:18 +02:00
|
|
|
ret lval_generic_fn(cx, tyt, did, ann);
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::def_variant(?tid, ?vid)) {
|
2011-05-19 17:21:21 -07:00
|
|
|
auto v_tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, vid);
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(cx.fcx.lcx.ccx.tcx, v_tyt._1)) {
|
2011-06-09 09:48:16 -07:00
|
|
|
case (ty::ty_fn(_, _, _, _, _)) {
|
2011-05-12 13:25:18 +02:00
|
|
|
// N-ary variant.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-12 13:25:18 +02:00
|
|
|
ret lval_generic_fn(cx, v_tyt, vid, ann);
|
2010-12-16 10:23:47 -08:00
|
|
|
}
|
2011-05-12 13:25:18 +02:00
|
|
|
case (_) {
|
|
|
|
// Nullary variant.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-12 13:25:18 +02:00
|
|
|
auto tag_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
|
|
|
|
auto lldiscrim_gv =
|
|
|
|
lookup_discriminant(cx.fcx.lcx, tid, vid);
|
|
|
|
auto lldiscrim = cx.build.Load(lldiscrim_gv);
|
|
|
|
auto alloc_result = alloc_ty(cx, tag_ty);
|
|
|
|
auto lltagblob = alloc_result.val;
|
|
|
|
auto lltagty;
|
2011-06-15 11:19:50 -07:00
|
|
|
if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, tag_ty))
|
|
|
|
{
|
2011-05-12 13:25:18 +02:00
|
|
|
lltagty = T_opaque_tag(cx.fcx.lcx.ccx.tn);
|
|
|
|
} else {
|
2011-05-18 15:35:16 -07:00
|
|
|
lltagty = type_of(cx.fcx.lcx.ccx, p.span, tag_ty);
|
2011-05-12 13:25:18 +02:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
auto lltagptr =
|
|
|
|
alloc_result.bcx.build.PointerCast(lltagblob,
|
|
|
|
T_ptr(lltagty));
|
|
|
|
auto lldiscrimptr =
|
|
|
|
alloc_result.bcx.build.GEP(lltagptr,
|
|
|
|
[C_int(0), C_int(0)]);
|
|
|
|
alloc_result.bcx.build.Store(lldiscrim, lldiscrimptr);
|
2011-05-12 13:25:18 +02:00
|
|
|
ret lval_val(alloc_result.bcx, lltagptr);
|
2010-10-19 16:33:11 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::def_const(?did)) {
|
2011-05-12 13:25:18 +02:00
|
|
|
// TODO: externals
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-12 13:25:18 +02:00
|
|
|
assert (cx.fcx.lcx.ccx.consts.contains_key(did));
|
|
|
|
ret lval_mem(cx, cx.fcx.lcx.ccx.consts.get(did));
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::def_native_fn(?did)) {
|
2011-05-19 17:21:21 -07:00
|
|
|
auto tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, did);
|
2011-05-12 13:25:18 +02:00
|
|
|
ret lval_generic_fn(cx, tyt, did, ann);
|
|
|
|
}
|
|
|
|
case (_) {
|
2011-05-20 14:15:39 -07:00
|
|
|
cx.fcx.lcx.ccx.sess.span_unimpl(cx.sp, "def variant in trans");
|
2010-11-26 15:54:04 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-31 18:24:06 -07:00
|
|
|
fn trans_field(&@block_ctxt cx, &span sp, ValueRef v, &ty::t t0,
|
2011-05-12 17:24:54 +02:00
|
|
|
&ast::ident field, &ast::ann ann) -> lval_result {
|
2011-04-05 14:18:44 -07:00
|
|
|
auto r = autoderef(cx, v, t0);
|
2011-04-22 17:00:46 -07:00
|
|
|
auto t = autoderefed_ty(cx.fcx.lcx.ccx, t0);
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
|
|
|
|
case (ty::ty_tup(_)) {
|
|
|
|
let uint ix = ty::field_num(cx.fcx.lcx.ccx.sess, sp, field);
|
2011-05-16 18:21:22 -07:00
|
|
|
auto v = GEP_tup_like(r.bcx, t, r.val, [0, ix as int]);
|
2011-01-31 15:03:05 -08:00
|
|
|
ret lval_mem(v.bcx, v.val);
|
2010-11-26 15:54:04 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_rec(?fields)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
let uint ix =
|
|
|
|
ty::field_idx(cx.fcx.lcx.ccx.sess, sp, field, fields);
|
2011-05-16 18:21:22 -07:00
|
|
|
auto v = GEP_tup_like(r.bcx, t, r.val, [0, ix as int]);
|
2011-01-31 15:03:05 -08:00
|
|
|
ret lval_mem(v.bcx, v.val);
|
2010-12-20 16:48:28 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ty::ty_obj(?methods)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
let uint ix =
|
|
|
|
ty::method_idx(cx.fcx.lcx.ccx.sess, sp, field, methods);
|
|
|
|
auto vtbl =
|
|
|
|
r.bcx.build.GEP(r.val,
|
|
|
|
[C_int(0), C_int(abi::obj_field_vtbl)]);
|
2010-12-20 16:48:28 -08:00
|
|
|
vtbl = r.bcx.build.Load(vtbl);
|
2011-04-29 13:34:30 +02:00
|
|
|
// +1 because slot #0 contains the destructor
|
2010-12-23 17:31:16 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto v = r.bcx.build.GEP(vtbl, [C_int(0), C_int(ix + 1u as int)]);
|
2010-12-23 17:31:16 -08:00
|
|
|
auto lvo = lval_mem(r.bcx, v);
|
2011-06-15 11:19:50 -07:00
|
|
|
let ty::t fn_ty =
|
|
|
|
ty::method_ty_to_fn_ty(cx.fcx.lcx.ccx.tcx, methods.(ix));
|
|
|
|
ret rec(llobj=some[ValueRef](r.val), method_ty=some[ty::t](fn_ty)
|
2011-04-05 16:17:47 -07:00
|
|
|
with lvo);
|
2010-11-30 10:39:35 -08:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) {
|
|
|
|
cx.fcx.lcx.ccx.sess.unimpl("field variant in trans_field");
|
|
|
|
}
|
2010-11-26 15:54:04 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_index(&@block_ctxt cx, &span sp, &@ast::expr base, &@ast::expr idx,
|
|
|
|
&ast::ann ann) -> lval_result {
|
2011-06-11 23:15:16 -07:00
|
|
|
// Is this an interior vector?
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-11 23:15:16 -07:00
|
|
|
auto base_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, base);
|
|
|
|
auto base_ty_no_boxes = ty::strip_boxes(cx.fcx.lcx.ccx.tcx, base_ty);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto is_interior =
|
|
|
|
ty::sequence_is_interior(cx.fcx.lcx.ccx.tcx, base_ty_no_boxes);
|
2010-12-10 17:24:35 -08:00
|
|
|
auto lv = trans_expr(cx, base);
|
2011-06-11 23:15:16 -07:00
|
|
|
lv = autoderef(lv.bcx, lv.val, base_ty);
|
2010-12-10 17:24:35 -08:00
|
|
|
auto ix = trans_expr(lv.bcx, idx);
|
|
|
|
auto v = lv.val;
|
2011-01-31 15:03:05 -08:00
|
|
|
auto bcx = ix.bcx;
|
2011-03-07 15:43:55 -08:00
|
|
|
// Cast to an LLVM integer. Rust is less strict than LLVM in this regard.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-07 15:43:55 -08:00
|
|
|
auto ix_val;
|
2011-04-17 14:24:45 +02:00
|
|
|
auto ix_size = llsize_of_real(cx.fcx.lcx.ccx, val_ty(ix.val));
|
|
|
|
auto int_size = llsize_of_real(cx.fcx.lcx.ccx, T_int());
|
2011-03-07 15:43:55 -08:00
|
|
|
if (ix_size < int_size) {
|
|
|
|
ix_val = bcx.build.ZExt(ix.val, T_int());
|
|
|
|
} else if (ix_size > int_size) {
|
|
|
|
ix_val = bcx.build.Trunc(ix.val, T_int());
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { ix_val = ix.val; }
|
2011-04-17 14:24:45 +02:00
|
|
|
auto unit_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
|
2011-03-31 10:10:21 -07:00
|
|
|
auto unit_sz = size_of(bcx, unit_ty);
|
2011-01-31 15:03:05 -08:00
|
|
|
bcx = unit_sz.bcx;
|
2011-05-10 16:43:34 -07:00
|
|
|
maybe_name_value(cx.fcx.lcx.ccx, unit_sz.val, "unit_sz");
|
2011-03-07 15:43:55 -08:00
|
|
|
auto scaled_ix = bcx.build.Mul(ix_val, unit_sz.val);
|
2011-05-10 16:43:34 -07:00
|
|
|
maybe_name_value(cx.fcx.lcx.ccx, scaled_ix, "scaled_ix");
|
2011-06-11 23:15:16 -07:00
|
|
|
auto interior_len_and_data;
|
|
|
|
if (is_interior) {
|
|
|
|
auto rslt = get_ivec_len_and_data(bcx, v, unit_ty);
|
|
|
|
interior_len_and_data = some(tup(rslt._0, rslt._1));
|
|
|
|
bcx = rslt._2;
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { interior_len_and_data = none; }
|
2011-06-11 23:15:16 -07:00
|
|
|
auto lim;
|
|
|
|
alt (interior_len_and_data) {
|
|
|
|
case (some(?lad)) { lim = lad._0; }
|
|
|
|
case (none) {
|
|
|
|
lim = bcx.build.GEP(v, [C_int(0), C_int(abi::vec_elt_fill)]);
|
|
|
|
lim = bcx.build.Load(lim);
|
|
|
|
}
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
auto bounds_check = bcx.build.ICmp(lib::llvm::LLVMIntULT, scaled_ix, lim);
|
2011-01-31 15:03:05 -08:00
|
|
|
auto fail_cx = new_sub_block_ctxt(bcx, "fail");
|
|
|
|
auto next_cx = new_sub_block_ctxt(bcx, "next");
|
|
|
|
bcx.build.CondBr(bounds_check, next_cx.llbb, fail_cx.llbb);
|
2010-12-10 16:10:35 -08:00
|
|
|
// fail: bad bounds check.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto fail_res =
|
|
|
|
trans_fail(fail_cx, some[common::span](sp), "bounds check");
|
2011-06-11 23:15:16 -07:00
|
|
|
auto body;
|
|
|
|
alt (interior_len_and_data) {
|
|
|
|
case (some(?lad)) { body = lad._1; }
|
|
|
|
case (none) {
|
2011-06-15 11:19:50 -07:00
|
|
|
body =
|
|
|
|
next_cx.build.GEP(v,
|
|
|
|
[C_int(0), C_int(abi::vec_elt_data),
|
|
|
|
C_int(0)]);
|
2011-06-11 23:15:16 -07:00
|
|
|
}
|
|
|
|
}
|
2011-03-31 10:10:21 -07:00
|
|
|
auto elt;
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, unit_ty)) {
|
2011-06-12 00:44:43 -07:00
|
|
|
body = next_cx.build.PointerCast(body, T_ptr(T_i8()));
|
|
|
|
elt = next_cx.build.GEP(body, [scaled_ix]);
|
2011-03-31 10:10:21 -07:00
|
|
|
} else {
|
2011-06-12 00:44:43 -07:00
|
|
|
elt = next_cx.build.GEP(body, [ix_val]);
|
2011-04-07 18:00:29 -07:00
|
|
|
// We're crossing a box boundary here, so we may need to pointer cast.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-18 15:35:16 -07:00
|
|
|
auto llunitty = type_of(next_cx.fcx.lcx.ccx, sp, unit_ty);
|
2011-04-07 18:00:29 -07:00
|
|
|
elt = next_cx.build.PointerCast(elt, T_ptr(llunitty));
|
2011-03-31 10:10:21 -07:00
|
|
|
}
|
2010-12-23 17:31:16 -08:00
|
|
|
ret lval_mem(next_cx, elt);
|
2010-12-10 16:10:35 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-12-07 11:57:19 -08:00
|
|
|
// The additional bool returned indicates whether it's mem (that is
|
|
|
|
// represented as an alloca or heap, hence needs a 'load' to be used as an
|
|
|
|
// immediate).
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_lval(&@block_ctxt cx, &@ast::expr e) -> lval_result {
|
2010-11-26 15:54:04 -08:00
|
|
|
alt (e.node) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ast::expr_path(?p, ?ann)) { ret trans_path(cx, p, ann); }
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_field(?base, ?ident, ?ann)) {
|
2011-04-05 14:18:44 -07:00
|
|
|
auto r = trans_expr(cx, base);
|
2011-05-19 15:47:15 -07:00
|
|
|
auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, base);
|
2011-04-05 14:18:44 -07:00
|
|
|
ret trans_field(r.bcx, e.span, r.val, t, ident, ann);
|
2010-11-26 15:54:04 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_index(?base, ?idx, ?ann)) {
|
2010-12-10 16:10:35 -08:00
|
|
|
ret trans_index(cx, e.span, base, idx, ann);
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_unary(?unop, ?base, ?ann)) {
|
|
|
|
assert (unop == ast::deref);
|
2011-04-07 12:50:37 -07:00
|
|
|
auto sub = trans_expr(cx, base);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto val =
|
|
|
|
sub.bcx.build.GEP(sub.val,
|
|
|
|
[C_int(0), C_int(abi::box_rc_field_body)]);
|
2011-04-07 12:50:37 -07:00
|
|
|
ret lval_mem(sub.bcx, val);
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_self_method(?ident, ?ann)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
alt ({ cx.fcx.llself }) {
|
2011-06-01 11:34:52 -07:00
|
|
|
case (some(?pair)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto r = pair.v;
|
|
|
|
auto t = pair.t;
|
2011-04-05 14:18:44 -07:00
|
|
|
ret trans_field(cx, e.span, r, t, ident, ann);
|
|
|
|
}
|
|
|
|
case (_) {
|
|
|
|
// Shouldn't happen.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.fcx.lcx.ccx.sess.bug("trans_lval called on "
|
|
|
|
+ "expr_self_method in a context"
|
|
|
|
+ "without llself");
|
|
|
|
}
|
2011-04-05 14:18:44 -07:00
|
|
|
}
|
|
|
|
}
|
2011-04-07 12:50:37 -07:00
|
|
|
case (_) {
|
2011-06-14 21:37:49 +02:00
|
|
|
ret rec(res=trans_expr(cx, e),
|
|
|
|
is_mem=false,
|
|
|
|
generic=none,
|
|
|
|
llobj=none,
|
|
|
|
method_ty=none);
|
2011-04-07 12:50:37 -07:00
|
|
|
}
|
2010-10-19 16:33:11 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-10 17:58:22 -07:00
|
|
|
fn int_cast(&@block_ctxt bcx, TypeRef lldsttype, TypeRef llsrctype,
|
2011-05-10 14:03:47 -07:00
|
|
|
ValueRef llsrc, bool signed) -> ValueRef {
|
2011-05-12 17:24:54 +02:00
|
|
|
if (llvm::LLVMGetIntTypeWidth(lldsttype) >
|
|
|
|
llvm::LLVMGetIntTypeWidth(llsrctype)) {
|
2011-05-10 14:03:47 -07:00
|
|
|
if (signed) {
|
|
|
|
// Widening signed cast.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-10 14:03:47 -07:00
|
|
|
ret bcx.build.SExtOrBitCast(llsrc, lldsttype);
|
|
|
|
}
|
|
|
|
// Widening unsigned cast.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-10 14:03:47 -07:00
|
|
|
ret bcx.build.ZExtOrBitCast(llsrc, lldsttype);
|
|
|
|
}
|
|
|
|
ret bcx.build.TruncOrBitCast(llsrc, lldsttype);
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_cast(&@block_ctxt cx, &@ast::expr e, &ast::ann ann) -> result {
|
2010-11-24 10:32:14 -08:00
|
|
|
auto e_res = trans_expr(cx, e);
|
|
|
|
auto llsrctype = val_ty(e_res.val);
|
2011-04-17 14:24:45 +02:00
|
|
|
auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
|
2011-05-18 15:35:16 -07:00
|
|
|
auto lldsttype = type_of(cx.fcx.lcx.ccx, e.span, t);
|
2011-05-12 17:24:54 +02:00
|
|
|
if (!ty::type_is_fp(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-18 18:49:59 -07:00
|
|
|
// TODO: native-to-native casts
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_is_native(cx.fcx.lcx.ccx.tcx,
|
2011-06-15 11:19:50 -07:00
|
|
|
ty::expr_ty(cx.fcx.lcx.ccx.tcx, e))) {
|
|
|
|
e_res =
|
|
|
|
res(e_res.bcx,
|
|
|
|
e_res.bcx.build.PtrToInt(e_res.val, lldsttype));
|
2011-05-12 17:24:54 +02:00
|
|
|
} else if (ty::type_is_native(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
e_res =
|
|
|
|
res(e_res.bcx,
|
|
|
|
e_res.bcx.build.IntToPtr(e_res.val, lldsttype));
|
2010-11-24 10:32:14 -08:00
|
|
|
} else {
|
2011-06-15 11:19:50 -07:00
|
|
|
e_res =
|
|
|
|
res(e_res.bcx,
|
|
|
|
int_cast(e_res.bcx, lldsttype, llsrctype, e_res.val,
|
|
|
|
ty::type_is_signed(cx.fcx.lcx.ccx.tcx, t)));
|
2010-11-24 10:32:14 -08:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { cx.fcx.lcx.ccx.sess.unimpl("fp cast"); }
|
2010-11-24 10:32:14 -08:00
|
|
|
ret e_res;
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_bind_thunk(&@local_ctxt cx, &span sp, &ty::t incoming_fty,
|
|
|
|
&ty::t outgoing_fty, &vec[option::t[@ast::expr]] args,
|
|
|
|
&ty::t closure_ty, &vec[ty::t] bound_tys,
|
2011-02-23 10:58:43 -08:00
|
|
|
uint ty_param_count) -> ValueRef {
|
2011-01-07 15:12:23 -08:00
|
|
|
// Construct a thunk-call with signature incoming_fty, and that copies
|
2011-05-12 17:24:54 +02:00
|
|
|
// args forward into a call to outgoing_fty:
|
2011-01-07 15:12:23 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
let str s =
|
|
|
|
mangle_internal_name_by_path_and_seq(cx.ccx, cx.path, "thunk");
|
|
|
|
let TypeRef llthunk_ty =
|
|
|
|
get_pair_fn_ty(type_of(cx.ccx, sp, incoming_fty));
|
|
|
|
let ValueRef llthunk =
|
|
|
|
decl_internal_fastcall_fn(cx.ccx.llmod, s, llthunk_ty);
|
2011-05-18 15:35:16 -07:00
|
|
|
auto fcx = new_fn_ctxt(cx, sp, llthunk);
|
2011-01-07 15:12:23 -08:00
|
|
|
auto bcx = new_top_block_ctxt(fcx);
|
2011-03-28 18:04:52 -07:00
|
|
|
auto lltop = bcx.llbb;
|
2011-04-20 18:52:04 -07:00
|
|
|
auto llclosure_ptr_ty =
|
2011-05-18 15:35:16 -07:00
|
|
|
type_of(cx.ccx, sp, ty::mk_imm_box(cx.ccx.tcx, closure_ty));
|
2011-03-07 18:13:39 -08:00
|
|
|
auto llclosure = bcx.build.PointerCast(fcx.llenv, llclosure_ptr_ty);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto lltarget =
|
|
|
|
GEP_tup_like(bcx, closure_ty, llclosure,
|
|
|
|
[0, abi::box_rc_field_body, abi::closure_elt_target]);
|
2011-03-07 18:13:39 -08:00
|
|
|
bcx = lltarget.bcx;
|
2011-06-15 11:19:50 -07:00
|
|
|
auto lltargetclosure =
|
|
|
|
bcx.build.GEP(lltarget.val, [C_int(0), C_int(abi::fn_field_box)]);
|
2011-01-07 15:12:23 -08:00
|
|
|
lltargetclosure = bcx.build.Load(lltargetclosure);
|
2011-05-12 17:24:54 +02:00
|
|
|
auto outgoing_ret_ty = ty::ty_fn_ret(cx.ccx.tcx, outgoing_fty);
|
|
|
|
auto outgoing_args = ty::ty_fn_args(cx.ccx.tcx, outgoing_fty);
|
2011-02-23 10:58:43 -08:00
|
|
|
auto llretptr = fcx.llretptr;
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_has_dynamic_size(cx.ccx.tcx, outgoing_ret_ty)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
llretptr = bcx.build.PointerCast(llretptr, T_typaram_ptr(cx.ccx.tn));
|
2011-02-23 10:58:43 -08:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
let vec[ValueRef] llargs = [llretptr, fcx.lltaskptr, lltargetclosure];
|
2011-02-23 10:58:43 -08:00
|
|
|
// Copy in the type parameters.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-02-23 10:58:43 -08:00
|
|
|
let uint i = 0u;
|
|
|
|
while (i < ty_param_count) {
|
|
|
|
auto lltyparam_ptr =
|
2011-03-07 18:13:39 -08:00
|
|
|
GEP_tup_like(bcx, closure_ty, llclosure,
|
2011-06-15 11:19:50 -07:00
|
|
|
[0, abi::box_rc_field_body,
|
|
|
|
abi::closure_elt_ty_params, i as int]);
|
2011-03-07 18:13:39 -08:00
|
|
|
bcx = lltyparam_ptr.bcx;
|
2011-04-28 11:24:16 -07:00
|
|
|
auto td = bcx.build.Load(lltyparam_ptr.val);
|
2011-05-16 18:21:22 -07:00
|
|
|
llargs += [td];
|
|
|
|
fcx.lltydescs += [td];
|
2011-02-23 10:58:43 -08:00
|
|
|
i += 1u;
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
let uint a = 3u; // retptr, task ptr, env come first
|
2011-02-23 10:58:43 -08:00
|
|
|
|
2011-01-07 15:12:23 -08:00
|
|
|
let int b = 0;
|
2011-02-23 10:58:43 -08:00
|
|
|
let uint outgoing_arg_index = 0u;
|
2011-03-08 16:31:37 -08:00
|
|
|
let vec[TypeRef] llout_arg_tys =
|
2011-05-18 15:35:16 -07:00
|
|
|
type_of_explicit_args(cx.ccx, sp, outgoing_args);
|
2011-05-12 17:24:54 +02:00
|
|
|
for (option::t[@ast::expr] arg in args) {
|
2011-03-08 16:31:37 -08:00
|
|
|
auto out_arg = outgoing_args.(outgoing_arg_index);
|
|
|
|
auto llout_arg_ty = llout_arg_tys.(outgoing_arg_index);
|
2011-01-07 15:12:23 -08:00
|
|
|
alt (arg) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (
|
|
|
|
// Arg provided at binding time; thunk copies it from
|
|
|
|
// closure.
|
|
|
|
some(?e)) {
|
2011-05-19 15:47:15 -07:00
|
|
|
auto e_ty = ty::expr_ty(cx.ccx.tcx, e);
|
2011-03-07 18:13:39 -08:00
|
|
|
auto bound_arg =
|
|
|
|
GEP_tup_like(bcx, closure_ty, llclosure,
|
2011-06-15 11:19:50 -07:00
|
|
|
[0, abi::box_rc_field_body,
|
|
|
|
abi::closure_elt_bindings, b]);
|
2011-03-07 18:13:39 -08:00
|
|
|
bcx = bound_arg.bcx;
|
2011-03-08 16:31:37 -08:00
|
|
|
auto val = bound_arg.val;
|
2011-05-12 17:24:54 +02:00
|
|
|
if (out_arg.mode == ty::mo_val) {
|
2011-04-28 11:24:16 -07:00
|
|
|
if (type_is_immediate(cx.ccx, e_ty)) {
|
|
|
|
val = bcx.build.Load(val);
|
|
|
|
bcx = take_ty(bcx, val, e_ty).bcx;
|
|
|
|
} else {
|
|
|
|
bcx = take_ty(bcx, val, e_ty).bcx;
|
|
|
|
val = bcx.build.Load(val);
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
} else if (ty::type_contains_params(cx.ccx.tcx, out_arg.ty)) {
|
2011-06-10 12:03:50 +02:00
|
|
|
assert (out_arg.mode != ty::mo_val);
|
2011-03-08 16:31:37 -08:00
|
|
|
val = bcx.build.PointerCast(val, llout_arg_ty);
|
|
|
|
}
|
2011-05-16 18:21:22 -07:00
|
|
|
llargs += [val];
|
2011-01-07 15:12:23 -08:00
|
|
|
b += 1;
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (
|
|
|
|
// Arg will be provided when the thunk is invoked.
|
|
|
|
none) {
|
2011-05-12 17:24:54 +02:00
|
|
|
let ValueRef passed_arg = llvm::LLVMGetParam(llthunk, a);
|
|
|
|
if (ty::type_contains_params(cx.ccx.tcx, out_arg.ty)) {
|
2011-06-10 12:03:50 +02:00
|
|
|
assert (out_arg.mode != ty::mo_val);
|
2011-06-15 11:19:50 -07:00
|
|
|
passed_arg =
|
|
|
|
bcx.build.PointerCast(passed_arg, llout_arg_ty);
|
2011-02-23 10:58:43 -08:00
|
|
|
}
|
2011-05-16 18:21:22 -07:00
|
|
|
llargs += [passed_arg];
|
2011-01-07 15:12:23 -08:00
|
|
|
a += 1u;
|
|
|
|
}
|
|
|
|
}
|
2011-03-10 15:09:41 -08:00
|
|
|
outgoing_arg_index += 1u;
|
2011-01-07 15:12:23 -08:00
|
|
|
}
|
|
|
|
// FIXME: turn this call + ret into a tail call.
|
2011-03-08 16:51:23 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto lltargetfn =
|
|
|
|
bcx.build.GEP(lltarget.val, [C_int(0), C_int(abi::fn_field_code)]);
|
2011-03-08 16:51:23 -08:00
|
|
|
// Cast the outgoing function to the appropriate type (see the comments in
|
|
|
|
// trans_bind below for why this is necessary).
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto lltargetty =
|
|
|
|
type_of_fn(bcx.fcx.lcx.ccx, sp,
|
|
|
|
ty::ty_fn_proto(bcx.fcx.lcx.ccx.tcx, outgoing_fty),
|
|
|
|
outgoing_args, outgoing_ret_ty, ty_param_count);
|
|
|
|
lltargetfn = bcx.build.PointerCast(lltargetfn, T_ptr(T_ptr(lltargetty)));
|
2011-01-07 15:12:23 -08:00
|
|
|
lltargetfn = bcx.build.Load(lltargetfn);
|
|
|
|
auto r = bcx.build.FastCall(lltargetfn, llargs);
|
2011-02-08 11:47:53 -08:00
|
|
|
bcx.build.RetVoid();
|
2011-05-11 11:56:49 -07:00
|
|
|
finish_fn(fcx, lltop);
|
2011-01-07 15:12:23 -08:00
|
|
|
ret llthunk;
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_bind(&@block_ctxt cx, &@ast::expr f,
|
2011-06-15 11:19:50 -07:00
|
|
|
&vec[option::t[@ast::expr]] args, &ast::ann ann) -> result {
|
2011-01-03 22:39:43 -08:00
|
|
|
auto f_res = trans_lval(cx, f);
|
|
|
|
if (f_res.is_mem) {
|
2011-04-17 14:24:45 +02:00
|
|
|
cx.fcx.lcx.ccx.sess.unimpl("re-binding existing function");
|
2011-01-03 22:39:43 -08:00
|
|
|
} else {
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[@ast::expr] bound = [];
|
2011-05-12 17:24:54 +02:00
|
|
|
for (option::t[@ast::expr] argopt in args) {
|
2011-01-05 16:06:01 -08:00
|
|
|
alt (argopt) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (none) { }
|
|
|
|
case (some(?e)) { vec::push[@ast::expr](bound, e); }
|
2011-01-05 16:06:01 -08:00
|
|
|
}
|
|
|
|
}
|
2011-02-23 10:58:43 -08:00
|
|
|
// Figure out which tydescs we need to pass, if any.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
let ty::t outgoing_fty;
|
2011-03-06 13:56:38 -05:00
|
|
|
let vec[ValueRef] lltydescs;
|
2011-02-23 10:58:43 -08:00
|
|
|
alt (f_res.generic) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (none) {
|
2011-05-19 15:47:15 -07:00
|
|
|
outgoing_fty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, f);
|
2011-05-16 18:21:22 -07:00
|
|
|
lltydescs = [];
|
2011-02-23 10:58:43 -08:00
|
|
|
}
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(?ginfo)) {
|
2011-05-12 15:42:12 -07:00
|
|
|
lazily_emit_all_generic_info_tydesc_glues(cx, ginfo);
|
2011-02-23 10:58:43 -08:00
|
|
|
outgoing_fty = ginfo.item_type;
|
|
|
|
lltydescs = ginfo.tydescs;
|
|
|
|
}
|
|
|
|
}
|
2011-05-17 20:41:41 +02:00
|
|
|
auto ty_param_count = vec::len[ValueRef](lltydescs);
|
|
|
|
if (vec::len[@ast::expr](bound) == 0u && ty_param_count == 0u) {
|
2011-01-05 16:06:01 -08:00
|
|
|
// Trivial 'binding': just return the static pair-ptr.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-01-05 16:06:01 -08:00
|
|
|
ret f_res.res;
|
|
|
|
} else {
|
|
|
|
auto bcx = f_res.res.bcx;
|
2011-05-18 15:35:16 -07:00
|
|
|
auto pair_t = node_type(cx.fcx.lcx.ccx, cx.sp, ann);
|
2011-03-28 18:04:52 -07:00
|
|
|
auto pair_v = alloca(bcx, pair_t);
|
2011-01-05 18:57:28 -08:00
|
|
|
// Translate the bound expressions.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ty::t] bound_tys = [];
|
|
|
|
let vec[ValueRef] bound_vals = [];
|
2011-02-23 10:58:43 -08:00
|
|
|
auto i = 0u;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (@ast::expr e in bound) {
|
2011-01-05 18:57:28 -08:00
|
|
|
auto arg = trans_expr(bcx, e);
|
|
|
|
bcx = arg.bcx;
|
2011-05-17 20:41:41 +02:00
|
|
|
vec::push[ValueRef](bound_vals, arg.val);
|
|
|
|
vec::push[ty::t](bound_tys,
|
2011-05-19 15:47:15 -07:00
|
|
|
ty::expr_ty(cx.fcx.lcx.ccx.tcx, e));
|
2011-02-23 10:58:43 -08:00
|
|
|
i += 1u;
|
2011-01-05 18:57:28 -08:00
|
|
|
}
|
|
|
|
// Synthesize a closure type.
|
2011-03-07 18:13:39 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
let ty::t bindings_ty =
|
|
|
|
ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, bound_tys);
|
2011-03-07 18:13:39 -08:00
|
|
|
// NB: keep this in sync with T_closure_ptr; we're making
|
2011-05-12 17:24:54 +02:00
|
|
|
// a ty::t structure that has the same "shape" as the LLVM type
|
2011-03-07 18:13:39 -08:00
|
|
|
// it constructs.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
let ty::t tydesc_ty = ty::mk_type(cx.fcx.lcx.ccx.tcx);
|
2011-05-12 17:24:54 +02:00
|
|
|
let vec[ty::t] captured_tys =
|
2011-05-17 20:41:41 +02:00
|
|
|
vec::init_elt[ty::t](tydesc_ty, ty_param_count);
|
2011-05-12 17:24:54 +02:00
|
|
|
let vec[ty::t] closure_tys =
|
2011-06-15 11:19:50 -07:00
|
|
|
[tydesc_ty, outgoing_fty, bindings_ty,
|
|
|
|
ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, captured_tys)];
|
|
|
|
let ty::t closure_ty =
|
|
|
|
ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, closure_tys);
|
2011-03-07 18:13:39 -08:00
|
|
|
auto r = trans_malloc_boxed(bcx, closure_ty);
|
2011-01-05 18:57:28 -08:00
|
|
|
auto box = r.val;
|
|
|
|
bcx = r.bcx;
|
2011-06-15 11:19:50 -07:00
|
|
|
auto rc =
|
2011-01-05 18:57:28 -08:00
|
|
|
bcx.build.GEP(box,
|
2011-06-15 11:19:50 -07:00
|
|
|
[C_int(0), C_int(abi::box_rc_field_refcnt)]);
|
|
|
|
auto closure =
|
|
|
|
bcx.build.GEP(box, [C_int(0), C_int(abi::box_rc_field_body)]);
|
2011-01-05 18:57:28 -08:00
|
|
|
bcx.build.Store(C_int(1), rc);
|
|
|
|
// Store bindings tydesc.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-01-05 18:57:28 -08:00
|
|
|
auto bound_tydesc =
|
|
|
|
bcx.build.GEP(closure,
|
2011-06-15 11:19:50 -07:00
|
|
|
[C_int(0), C_int(abi::closure_elt_tydesc)]);
|
2011-05-12 15:42:12 -07:00
|
|
|
auto ti = none[@tydesc_info];
|
|
|
|
auto bindings_tydesc = get_tydesc(bcx, bindings_ty, true, ti);
|
|
|
|
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
|
2011-05-18 17:28:08 -07:00
|
|
|
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
|
2011-01-31 15:03:05 -08:00
|
|
|
bcx = bindings_tydesc.bcx;
|
|
|
|
bcx.build.Store(bindings_tydesc.val, bound_tydesc);
|
2011-03-08 16:51:23 -08:00
|
|
|
// Determine the LLVM type for the outgoing function type. This
|
|
|
|
// may be different from the type returned by trans_malloc_boxed()
|
|
|
|
// since we have more information than that function does;
|
|
|
|
// specifically, we know how many type descriptors the outgoing
|
|
|
|
// function has, which type_of() doesn't, as only we know which
|
|
|
|
// item the function refers to.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llfnty =
|
|
|
|
type_of_fn(bcx.fcx.lcx.ccx, cx.sp,
|
|
|
|
ty::ty_fn_proto(bcx.fcx.lcx.ccx.tcx, outgoing_fty),
|
|
|
|
ty::ty_fn_args(bcx.fcx.lcx.ccx.tcx, outgoing_fty),
|
|
|
|
ty::ty_fn_ret(bcx.fcx.lcx.ccx.tcx, outgoing_fty),
|
|
|
|
ty_param_count);
|
|
|
|
auto llclosurety = T_ptr(T_fn_pair(bcx.fcx.lcx.ccx.tn, llfnty));
|
2011-01-06 12:55:27 -08:00
|
|
|
// Store thunk-target.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-01-06 12:55:27 -08:00
|
|
|
auto bound_target =
|
2011-01-05 18:57:28 -08:00
|
|
|
bcx.build.GEP(closure,
|
2011-06-15 11:19:50 -07:00
|
|
|
[C_int(0), C_int(abi::closure_elt_target)]);
|
2011-02-23 10:58:43 -08:00
|
|
|
auto src = bcx.build.Load(f_res.res.val);
|
2011-03-08 16:51:23 -08:00
|
|
|
bound_target = bcx.build.PointerCast(bound_target, llclosurety);
|
2011-02-23 10:58:43 -08:00
|
|
|
bcx.build.Store(src, bound_target);
|
2011-01-06 12:55:27 -08:00
|
|
|
// Copy expr values into boxed bindings.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-02-23 10:58:43 -08:00
|
|
|
i = 0u;
|
2011-01-06 12:55:27 -08:00
|
|
|
auto bindings =
|
|
|
|
bcx.build.GEP(closure,
|
2011-06-15 11:19:50 -07:00
|
|
|
[C_int(0), C_int(abi::closure_elt_bindings)]);
|
2011-01-05 18:57:28 -08:00
|
|
|
for (ValueRef v in bound_vals) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto bound =
|
|
|
|
bcx.build.GEP(bindings, [C_int(0), C_int(i as int)]);
|
2011-05-27 17:58:22 -07:00
|
|
|
bcx = copy_val(bcx, INIT, bound, v, bound_tys.(i)).bcx;
|
2011-02-23 10:58:43 -08:00
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
// If necessary, copy tydescs describing type parameters into the
|
|
|
|
// appropriate slot in the closure.
|
2011-05-12 15:42:12 -07:00
|
|
|
|
2011-02-23 10:58:43 -08:00
|
|
|
alt (f_res.generic) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (none) {/* nothing to do */ }
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(?ginfo)) {
|
2011-05-12 15:42:12 -07:00
|
|
|
lazily_emit_all_generic_info_tydesc_glues(cx, ginfo);
|
2011-02-23 10:58:43 -08:00
|
|
|
auto ty_params_slot =
|
|
|
|
bcx.build.GEP(closure,
|
2011-05-16 18:21:22 -07:00
|
|
|
[C_int(0),
|
2011-06-15 11:19:50 -07:00
|
|
|
C_int(abi::closure_elt_ty_params)]);
|
2011-02-23 10:58:43 -08:00
|
|
|
auto i = 0;
|
|
|
|
for (ValueRef td in ginfo.tydescs) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto ty_param_slot =
|
|
|
|
bcx.build.GEP(ty_params_slot,
|
|
|
|
[C_int(0), C_int(i)]);
|
2011-02-23 10:58:43 -08:00
|
|
|
bcx.build.Store(td, ty_param_slot);
|
|
|
|
i += 1;
|
|
|
|
}
|
2011-03-10 15:14:45 -08:00
|
|
|
outgoing_fty = ginfo.item_type;
|
2011-02-23 10:58:43 -08:00
|
|
|
}
|
2011-01-05 18:57:28 -08:00
|
|
|
}
|
2011-01-07 15:12:23 -08:00
|
|
|
// Make thunk and store thunk-ptr in outer pair's code slot.
|
2011-01-07 16:26:30 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto pair_code =
|
|
|
|
bcx.build.GEP(pair_v, [C_int(0), C_int(abi::fn_field_code)]);
|
2011-05-12 17:24:54 +02:00
|
|
|
let ty::t pair_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
|
2011-01-07 15:12:23 -08:00
|
|
|
let ValueRef llthunk =
|
2011-05-18 15:35:16 -07:00
|
|
|
trans_bind_thunk(cx.fcx.lcx, cx.sp, pair_ty, outgoing_fty,
|
2011-06-15 11:19:50 -07:00
|
|
|
args, closure_ty, bound_tys, ty_param_count);
|
2011-01-07 15:12:23 -08:00
|
|
|
bcx.build.Store(llthunk, pair_code);
|
|
|
|
// Store box ptr in outer pair's box slot.
|
2011-01-05 18:57:28 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto tn = bcx.fcx.lcx.ccx.tn;
|
|
|
|
auto pair_box =
|
|
|
|
bcx.build.GEP(pair_v, [C_int(0), C_int(abi::fn_field_box)]);
|
|
|
|
bcx.build.Store(bcx.build.PointerCast(box,
|
|
|
|
T_opaque_closure_ptr(tn)),
|
|
|
|
pair_box);
|
2011-01-07 16:26:30 -08:00
|
|
|
find_scope_cx(cx).cleanups +=
|
2011-05-16 18:21:22 -07:00
|
|
|
[clean(bind drop_slot(_, pair_v, pair_ty))];
|
2011-01-05 16:06:01 -08:00
|
|
|
ret res(bcx, pair_v);
|
|
|
|
}
|
2011-01-03 22:39:43 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_arg_expr(&@block_ctxt cx, &ty::arg arg, TypeRef lldestty0,
|
2011-05-12 17:24:54 +02:00
|
|
|
&@ast::expr e) -> result {
|
2011-04-23 14:17:44 -07:00
|
|
|
auto val;
|
|
|
|
auto bcx = cx;
|
2011-05-19 15:47:15 -07:00
|
|
|
auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, e_ty)) {
|
2011-04-23 14:17:44 -07:00
|
|
|
auto re = trans_expr(bcx, e);
|
|
|
|
val = re.val;
|
|
|
|
bcx = re.bcx;
|
2011-06-10 12:03:50 +02:00
|
|
|
} else if (arg.mode != ty::mo_val) {
|
2011-04-23 14:17:44 -07:00
|
|
|
let lval_result lv;
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::is_lval(e)) {
|
2011-04-23 14:17:44 -07:00
|
|
|
lv = trans_lval(bcx, e);
|
|
|
|
} else {
|
|
|
|
auto r = trans_expr(bcx, e);
|
|
|
|
if (type_is_immediate(cx.fcx.lcx.ccx, e_ty)) {
|
|
|
|
lv = lval_val(r.bcx, r.val);
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { lv = lval_mem(r.bcx, r.val); }
|
2011-04-23 14:17:44 -07:00
|
|
|
}
|
|
|
|
bcx = lv.res.bcx;
|
|
|
|
if (lv.is_mem) {
|
|
|
|
val = lv.res.val;
|
|
|
|
} else {
|
|
|
|
// Non-mem but we're trying to alias; synthesize an
|
|
|
|
// alloca, spill to it and pass its address.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-23 14:17:44 -07:00
|
|
|
val = do_spill(lv.res.bcx, lv.res.val);
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { auto re = trans_expr(bcx, e); val = re.val; bcx = re.bcx; }
|
|
|
|
if (arg.mode == ty::mo_val) { bcx = take_ty(bcx, val, e_ty).bcx; }
|
2011-06-02 17:50:37 -07:00
|
|
|
if (ty::type_is_bot(cx.fcx.lcx.ccx.tcx, e_ty)) {
|
|
|
|
// For values of type _|_, we generate an
|
|
|
|
// "undef" value, as such a value should never
|
|
|
|
// be inspected. It's important for the value
|
|
|
|
// to have type lldestty0 (the callee's expected type).
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-02 17:50:37 -07:00
|
|
|
val = llvm::LLVMGetUndef(lldestty0);
|
2011-06-15 11:19:50 -07:00
|
|
|
} else if (ty::type_contains_params(cx.fcx.lcx.ccx.tcx, arg.ty)) {
|
2011-04-23 14:17:44 -07:00
|
|
|
auto lldestty = lldestty0;
|
2011-05-12 17:24:54 +02:00
|
|
|
if (arg.mode == ty::mo_val) {
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-23 14:17:44 -07:00
|
|
|
// FIXME: we'd prefer to use &&, but rustboot doesn't like it
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, e_ty)) {
|
2011-04-23 14:17:44 -07:00
|
|
|
lldestty = T_ptr(lldestty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
val = bcx.build.PointerCast(val, lldestty);
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
if (arg.mode == ty::mo_val) {
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-23 14:17:44 -07:00
|
|
|
// FIXME: we'd prefer to use &&, but rustboot doesn't like it
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, e_ty)) {
|
2011-04-23 14:17:44 -07:00
|
|
|
// Until here we've been treating structures by pointer;
|
|
|
|
// we are now passing it as an arg, so need to load it.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-23 14:17:44 -07:00
|
|
|
val = bcx.build.Load(val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret res(bcx, val);
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-02-08 11:47:53 -08:00
|
|
|
// NB: must keep 4 fns in sync:
|
|
|
|
//
|
|
|
|
// - type_of_fn_full
|
|
|
|
// - create_llargs_for_fn_args.
|
|
|
|
// - new_fn_ctxt
|
|
|
|
// - trans_args
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_args(&@block_ctxt cx, ValueRef llenv, &option::t[ValueRef] llobj,
|
|
|
|
&option::t[generic_info] gen, &option::t[ValueRef] lliterbody,
|
|
|
|
&vec[@ast::expr] es, &ty::t fn_ty) ->
|
|
|
|
tup(@block_ctxt, vec[ValueRef], ValueRef) {
|
2011-05-12 17:24:54 +02:00
|
|
|
let vec[ty::arg] args = ty::ty_fn_args(cx.fcx.lcx.ccx.tcx, fn_ty);
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ValueRef] llargs = [];
|
|
|
|
let vec[ValueRef] lltydescs = [];
|
2011-02-08 11:47:53 -08:00
|
|
|
let @block_ctxt bcx = cx;
|
|
|
|
// Arg 0: Output pointer.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
auto retty = ty::ty_fn_ret(cx.fcx.lcx.ccx.tcx, fn_ty);
|
2011-02-10 15:00:16 -08:00
|
|
|
auto llretslot_res = alloc_ty(bcx, retty);
|
|
|
|
bcx = llretslot_res.bcx;
|
|
|
|
auto llretslot = llretslot_res.val;
|
2011-02-08 11:47:53 -08:00
|
|
|
alt (gen) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(?g)) {
|
2011-05-12 15:42:12 -07:00
|
|
|
lazily_emit_all_generic_info_tydesc_glues(cx, g);
|
2011-02-08 11:47:53 -08:00
|
|
|
lltydescs = g.tydescs;
|
2011-05-12 17:24:54 +02:00
|
|
|
args = ty::ty_fn_args(cx.fcx.lcx.ccx.tcx, g.item_type);
|
|
|
|
retty = ty::ty_fn_ret(cx.fcx.lcx.ccx.tcx, g.item_type);
|
2011-02-08 11:47:53 -08:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { }
|
2011-02-08 11:47:53 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, retty)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
llargs +=
|
|
|
|
[bcx.build.PointerCast(llretslot,
|
|
|
|
T_typaram_ptr(cx.fcx.lcx.ccx.tn))];
|
2011-05-12 17:24:54 +02:00
|
|
|
} else if (ty::type_contains_params(cx.fcx.lcx.ccx.tcx, retty)) {
|
2011-02-08 17:05:53 -08:00
|
|
|
// It's possible that the callee has some generic-ness somewhere in
|
|
|
|
// its return value -- say a method signature within an obj or a fn
|
|
|
|
// type deep in a structure -- which the caller has a concrete view
|
|
|
|
// of. If so, cast the caller's view of the restlot to the callee's
|
|
|
|
// view, for the sake of making a type-compatible call.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-16 14:58:02 -07:00
|
|
|
llargs +=
|
2011-05-16 18:21:22 -07:00
|
|
|
[cx.build.PointerCast(llretslot,
|
2011-06-15 11:19:50 -07:00
|
|
|
T_ptr(type_of(bcx.fcx.lcx.ccx, bcx.sp,
|
|
|
|
retty)))];
|
|
|
|
} else { llargs += [llretslot]; }
|
2011-05-12 17:24:54 +02:00
|
|
|
// Arg 1: task pointer.
|
2011-02-08 11:47:53 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
llargs += [bcx.fcx.lltaskptr];
|
2011-02-08 11:47:53 -08:00
|
|
|
// Arg 2: Env (closure-bindings / self-obj)
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-02-08 11:47:53 -08:00
|
|
|
alt (llobj) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(?ob)) {
|
2011-02-08 11:47:53 -08:00
|
|
|
// Every object is always found in memory,
|
|
|
|
// and not-yet-loaded (as part of an lval x.y
|
|
|
|
// doted method-call).
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-16 18:21:22 -07:00
|
|
|
llargs += [bcx.build.Load(ob)];
|
2011-02-08 11:47:53 -08:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { llargs += [llenv]; }
|
2011-02-08 11:47:53 -08:00
|
|
|
}
|
|
|
|
// Args >3: ty_params ...
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
llargs += lltydescs;
|
2011-02-18 17:30:57 -08:00
|
|
|
// ... then possibly an lliterbody argument.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-02-18 17:30:57 -08:00
|
|
|
alt (lliterbody) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (none) { }
|
|
|
|
case (some(?lli)) { llargs += [lli]; }
|
2011-02-18 17:30:57 -08:00
|
|
|
}
|
2011-02-08 11:47:53 -08:00
|
|
|
// ... then explicit args.
|
2011-02-24 13:51:53 -08:00
|
|
|
|
|
|
|
// First we figure out the caller's view of the types of the arguments.
|
|
|
|
// This will be needed if this is a generic call, because the callee has
|
|
|
|
// to cast her view of the arguments to the caller's view.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto arg_tys = type_of_explicit_args(cx.fcx.lcx.ccx, cx.sp, args);
|
2011-02-08 11:47:53 -08:00
|
|
|
auto i = 0u;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (@ast::expr e in es) {
|
2011-04-23 14:17:44 -07:00
|
|
|
auto r = trans_arg_expr(bcx, args.(i), arg_tys.(i), e);
|
|
|
|
bcx = r.bcx;
|
2011-05-16 18:21:22 -07:00
|
|
|
llargs += [r.val];
|
2011-02-08 11:47:53 -08:00
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
ret tup(bcx, llargs, llretslot);
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_call(&@block_ctxt cx, &@ast::expr f, &option::t[ValueRef] lliterbody,
|
|
|
|
&vec[@ast::expr] args, &ast::ann ann) -> result {
|
2011-04-05 16:17:47 -07:00
|
|
|
// NB: 'f' isn't necessarily a function; it might be an entire self-call
|
|
|
|
// expression because of the hack that allows us to process self-calls
|
|
|
|
// with trans_call.
|
|
|
|
|
2010-11-24 10:36:46 -08:00
|
|
|
auto f_res = trans_lval(cx, f);
|
2010-12-23 17:31:16 -08:00
|
|
|
auto faddr = f_res.res.val;
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llenv = C_null(T_opaque_closure_ptr(cx.fcx.lcx.ccx.tn));
|
2011-01-05 15:31:35 -08:00
|
|
|
alt (f_res.llobj) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(_)) {
|
2011-01-05 15:31:35 -08:00
|
|
|
// It's a vtbl entry.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-01-05 15:31:35 -08:00
|
|
|
faddr = f_res.res.bcx.build.Load(faddr);
|
|
|
|
}
|
2011-05-31 00:39:19 -04:00
|
|
|
case (none) {
|
2011-01-05 15:31:35 -08:00
|
|
|
// It's a closure.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-01-05 15:31:35 -08:00
|
|
|
auto bcx = f_res.res.bcx;
|
2011-01-07 15:12:23 -08:00
|
|
|
auto pair = faddr;
|
2011-06-15 11:19:50 -07:00
|
|
|
faddr =
|
|
|
|
bcx.build.GEP(pair, [C_int(0), C_int(abi::fn_field_code)]);
|
2011-01-05 15:31:35 -08:00
|
|
|
faddr = bcx.build.Load(faddr);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llclosure =
|
|
|
|
bcx.build.GEP(pair, [C_int(0), C_int(abi::fn_field_box)]);
|
2011-02-08 11:47:53 -08:00
|
|
|
llenv = bcx.build.Load(llclosure);
|
2011-01-03 22:39:43 -08:00
|
|
|
}
|
2010-12-20 16:48:28 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
let ty::t fn_ty;
|
2011-04-05 16:17:47 -07:00
|
|
|
alt (f_res.method_ty) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(?meth)) {
|
2011-04-05 16:17:47 -07:00
|
|
|
// self-call
|
2011-04-12 12:06:20 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn_ty = meth;
|
2011-03-31 11:26:25 -07:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { fn_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, f); }
|
2011-03-31 11:26:25 -07:00
|
|
|
}
|
2011-06-07 13:50:30 -07:00
|
|
|
auto ret_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto args_res =
|
|
|
|
trans_args(f_res.res.bcx, llenv, f_res.llobj, f_res.generic,
|
|
|
|
lliterbody, args, fn_ty);
|
2011-03-31 11:26:25 -07:00
|
|
|
auto bcx = args_res._0;
|
|
|
|
auto llargs = args_res._1;
|
|
|
|
auto llretslot = args_res._2;
|
|
|
|
/*
|
2011-04-17 14:24:45 +02:00
|
|
|
log "calling: " + val_str(cx.fcx.lcx.ccx.tn, faddr);
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-01 16:04:22 -07:00
|
|
|
for (ValueRef arg in llargs) {
|
2011-04-17 14:24:45 +02:00
|
|
|
log "arg: " + val_str(cx.fcx.lcx.ccx.tn, arg);
|
2011-04-01 16:04:22 -07:00
|
|
|
}
|
2011-03-31 11:26:25 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
bcx.build.FastCall(faddr, llargs);
|
|
|
|
auto retval = C_nil();
|
2011-04-23 14:17:44 -07:00
|
|
|
alt (lliterbody) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (none) {
|
2011-05-12 17:24:54 +02:00
|
|
|
if (!ty::type_is_nil(cx.fcx.lcx.ccx.tcx, ret_ty)) {
|
2011-04-23 14:17:44 -07:00
|
|
|
retval = load_if_immediate(bcx, llretslot, ret_ty);
|
|
|
|
// Retval doesn't correspond to anything really tangible in
|
|
|
|
// the frame, but it's a ref all the same, so we put a note
|
|
|
|
// here to drop it when we're done in this scope.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-23 14:17:44 -07:00
|
|
|
find_scope_cx(cx).cleanups +=
|
2011-05-16 18:21:22 -07:00
|
|
|
[clean(bind drop_ty(_, retval, ret_ty))];
|
2011-04-23 14:17:44 -07:00
|
|
|
}
|
|
|
|
}
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(_)) {
|
2011-04-23 14:17:44 -07:00
|
|
|
// If there was an lliterbody, it means we were calling an
|
|
|
|
// iter, and we are *not* the party using its 'output' value,
|
|
|
|
// we should ignore llretslot.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-23 14:17:44 -07:00
|
|
|
}
|
2011-03-31 11:26:25 -07:00
|
|
|
}
|
|
|
|
ret res(bcx, retval);
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_tup(&@block_ctxt cx, &vec[ast::elt] elts, &ast::ann ann) -> result {
|
2011-02-10 15:00:16 -08:00
|
|
|
auto bcx = cx;
|
2011-04-17 14:24:45 +02:00
|
|
|
auto t = node_ann_type(bcx.fcx.lcx.ccx, ann);
|
2011-02-10 15:00:16 -08:00
|
|
|
auto tup_res = alloc_ty(bcx, t);
|
|
|
|
auto tup_val = tup_res.val;
|
|
|
|
bcx = tup_res.bcx;
|
2011-06-15 11:19:50 -07:00
|
|
|
find_scope_cx(cx).cleanups += [clean(bind drop_ty(_, tup_val, t))];
|
2010-11-24 18:10:52 -08:00
|
|
|
let int i = 0;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ast::elt e in elts) {
|
2011-05-19 15:47:15 -07:00
|
|
|
auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e.expr);
|
2011-02-10 15:00:16 -08:00
|
|
|
auto src_res = trans_expr(bcx, e.expr);
|
|
|
|
bcx = src_res.bcx;
|
2011-05-16 18:21:22 -07:00
|
|
|
auto dst_res = GEP_tup_like(bcx, t, tup_val, [0, i]);
|
2011-02-10 15:00:16 -08:00
|
|
|
bcx = dst_res.bcx;
|
2011-05-27 17:58:22 -07:00
|
|
|
bcx = copy_val(src_res.bcx, INIT, dst_res.val, src_res.val, e_ty).bcx;
|
2010-11-24 18:10:52 -08:00
|
|
|
i += 1;
|
|
|
|
}
|
2011-02-10 15:00:16 -08:00
|
|
|
ret res(bcx, tup_val);
|
2010-11-24 18:10:52 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_vec(&@block_ctxt cx, &vec[@ast::expr] args, &ast::ann ann) ->
|
|
|
|
result {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
|
2010-12-21 12:13:51 -08:00
|
|
|
auto unit_ty = t;
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_vec(?mt)) { unit_ty = mt.ty; }
|
|
|
|
case (_) { cx.fcx.lcx.ccx.sess.bug("non-vec type in trans_vec"); }
|
2010-12-10 17:25:11 -08:00
|
|
|
}
|
2011-01-31 15:03:05 -08:00
|
|
|
auto bcx = cx;
|
|
|
|
auto unit_sz = size_of(bcx, unit_ty);
|
|
|
|
bcx = unit_sz.bcx;
|
2011-06-15 11:19:50 -07:00
|
|
|
auto data_sz =
|
|
|
|
bcx.build.Mul(C_int(vec::len[@ast::expr](args) as int), unit_sz.val);
|
2010-12-10 17:25:11 -08:00
|
|
|
// FIXME: pass tydesc properly.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
auto vec_val =
|
|
|
|
bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.new_vec,
|
|
|
|
[bcx.fcx.lltaskptr, data_sz,
|
|
|
|
C_null(T_ptr(T_tydesc(bcx.fcx.lcx.ccx.tn)))]);
|
2011-05-18 15:35:16 -07:00
|
|
|
auto llty = type_of(bcx.fcx.lcx.ccx, bcx.sp, t);
|
2011-05-10 14:03:47 -07:00
|
|
|
vec_val = bcx.build.PointerCast(vec_val, llty);
|
2011-06-15 11:19:50 -07:00
|
|
|
find_scope_cx(bcx).cleanups += [clean(bind drop_ty(_, vec_val, t))];
|
|
|
|
auto body = bcx.build.GEP(vec_val, [C_int(0), C_int(abi::vec_elt_data)]);
|
2011-02-10 15:00:16 -08:00
|
|
|
auto pseudo_tup_ty =
|
2011-05-12 17:24:54 +02:00
|
|
|
ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx,
|
2011-06-15 11:19:50 -07:00
|
|
|
vec::init_elt[ty::t](unit_ty,
|
|
|
|
vec::len[@ast::expr](args)));
|
2010-12-10 17:25:11 -08:00
|
|
|
let int i = 0;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (@ast::expr e in args) {
|
2011-02-10 15:00:16 -08:00
|
|
|
auto src_res = trans_expr(bcx, e);
|
|
|
|
bcx = src_res.bcx;
|
2011-05-16 18:21:22 -07:00
|
|
|
auto dst_res = GEP_tup_like(bcx, pseudo_tup_ty, body, [0, i]);
|
2011-02-10 15:00:16 -08:00
|
|
|
bcx = dst_res.bcx;
|
2011-03-10 10:40:44 -08:00
|
|
|
// Cast the destination type to the source type. This is needed to
|
|
|
|
// make tags work, for a subtle combination of reasons:
|
|
|
|
//
|
|
|
|
// (1) "dst_res" above is derived from "body", which is in turn
|
|
|
|
// derived from "vec_val".
|
|
|
|
// (2) "vec_val" has the LLVM type "llty".
|
|
|
|
// (3) "llty" is the result of calling type_of() on a vector type.
|
|
|
|
// (4) For tags, type_of() returns a different type depending on
|
|
|
|
// on whether the tag is behind a box or not. Vector types are
|
|
|
|
// considered boxes.
|
|
|
|
// (5) "src_res" is derived from "unit_ty", which is not behind a box.
|
|
|
|
|
|
|
|
auto dst_val;
|
2011-05-12 17:24:54 +02:00
|
|
|
if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, unit_ty)) {
|
2011-05-18 15:35:16 -07:00
|
|
|
auto llunit_ty = type_of(cx.fcx.lcx.ccx, bcx.sp, unit_ty);
|
2011-03-10 10:40:44 -08:00
|
|
|
dst_val = bcx.build.PointerCast(dst_res.val, T_ptr(llunit_ty));
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { dst_val = dst_res.val; }
|
2011-05-27 17:58:22 -07:00
|
|
|
bcx = copy_val(bcx, INIT, dst_val, src_res.val, unit_ty).bcx;
|
2010-12-10 17:25:11 -08:00
|
|
|
i += 1;
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
auto fill = bcx.build.GEP(vec_val, [C_int(0), C_int(abi::vec_elt_fill)]);
|
2011-02-10 15:00:16 -08:00
|
|
|
bcx.build.Store(data_sz, fill);
|
|
|
|
ret res(bcx, vec_val);
|
2010-12-10 17:25:11 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_ivec(@block_ctxt bcx, &vec[@ast::expr] args, &ast::ann ann) ->
|
|
|
|
result {
|
2011-06-10 19:35:59 -07:00
|
|
|
auto typ = node_ann_type(bcx.fcx.lcx.ccx, ann);
|
|
|
|
auto unit_ty;
|
|
|
|
alt (ty::struct(bcx.fcx.lcx.ccx.tcx, typ)) {
|
|
|
|
case (ty::ty_ivec(?mt)) { unit_ty = mt.ty; }
|
|
|
|
case (_) { bcx.fcx.lcx.ccx.sess.bug("non-ivec type in trans_ivec"); }
|
|
|
|
}
|
|
|
|
auto rslt = size_of(bcx, unit_ty);
|
|
|
|
auto unit_sz = rslt.val;
|
|
|
|
bcx = rslt.bcx;
|
2011-06-14 18:22:36 -07:00
|
|
|
auto llalen = bcx.build.Mul(unit_sz, C_uint(abi::ivec_default_length));
|
2011-06-10 19:35:59 -07:00
|
|
|
auto llunitty = type_of_or_i8(bcx, unit_ty);
|
2011-06-12 00:44:43 -07:00
|
|
|
auto llvecptr;
|
|
|
|
if (ty::type_has_dynamic_size(bcx.fcx.lcx.ccx.tcx, unit_ty)) {
|
2011-06-14 11:54:09 -07:00
|
|
|
auto array_size = bcx.build.Add(llsize_of(T_opaque_ivec()), llalen);
|
|
|
|
llvecptr = array_alloca(bcx, T_i8(), array_size);
|
|
|
|
llvecptr = bcx.build.PointerCast(llvecptr, T_ptr(T_opaque_ivec()));
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { llvecptr = alloca(bcx, T_ivec(llunitty)); }
|
2011-06-10 19:35:59 -07:00
|
|
|
auto lllen = bcx.build.Mul(C_uint(vec::len(args)), unit_sz);
|
|
|
|
// Allocate the vector pieces and store length and allocated length.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-10 19:35:59 -07:00
|
|
|
auto llfirsteltptr;
|
2011-06-14 11:54:09 -07:00
|
|
|
if (vec::len(args) > 0u && vec::len(args) < abi::ivec_default_length) {
|
2011-06-10 19:35:59 -07:00
|
|
|
// Interior case.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
bcx.build.Store(lllen,
|
|
|
|
bcx.build.InBoundsGEP(llvecptr,
|
|
|
|
[C_int(0),
|
|
|
|
C_uint(abi::ivec_elt_len)]));
|
|
|
|
bcx.build.Store(llalen,
|
|
|
|
bcx.build.InBoundsGEP(llvecptr,
|
|
|
|
[C_int(0),
|
|
|
|
C_uint(abi::ivec_elt_alen)]));
|
|
|
|
llfirsteltptr =
|
|
|
|
bcx.build.InBoundsGEP(llvecptr,
|
|
|
|
[C_int(0), C_uint(abi::ivec_elt_elems),
|
|
|
|
C_int(0)]);
|
2011-06-10 19:35:59 -07:00
|
|
|
} else {
|
|
|
|
// Heap case.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
|
|
|
|
auto stub_z = [C_int(0), C_uint(abi::ivec_heap_stub_elt_zero)];
|
|
|
|
auto stub_a = [C_int(0), C_uint(abi::ivec_heap_stub_elt_alen)];
|
|
|
|
auto stub_p = [C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)];
|
|
|
|
|
2011-06-10 19:35:59 -07:00
|
|
|
auto llstubty = T_ivec_heap(llunitty);
|
|
|
|
auto llstubptr = bcx.build.PointerCast(llvecptr, T_ptr(llstubty));
|
2011-06-15 11:19:50 -07:00
|
|
|
bcx.build.Store(C_int(0),
|
|
|
|
bcx.build.InBoundsGEP(llstubptr, stub_z));
|
2011-06-13 18:52:04 -07:00
|
|
|
bcx.build.Store(lllen,
|
2011-06-15 11:19:50 -07:00
|
|
|
bcx.build.InBoundsGEP(llstubptr, stub_a));
|
2011-06-10 19:35:59 -07:00
|
|
|
auto llheapty = struct_elt(llstubty, abi::ivec_heap_stub_elt_ptr);
|
|
|
|
if (vec::len(args) == 0u) {
|
|
|
|
// Null heap pointer indicates a zero-length vector.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-13 18:52:04 -07:00
|
|
|
bcx.build.Store(C_null(T_ptr(llheapty)),
|
2011-06-15 11:19:50 -07:00
|
|
|
bcx.build.InBoundsGEP(llstubptr, stub_p));
|
2011-06-10 19:35:59 -07:00
|
|
|
llfirsteltptr = C_null(T_ptr(llunitty));
|
|
|
|
} else {
|
|
|
|
auto llheapsz = bcx.build.Add(llsize_of(llheapty), lllen);
|
2011-06-14 14:33:19 -07:00
|
|
|
rslt = trans_raw_malloc(bcx, T_ptr(llheapty), llheapsz);
|
2011-06-10 19:35:59 -07:00
|
|
|
bcx = rslt.bcx;
|
|
|
|
auto llheapptr = rslt.val;
|
2011-06-15 11:19:50 -07:00
|
|
|
bcx.build.Store(llheapptr,
|
|
|
|
bcx.build.InBoundsGEP(llstubptr, stub_p));
|
|
|
|
auto heap_l = [C_uint(abi::ivec_heap_elt_len)];
|
|
|
|
bcx.build.Store(lllen,
|
|
|
|
bcx.build.InBoundsGEP(llheapptr, heap_l));
|
|
|
|
llfirsteltptr =
|
|
|
|
bcx.build.InBoundsGEP(llheapptr,
|
|
|
|
[C_int(0),
|
|
|
|
C_uint(abi::ivec_heap_elt_elems),
|
|
|
|
C_int(0)]);
|
2011-06-10 19:35:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Store the individual elements.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-10 19:35:59 -07:00
|
|
|
auto i = 0u;
|
|
|
|
for (@ast::expr e in args) {
|
|
|
|
rslt = trans_expr(bcx, e);
|
|
|
|
bcx = rslt.bcx;
|
|
|
|
auto llsrc = rslt.val;
|
|
|
|
auto lleltptr;
|
|
|
|
if (ty::type_has_dynamic_size(bcx.fcx.lcx.ccx.tcx, unit_ty)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
lleltptr =
|
|
|
|
bcx.build.InBoundsGEP(llfirsteltptr,
|
|
|
|
[bcx.build.Mul(C_uint(i), unit_sz)]);
|
2011-06-10 19:35:59 -07:00
|
|
|
} else {
|
2011-06-12 00:44:43 -07:00
|
|
|
lleltptr = bcx.build.InBoundsGEP(llfirsteltptr, [C_uint(i)]);
|
2011-06-10 19:35:59 -07:00
|
|
|
}
|
|
|
|
bcx = copy_val(bcx, INIT, lleltptr, llsrc, unit_ty).bcx;
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
ret res(bcx, llvecptr);
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_rec(&@block_ctxt cx, &vec[ast::field] fields,
|
|
|
|
&option::t[@ast::expr] base, &ast::ann ann) -> result {
|
2011-02-10 15:00:16 -08:00
|
|
|
auto bcx = cx;
|
2011-04-17 14:24:45 +02:00
|
|
|
auto t = node_ann_type(bcx.fcx.lcx.ccx, ann);
|
2011-02-10 15:00:16 -08:00
|
|
|
auto rec_res = alloc_ty(bcx, t);
|
|
|
|
auto rec_val = rec_res.val;
|
|
|
|
bcx = rec_res.bcx;
|
2011-06-15 11:19:50 -07:00
|
|
|
find_scope_cx(cx).cleanups += [clean(bind drop_ty(_, rec_val, t))];
|
2010-11-30 10:39:35 -08:00
|
|
|
let int i = 0;
|
2011-02-15 18:16:13 -08:00
|
|
|
auto base_val = C_nil();
|
|
|
|
alt (base) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (none) { }
|
|
|
|
case (some(?bexp)) {
|
2011-02-15 18:16:13 -08:00
|
|
|
auto base_res = trans_expr(bcx, bexp);
|
|
|
|
bcx = base_res.bcx;
|
|
|
|
base_val = base_res.val;
|
|
|
|
}
|
|
|
|
}
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ty::field] ty_fields = [];
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
|
|
|
|
case (ty::ty_rec(?flds)) { ty_fields = flds; }
|
2011-02-15 18:16:13 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ty::field tf in ty_fields) {
|
2011-03-17 17:39:47 -07:00
|
|
|
auto e_ty = tf.mt.ty;
|
2011-05-16 18:21:22 -07:00
|
|
|
auto dst_res = GEP_tup_like(bcx, t, rec_val, [0, i]);
|
2011-02-10 15:00:16 -08:00
|
|
|
bcx = dst_res.bcx;
|
2011-02-15 18:16:13 -08:00
|
|
|
auto expr_provided = false;
|
|
|
|
auto src_res = res(bcx, C_nil());
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ast::field f in fields) {
|
2011-05-30 15:56:01 -07:00
|
|
|
if (str::eq(f.node.ident, tf.ident)) {
|
2011-02-15 18:16:13 -08:00
|
|
|
expr_provided = true;
|
2011-05-30 15:56:01 -07:00
|
|
|
src_res = trans_expr(bcx, f.node.expr);
|
2011-02-15 18:16:13 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!expr_provided) {
|
2011-05-16 18:21:22 -07:00
|
|
|
src_res = GEP_tup_like(bcx, t, base_val, [0, i]);
|
2011-06-15 11:19:50 -07:00
|
|
|
src_res =
|
|
|
|
res(src_res.bcx, load_if_immediate(bcx, src_res.val, e_ty));
|
2011-02-15 18:16:13 -08:00
|
|
|
}
|
|
|
|
bcx = src_res.bcx;
|
2011-05-27 17:58:22 -07:00
|
|
|
bcx = copy_val(bcx, INIT, dst_res.val, src_res.val, e_ty).bcx;
|
2010-11-30 10:39:35 -08:00
|
|
|
i += 1;
|
|
|
|
}
|
2011-02-10 15:00:16 -08:00
|
|
|
ret res(bcx, rec_val);
|
2010-11-30 10:39:35 -08:00
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_expr(&@block_ctxt cx, &@ast::expr e) -> result {
|
2011-06-15 12:17:51 +02:00
|
|
|
ret trans_expr_out(cx, e, return);
|
2011-05-31 14:24:04 +02:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_expr_out(&@block_ctxt cx, &@ast::expr e, out_method output) ->
|
|
|
|
result {
|
2011-06-15 12:17:51 +02:00
|
|
|
// FIXME Fill in cx.sp
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-10-05 18:21:44 -07:00
|
|
|
alt (e.node) {
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_lit(?lit, ?ann)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
ret res(cx, trans_lit(cx.fcx.lcx.ccx, *lit, ann));
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_unary(?op, ?x, ?ann)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
if (op != ast::deref) { ret trans_unary(cx, op, x, ann); }
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_binary(?op, ?x, ?y, _)) {
|
2010-11-26 15:54:04 -08:00
|
|
|
ret trans_binary(cx, op, x, y);
|
2010-09-28 12:23:40 -07:00
|
|
|
}
|
2011-05-21 14:07:44 -04:00
|
|
|
case (ast::expr_if(?cond, ?thn, ?els, ?ann)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret with_out_method(bind trans_if(cx, cond, thn, els, ann, _), cx,
|
|
|
|
ann, output);
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_for(?decl, ?seq, ?body, _)) {
|
2011-01-21 07:59:06 -08:00
|
|
|
ret trans_for(cx, decl, seq, body);
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_for_each(?decl, ?seq, ?body, _)) {
|
2011-02-14 18:17:31 -08:00
|
|
|
ret trans_for_each(cx, decl, seq, body);
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_while(?cond, ?body, _)) {
|
2010-11-26 15:54:04 -08:00
|
|
|
ret trans_while(cx, cond, body);
|
2010-11-03 11:05:15 -07:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_do_while(?body, ?cond, _)) {
|
2010-11-26 15:54:04 -08:00
|
|
|
ret trans_do_while(cx, body, cond);
|
2010-11-04 07:55:33 -07:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_alt(?expr, ?arms, ?ann)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret with_out_method(bind trans_alt(cx, expr, arms, ann, _), cx,
|
|
|
|
ann, output);
|
2010-12-15 09:38:23 -08:00
|
|
|
}
|
2011-06-14 15:20:04 +02:00
|
|
|
case (ast::expr_fn(?f, ?ann)) {
|
|
|
|
auto ccx = cx.fcx.lcx.ccx;
|
2011-06-15 11:19:50 -07:00
|
|
|
let TypeRef llfnty =
|
|
|
|
alt (ty::struct(ccx.tcx, node_ann_type(ccx, ann))) {
|
|
|
|
case (ty::ty_fn(?proto, ?inputs, ?output, _, _)) {
|
|
|
|
type_of_fn_full(ccx, e.span, proto, none, inputs,
|
|
|
|
output, 0u)
|
|
|
|
}
|
|
|
|
};
|
2011-06-14 15:20:04 +02:00
|
|
|
auto sub_cx = extend_path(cx.fcx.lcx, ccx.names.next("anon"));
|
|
|
|
auto s = mangle_internal_name_by_path(ccx, sub_cx.path);
|
|
|
|
auto llfn = decl_internal_fastcall_fn(ccx.llmod, s, llfnty);
|
|
|
|
trans_fn(sub_cx, e.span, f, llfn, none, [], ann);
|
|
|
|
ret res(cx, create_fn_pair(ccx, s, llfnty, llfn, false));
|
|
|
|
}
|
2011-05-31 14:24:04 +02:00
|
|
|
case (ast::expr_block(?blk, ?ann)) {
|
2011-03-31 00:46:26 -04:00
|
|
|
auto sub_cx = new_scope_block_ctxt(cx, "block-expr body");
|
|
|
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
2011-06-15 11:19:50 -07:00
|
|
|
auto sub =
|
|
|
|
with_out_method(bind trans_block(sub_cx, blk, _), cx, ann,
|
|
|
|
output);
|
2011-03-31 00:46:26 -04:00
|
|
|
cx.build.Br(sub_cx.llbb);
|
|
|
|
sub.bcx.build.Br(next_cx.llbb);
|
|
|
|
ret res(next_cx, sub.val);
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
2011-06-13 17:25:36 -07:00
|
|
|
case (ast::expr_move(?dst, ?src, _)) {
|
2011-05-27 17:38:52 -07:00
|
|
|
auto lhs_res = trans_lval(cx, dst);
|
|
|
|
assert (lhs_res.is_mem);
|
2011-06-15 12:17:51 +02:00
|
|
|
// FIXME Fill in lhs_res.res.bcx.sp
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-31 14:36:08 -07:00
|
|
|
auto rhs_res = trans_lval(lhs_res.res.bcx, src);
|
2011-06-13 17:25:36 -07:00
|
|
|
auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, src);
|
2011-05-27 17:38:52 -07:00
|
|
|
// FIXME: calculate copy init-ness in typestate.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
auto move_res =
|
|
|
|
move_val(rhs_res.res.bcx, DROP_EXISTING, lhs_res.res.val,
|
|
|
|
rhs_res.res.val, t);
|
2011-06-13 17:25:36 -07:00
|
|
|
ret res(move_res.bcx, C_nil());
|
2011-05-27 17:38:52 -07:00
|
|
|
}
|
2011-06-13 17:25:36 -07:00
|
|
|
case (ast::expr_assign(?dst, ?src, _)) {
|
2010-11-26 15:54:04 -08:00
|
|
|
auto lhs_res = trans_lval(cx, dst);
|
2011-05-02 17:47:24 -07:00
|
|
|
assert (lhs_res.is_mem);
|
2011-06-15 12:17:51 +02:00
|
|
|
// FIXME Fill in lhs_res.res.bcx.sp
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-12-23 17:31:16 -08:00
|
|
|
auto rhs_res = trans_expr(lhs_res.res.bcx, src);
|
2011-06-13 17:25:36 -07:00
|
|
|
auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, src);
|
2010-11-24 18:10:52 -08:00
|
|
|
// FIXME: calculate copy init-ness in typestate.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
auto copy_res =
|
|
|
|
copy_val(rhs_res.bcx, DROP_EXISTING, lhs_res.res.val,
|
|
|
|
rhs_res.val, t);
|
2011-06-13 17:25:36 -07:00
|
|
|
ret res(copy_res.bcx, C_nil());
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2011-06-13 17:25:36 -07:00
|
|
|
case (ast::expr_assign_op(?op, ?dst, ?src, _)) {
|
|
|
|
auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, src);
|
2010-12-08 14:50:47 -08:00
|
|
|
auto lhs_res = trans_lval(cx, dst);
|
2011-05-02 17:47:24 -07:00
|
|
|
assert (lhs_res.is_mem);
|
2011-06-15 12:17:51 +02:00
|
|
|
// FIXME Fill in lhs_res.res.bcx.sp
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-12-23 17:31:16 -08:00
|
|
|
auto rhs_res = trans_expr(lhs_res.res.bcx, src);
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_is_sequence(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-04-28 17:44:28 -07:00
|
|
|
alt (op) {
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::add) {
|
2011-06-13 18:52:04 -07:00
|
|
|
if (ty::sequence_is_interior(cx.fcx.lcx.ccx.tcx, t)) {
|
|
|
|
ret trans_ivec_append(rhs_res.bcx, t,
|
|
|
|
lhs_res.res.val,
|
|
|
|
rhs_res.val);
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
ret trans_vec_append(rhs_res.bcx, t, lhs_res.res.val,
|
2011-04-28 17:44:28 -07:00
|
|
|
rhs_res.val);
|
|
|
|
}
|
|
|
|
case (_) { }
|
|
|
|
}
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
auto lhs_val = load_if_immediate(rhs_res.bcx, lhs_res.res.val, t);
|
|
|
|
auto v =
|
|
|
|
trans_eager_binop(rhs_res.bcx, op, t, lhs_val, rhs_res.val);
|
2010-12-08 14:50:47 -08:00
|
|
|
// FIXME: calculate copy init-ness in typestate.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
auto copy_res =
|
|
|
|
copy_val(v.bcx, DROP_EXISTING, lhs_res.res.val, v.val, t);
|
2011-06-13 17:25:36 -07:00
|
|
|
ret res(copy_res.bcx, C_nil());
|
2010-12-08 14:50:47 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_bind(?f, ?args, ?ann)) {
|
2011-01-03 22:39:43 -08:00
|
|
|
ret trans_bind(cx, f, args, ann);
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_call(?f, ?args, ?ann)) {
|
2011-02-18 17:30:57 -08:00
|
|
|
ret trans_call(cx, f, none[ValueRef], args, ann);
|
2010-10-21 17:24:26 -07:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ast::expr_cast(?e, _, ?ann)) { ret trans_cast(cx, e, ann); }
|
2011-06-10 19:35:59 -07:00
|
|
|
case (ast::expr_vec(?args, _, ast::sk_rc, ?ann)) {
|
2010-12-10 17:25:11 -08:00
|
|
|
ret trans_vec(cx, args, ann);
|
|
|
|
}
|
2011-06-10 19:35:59 -07:00
|
|
|
case (ast::expr_vec(?args, _, ast::sk_unique, ?ann)) {
|
|
|
|
ret trans_ivec(cx, args, ann);
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ast::expr_tup(?args, ?ann)) { ret trans_tup(cx, args, ann); }
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_rec(?args, ?base, ?ann)) {
|
2011-02-14 15:52:38 -08:00
|
|
|
ret trans_rec(cx, args, base, ann);
|
2010-11-30 10:39:35 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_ext(_, _, _, ?expanded, _)) {
|
2011-02-27 22:35:27 -05:00
|
|
|
ret trans_expr(cx, expanded);
|
2011-02-26 20:51:02 -05:00
|
|
|
}
|
2011-06-08 03:58:52 -04:00
|
|
|
case (ast::expr_fail(_, ?str)) {
|
|
|
|
auto failmsg;
|
|
|
|
alt (str) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (some(?msg)) { failmsg = msg; }
|
|
|
|
case (_) { failmsg = "explicit failure"; }
|
2011-06-08 03:58:52 -04:00
|
|
|
}
|
|
|
|
ret trans_fail(cx, some(e.span), failmsg);
|
2011-02-14 17:46:28 -08:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ast::expr_log(?lvl, ?a, _)) { ret trans_log(lvl, cx, a); }
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_assert(?a, _)) {
|
2011-06-14 14:16:47 -07:00
|
|
|
ret trans_check_expr(cx, a, "Assertion");
|
2011-05-02 17:47:24 -07:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_check(?a, _)) {
|
2011-06-14 14:16:47 -07:00
|
|
|
ret trans_check_expr(cx, a, "Predicate");
|
2011-02-14 17:46:28 -08:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ast::expr_break(?a)) { ret trans_break(e.span, cx); }
|
|
|
|
case (ast::expr_cont(?a)) { ret trans_cont(e.span, cx); }
|
|
|
|
case (ast::expr_ret(?e, _)) { ret trans_ret(cx, e); }
|
|
|
|
case (ast::expr_put(?e, _)) { ret trans_put(cx, e); }
|
|
|
|
case (ast::expr_be(?e, _)) { ret trans_be(cx, e); }
|
|
|
|
case (ast::expr_port(?ann)) { ret trans_port(cx, ann); }
|
|
|
|
case (ast::expr_chan(?e, ?ann)) { ret trans_chan(cx, e, ann); }
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_send(?lhs, ?rhs, ?ann)) {
|
2011-03-16 21:49:15 -04:00
|
|
|
ret trans_send(cx, lhs, rhs, ann);
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::expr_recv(?lhs, ?rhs, ?ann)) {
|
2011-03-16 21:49:15 -04:00
|
|
|
ret trans_recv(cx, lhs, rhs, ann);
|
|
|
|
}
|
2011-05-17 17:24:55 -07:00
|
|
|
case (ast::expr_spawn(?dom, ?name, ?func, ?args, ?ann)) {
|
2011-05-19 18:36:40 -07:00
|
|
|
ret trans_spawn(cx, dom, name, func, args, ann);
|
2011-05-17 17:24:55 -07:00
|
|
|
}
|
2011-05-20 17:41:36 -07:00
|
|
|
case (ast::expr_anon_obj(?anon_obj, ?tps, ?odid, ?ann)) {
|
2011-06-09 18:15:55 -07:00
|
|
|
ret trans_anon_obj(cx, e.span, anon_obj, tps, odid.ctor, ann);
|
2011-05-20 17:41:36 -07:00
|
|
|
}
|
2010-11-26 15:54:04 -08:00
|
|
|
case (_) {
|
2011-04-07 12:50:37 -07:00
|
|
|
// The expression is an lvalue. Fall through.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-11-26 15:54:04 -08:00
|
|
|
}
|
2010-09-28 12:23:40 -07:00
|
|
|
}
|
2011-04-07 12:50:37 -07:00
|
|
|
// lval cases fall through to trans_lval and then
|
|
|
|
// possibly load the result (if it's non-structural).
|
|
|
|
|
2011-05-19 15:47:15 -07:00
|
|
|
auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
|
2011-04-07 12:50:37 -07:00
|
|
|
auto sub = trans_lval(cx, e);
|
2011-04-12 12:06:20 -07:00
|
|
|
ret res(sub.res.bcx, load_if_immediate(sub.res.bcx, sub.res.val, t));
|
2010-09-28 12:23:40 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn with_out_method(fn(&out_method) -> result work, @block_ctxt cx,
|
2011-05-31 14:24:04 +02:00
|
|
|
&ast::ann ann, &out_method outer_output) -> result {
|
|
|
|
auto ccx = cx.fcx.lcx.ccx;
|
|
|
|
if (outer_output != return) {
|
|
|
|
ret work(outer_output);
|
|
|
|
} else {
|
|
|
|
auto tp = node_ann_type(ccx, ann);
|
2011-06-15 11:19:50 -07:00
|
|
|
if (ty::type_is_nil(ccx.tcx, tp)) { ret work(return); }
|
2011-05-31 14:24:04 +02:00
|
|
|
auto res_alloca = alloc_ty(cx, tp);
|
|
|
|
cx = zero_alloca(res_alloca.bcx, res_alloca.val, tp).bcx;
|
2011-06-15 11:19:50 -07:00
|
|
|
fn drop_hoisted_ty(&@block_ctxt cx, ValueRef target, ty::t t) ->
|
|
|
|
result {
|
2011-05-31 14:24:04 +02:00
|
|
|
auto reg_val = load_if_immediate(cx, target, t);
|
|
|
|
ret drop_ty(cx, reg_val, t);
|
|
|
|
}
|
|
|
|
auto cleanup = bind drop_hoisted_ty(_, res_alloca.val, tp);
|
|
|
|
find_scope_cx(cx).cleanups += [clean(cleanup)];
|
|
|
|
auto done = work(save_in(res_alloca.val));
|
2011-06-06 20:23:35 +02:00
|
|
|
done = res(done.bcx, load_if_immediate(done.bcx, res_alloca.val, tp));
|
2011-05-31 14:24:04 +02:00
|
|
|
ret done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-12-03 13:03:07 -08:00
|
|
|
// We pass structural values around the compiler "by pointer" and
|
2011-04-12 12:06:20 -07:00
|
|
|
// non-structural values (scalars, boxes, pointers) "by value". We call the
|
|
|
|
// latter group "immediates" and, in some circumstances when we know we have a
|
|
|
|
// pointer (or need one), perform load/store operations based on the
|
|
|
|
// immediate-ness of the type.
|
2011-05-12 17:24:54 +02:00
|
|
|
fn type_is_immediate(&@crate_ctxt ccx, &ty::t t) -> bool {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret ty::type_is_scalar(ccx.tcx, t) || ty::type_is_boxed(ccx.tcx, t) ||
|
|
|
|
ty::type_is_native(ccx.tcx, t);
|
2011-04-12 12:06:20 -07:00
|
|
|
}
|
|
|
|
|
2011-05-10 17:58:22 -07:00
|
|
|
fn do_spill(&@block_ctxt cx, ValueRef v) -> ValueRef {
|
2011-04-12 12:06:20 -07:00
|
|
|
// We have a value but we have to spill it to pass by alias.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-12 12:06:20 -07:00
|
|
|
auto llptr = alloca(cx, val_ty(v));
|
|
|
|
cx.build.Store(v, llptr);
|
|
|
|
ret llptr;
|
|
|
|
}
|
2010-12-03 13:03:07 -08:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn spill_if_immediate(&@block_ctxt cx, ValueRef v, &ty::t t) -> ValueRef {
|
2011-06-15 11:19:50 -07:00
|
|
|
if (type_is_immediate(cx.fcx.lcx.ccx, t)) { ret do_spill(cx, v); }
|
2011-04-12 12:06:20 -07:00
|
|
|
ret v;
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn load_if_immediate(&@block_ctxt cx, ValueRef v, &ty::t t) -> ValueRef {
|
2011-06-15 11:19:50 -07:00
|
|
|
if (type_is_immediate(cx.fcx.lcx.ccx, t)) { ret cx.build.Load(v); }
|
2011-04-12 12:06:20 -07:00
|
|
|
ret v;
|
2010-12-03 13:03:07 -08:00
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_log(int lvl, &@block_ctxt cx, &@ast::expr e) -> result {
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
auto lcx = cx.fcx.lcx;
|
2011-06-10 16:32:21 -07:00
|
|
|
auto modname = str::connect(lcx.module_path, "::");
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
auto global;
|
|
|
|
if (lcx.ccx.module_data.contains_key(modname)) {
|
|
|
|
global = lcx.ccx.module_data.get(modname);
|
|
|
|
} else {
|
2011-06-07 17:54:22 -07:00
|
|
|
auto s =
|
|
|
|
link::mangle_internal_name_by_path_and_seq(lcx.ccx,
|
|
|
|
lcx.module_path,
|
|
|
|
"loglevel");
|
|
|
|
global = llvm::LLVMAddGlobal(lcx.ccx.llmod, T_int(), str::buf(s));
|
2011-05-12 17:24:54 +02:00
|
|
|
llvm::LLVMSetGlobalConstant(global, False);
|
|
|
|
llvm::LLVMSetInitializer(global, C_null(T_int()));
|
2011-06-15 11:19:50 -07:00
|
|
|
llvm::LLVMSetLinkage(global,
|
|
|
|
lib::llvm::LLVMInternalLinkage as llvm::Linkage);
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
lcx.ccx.module_data.insert(modname, global);
|
|
|
|
}
|
2011-04-20 04:55:55 +00:00
|
|
|
auto log_cx = new_scope_block_ctxt(cx, "log");
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
auto after_cx = new_sub_block_ctxt(cx, "after");
|
|
|
|
auto load = cx.build.Load(global);
|
2011-05-12 17:24:54 +02:00
|
|
|
auto test = cx.build.ICmp(lib::llvm::LLVMIntSGE, load, C_int(lvl));
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
cx.build.CondBr(test, log_cx.llbb, after_cx.llbb);
|
|
|
|
auto sub = trans_expr(log_cx, e);
|
2011-05-19 15:47:15 -07:00
|
|
|
auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
|
2011-04-29 19:19:54 -07:00
|
|
|
auto log_bcx = sub.bcx;
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_is_fp(cx.fcx.lcx.ccx.tcx, e_ty)) {
|
2011-03-22 17:25:40 -07:00
|
|
|
let TypeRef tr;
|
|
|
|
let bool is32bit = false;
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(cx.fcx.lcx.ccx.tcx, e_ty)) {
|
|
|
|
case (ty::ty_machine(util::common::ty_f32)) {
|
2011-03-22 17:25:40 -07:00
|
|
|
tr = T_f32();
|
|
|
|
is32bit = true;
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_machine(util::common::ty_f64)) { tr = T_f64(); }
|
|
|
|
case (_) { tr = T_float(); }
|
2011-03-22 17:25:40 -07:00
|
|
|
}
|
|
|
|
if (is32bit) {
|
2011-05-10 14:03:47 -07:00
|
|
|
log_bcx.build.Call(log_bcx.fcx.lcx.ccx.upcalls.log_float,
|
2011-06-15 11:19:50 -07:00
|
|
|
[log_bcx.fcx.lltaskptr, C_int(lvl), sub.val]);
|
2011-03-22 17:25:40 -07:00
|
|
|
} else {
|
2011-05-10 14:03:47 -07:00
|
|
|
// FIXME: Eliminate this level of indirection.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-29 19:19:54 -07:00
|
|
|
auto tmp = alloca(log_bcx, tr);
|
2011-03-21 17:12:05 -07:00
|
|
|
sub.bcx.build.Store(sub.val, tmp);
|
2011-05-10 14:03:47 -07:00
|
|
|
log_bcx.build.Call(log_bcx.fcx.lcx.ccx.upcalls.log_double,
|
2011-05-16 18:21:22 -07:00
|
|
|
[log_bcx.fcx.lltaskptr, C_int(lvl), tmp]);
|
2011-03-21 17:12:05 -07:00
|
|
|
}
|
2011-05-25 15:25:48 -07:00
|
|
|
} else if (ty::type_is_integral(cx.fcx.lcx.ccx.tcx, e_ty) ||
|
2011-06-15 11:19:50 -07:00
|
|
|
ty::type_is_bool(cx.fcx.lcx.ccx.tcx, e_ty)) {
|
2011-05-25 15:25:48 -07:00
|
|
|
// FIXME: Handle signedness properly.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
auto llintval =
|
|
|
|
int_cast(log_bcx, T_int(), val_ty(sub.val), sub.val, false);
|
2011-05-25 15:25:48 -07:00
|
|
|
log_bcx.build.Call(log_bcx.fcx.lcx.ccx.upcalls.log_int,
|
2011-06-15 11:19:50 -07:00
|
|
|
[log_bcx.fcx.lltaskptr, C_int(lvl), llintval]);
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
} else {
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(cx.fcx.lcx.ccx.tcx, e_ty)) {
|
|
|
|
case (ty::ty_str) {
|
2011-05-10 14:03:47 -07:00
|
|
|
log_bcx.build.Call(log_bcx.fcx.lcx.ccx.upcalls.log_str,
|
2011-05-16 18:21:22 -07:00
|
|
|
[log_bcx.fcx.lltaskptr, C_int(lvl),
|
2011-06-15 11:19:50 -07:00
|
|
|
sub.val]);
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
}
|
|
|
|
case (_) {
|
2011-05-25 15:25:48 -07:00
|
|
|
// FIXME: Support these types.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-25 15:25:48 -07:00
|
|
|
cx.fcx.lcx.ccx.sess.span_err(e.span,
|
2011-06-15 11:19:50 -07:00
|
|
|
"log called on unsupported type "
|
|
|
|
+
|
|
|
|
ty_to_str(cx.fcx.lcx.ccx.tcx,
|
|
|
|
e_ty));
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
}
|
2010-09-23 18:38:37 -07:00
|
|
|
}
|
|
|
|
}
|
2011-04-29 19:19:54 -07:00
|
|
|
log_bcx = trans_block_cleanups(log_bcx, log_cx);
|
|
|
|
log_bcx.build.Br(after_cx.llbb);
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
ret res(after_cx, C_nil());
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
|
|
|
|
2011-06-14 14:16:47 -07:00
|
|
|
fn trans_check_expr(&@block_ctxt cx, &@ast::expr e, &str s) -> result {
|
2010-10-22 15:37:42 -07:00
|
|
|
auto cond_res = trans_expr(cx, e);
|
2011-06-14 14:16:47 -07:00
|
|
|
auto expr_str = s + " " + expr_to_str(e) + " failed";
|
2010-11-10 17:46:49 -08:00
|
|
|
auto fail_cx = new_sub_block_ctxt(cx, "fail");
|
2011-05-12 17:24:54 +02:00
|
|
|
auto fail_res = trans_fail(fail_cx, some[common::span](e.span), expr_str);
|
2010-11-10 17:46:49 -08:00
|
|
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
2011-06-15 11:19:50 -07:00
|
|
|
cond_res.bcx.build.CondBr(cond_res.val, next_cx.llbb, fail_cx.llbb);
|
2010-10-22 15:37:42 -07:00
|
|
|
ret res(next_cx, C_nil());
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_fail(&@block_ctxt cx, &option::t[common::span] sp_opt, &str fail_str)
|
2011-06-15 11:19:50 -07:00
|
|
|
-> result {
|
2011-05-10 14:03:47 -07:00
|
|
|
auto V_fail_str = C_cstr(cx.fcx.lcx.ccx, fail_str);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto V_filename;
|
|
|
|
auto V_line;
|
2011-04-19 15:22:57 -07:00
|
|
|
alt (sp_opt) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(?sp)) {
|
2011-04-19 15:22:57 -07:00
|
|
|
auto loc = cx.fcx.lcx.ccx.sess.lookup_pos(sp.lo);
|
2011-05-10 14:03:47 -07:00
|
|
|
V_filename = C_cstr(cx.fcx.lcx.ccx, loc.filename);
|
2011-04-19 15:22:57 -07:00
|
|
|
V_line = loc.line as int;
|
|
|
|
}
|
2011-05-31 00:39:19 -04:00
|
|
|
case (none) {
|
2011-05-10 14:03:47 -07:00
|
|
|
V_filename = C_cstr(cx.fcx.lcx.ccx, "<runtime>");
|
2011-04-19 15:22:57 -07:00
|
|
|
V_line = 0;
|
|
|
|
}
|
|
|
|
}
|
2011-05-10 14:03:47 -07:00
|
|
|
V_fail_str = cx.build.PointerCast(V_fail_str, T_ptr(T_i8()));
|
|
|
|
V_filename = cx.build.PointerCast(V_filename, T_ptr(T_i8()));
|
2011-05-16 18:21:22 -07:00
|
|
|
auto args = [cx.fcx.lltaskptr, V_fail_str, V_filename, C_int(V_line)];
|
2011-05-10 14:03:47 -07:00
|
|
|
cx.build.Call(cx.fcx.lcx.ccx.upcalls._fail, args);
|
|
|
|
cx.build.Unreachable();
|
|
|
|
ret res(cx, C_nil());
|
2011-01-28 00:09:26 -05:00
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_put(&@block_ctxt cx, &option::t[@ast::expr] e) -> result {
|
2011-02-18 18:52:16 -08:00
|
|
|
auto llcallee = C_nil();
|
|
|
|
auto llenv = C_nil();
|
2011-06-15 11:19:50 -07:00
|
|
|
alt ({ cx.fcx.lliterbody }) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(?lli)) {
|
2011-03-28 18:04:52 -07:00
|
|
|
auto slot = alloca(cx, val_ty(lli));
|
2011-02-18 18:52:16 -08:00
|
|
|
cx.build.Store(lli, slot);
|
2011-06-15 11:19:50 -07:00
|
|
|
llcallee =
|
|
|
|
cx.build.GEP(slot, [C_int(0), C_int(abi::fn_field_code)]);
|
2011-02-18 18:52:16 -08:00
|
|
|
llcallee = cx.build.Load(llcallee);
|
2011-06-15 11:19:50 -07:00
|
|
|
llenv = cx.build.GEP(slot, [C_int(0), C_int(abi::fn_field_box)]);
|
2011-02-18 18:52:16 -08:00
|
|
|
llenv = cx.build.Load(llenv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
auto bcx = cx;
|
2011-03-28 18:04:52 -07:00
|
|
|
auto dummy_retslot = alloca(bcx, T_nil());
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ValueRef] llargs = [dummy_retslot, cx.fcx.lltaskptr, llenv];
|
2011-02-18 18:52:16 -08:00
|
|
|
alt (e) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (none) { }
|
|
|
|
case (some(?x)) {
|
2011-05-19 15:47:15 -07:00
|
|
|
auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, x);
|
2011-06-10 12:03:50 +02:00
|
|
|
auto arg = rec(mode=ty::mo_alias(false), ty=e_ty);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto arg_tys =
|
|
|
|
type_of_explicit_args(cx.fcx.lcx.ccx, x.span, [arg]);
|
2011-04-23 14:17:44 -07:00
|
|
|
auto r = trans_arg_expr(bcx, arg, arg_tys.(0), x);
|
2011-02-18 18:52:16 -08:00
|
|
|
bcx = r.bcx;
|
2011-05-16 18:21:22 -07:00
|
|
|
llargs += [r.val];
|
2011-02-18 18:52:16 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ret res(bcx, bcx.build.FastCall(llcallee, llargs));
|
2011-02-14 17:58:32 -08:00
|
|
|
}
|
|
|
|
|
2011-06-10 14:34:01 -07:00
|
|
|
fn trans_break_cont(&span sp, &@block_ctxt cx, bool to_end) -> result {
|
2011-03-25 16:28:16 +01:00
|
|
|
auto bcx = cx;
|
|
|
|
// Locate closest loop block, outputting cleanup as we go.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-25 16:28:16 +01:00
|
|
|
auto cleanup_cx = cx;
|
|
|
|
while (true) {
|
|
|
|
bcx = trans_block_cleanups(bcx, cleanup_cx);
|
2011-06-15 11:19:50 -07:00
|
|
|
alt ({ cleanup_cx.kind }) {
|
2011-03-25 16:28:16 +01:00
|
|
|
case (LOOP_SCOPE_BLOCK(?_cont, ?_break)) {
|
|
|
|
if (to_end) {
|
|
|
|
bcx.build.Br(_break.llbb);
|
|
|
|
} else {
|
|
|
|
alt (_cont) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (option::some(?_cont)) {
|
2011-03-25 16:28:16 +01:00
|
|
|
bcx.build.Br(_cont.llbb);
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { bcx.build.Br(cleanup_cx.llbb); }
|
2011-03-25 16:28:16 +01:00
|
|
|
}
|
|
|
|
}
|
2011-05-10 11:50:29 -07:00
|
|
|
ret res(new_sub_block_ctxt(bcx, "break_cont.unreachable"),
|
|
|
|
C_nil());
|
2011-03-25 16:28:16 +01:00
|
|
|
}
|
|
|
|
case (_) {
|
2011-06-15 11:19:50 -07:00
|
|
|
alt ({ cleanup_cx.parent }) {
|
2011-03-25 16:28:16 +01:00
|
|
|
case (parent_some(?cx)) { cleanup_cx = cx; }
|
2011-06-10 14:34:01 -07:00
|
|
|
case (parent_none) {
|
|
|
|
cx.fcx.lcx.ccx.sess.span_err(sp,
|
2011-06-15 11:19:50 -07:00
|
|
|
if (to_end) {
|
|
|
|
"Break"
|
|
|
|
} else { "Cont" } +
|
|
|
|
" outside a loop");
|
2011-06-10 14:34:01 -07:00
|
|
|
}
|
2011-03-25 16:28:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-06-04 18:13:00 -07:00
|
|
|
// If we get here without returning, it's a bug
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-04 18:13:00 -07:00
|
|
|
cx.fcx.lcx.ccx.sess.bug("in trans::trans_break_cont()");
|
2011-03-25 16:28:16 +01:00
|
|
|
}
|
|
|
|
|
2011-06-10 14:34:01 -07:00
|
|
|
fn trans_break(&span sp, &@block_ctxt cx) -> result {
|
|
|
|
ret trans_break_cont(sp, cx, true);
|
2011-03-25 16:28:16 +01:00
|
|
|
}
|
|
|
|
|
2011-06-10 14:34:01 -07:00
|
|
|
fn trans_cont(&span sp, &@block_ctxt cx) -> result {
|
|
|
|
ret trans_break_cont(sp, cx, false);
|
2011-03-25 16:28:16 +01:00
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_ret(&@block_ctxt cx, &option::t[@ast::expr] e) -> result {
|
2011-01-21 07:58:16 -08:00
|
|
|
auto bcx = cx;
|
|
|
|
auto val = C_nil();
|
2010-10-22 19:23:10 -07:00
|
|
|
alt (e) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(?x)) {
|
2011-05-19 15:47:15 -07:00
|
|
|
auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, x);
|
2011-01-21 07:58:16 -08:00
|
|
|
auto r = trans_expr(cx, x);
|
|
|
|
bcx = r.bcx;
|
|
|
|
val = r.val;
|
2011-05-27 17:58:22 -07:00
|
|
|
bcx = copy_val(bcx, INIT, cx.fcx.llretptr, val, t).bcx;
|
2010-10-22 19:23:10 -07:00
|
|
|
}
|
2011-04-26 20:39:25 +00:00
|
|
|
case (_) {
|
2011-05-12 17:24:54 +02:00
|
|
|
auto t = llvm::LLVMGetElementType(val_ty(cx.fcx.llretptr));
|
|
|
|
auto null = lib::llvm::llvm::LLVMConstNull(t);
|
2011-04-26 20:39:25 +00:00
|
|
|
bcx.build.Store(null, cx.fcx.llretptr);
|
|
|
|
}
|
2010-10-22 19:23:10 -07:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
// run all cleanups and back out.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-11-10 17:46:49 -08:00
|
|
|
let bool more_cleanups = true;
|
2010-11-14 10:48:44 -08:00
|
|
|
auto cleanup_cx = cx;
|
2010-11-10 17:46:49 -08:00
|
|
|
while (more_cleanups) {
|
2011-01-21 07:58:16 -08:00
|
|
|
bcx = trans_block_cleanups(bcx, cleanup_cx);
|
2011-06-15 11:19:50 -07:00
|
|
|
alt ({ cleanup_cx.parent }) {
|
|
|
|
case (parent_some(?b)) { cleanup_cx = b; }
|
|
|
|
case (parent_none) { more_cleanups = false; }
|
2010-11-10 17:46:49 -08:00
|
|
|
}
|
|
|
|
}
|
2011-01-21 07:58:16 -08:00
|
|
|
bcx.build.RetVoid();
|
2011-05-10 11:50:29 -07:00
|
|
|
ret res(new_sub_block_ctxt(bcx, "ret.unreachable"), C_nil());
|
2010-10-22 19:23:10 -07:00
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_be(&@block_ctxt cx, &@ast::expr e) -> result {
|
2011-02-09 22:36:37 -05:00
|
|
|
// FIXME: This should be a typestate precondition
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
assert (ast::is_call_expr(e));
|
2011-02-09 22:36:37 -05:00
|
|
|
// FIXME: Turn this into a real tail call once
|
|
|
|
// calling convention issues are settled
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-01-30 17:18:19 -05:00
|
|
|
ret trans_ret(cx, some(e));
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_port(&@block_ctxt cx, &ast::ann ann) -> result {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
|
2011-03-16 21:49:15 -04:00
|
|
|
auto unit_ty;
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_port(?t)) { unit_ty = t; }
|
|
|
|
case (_) { cx.fcx.lcx.ccx.sess.bug("non-port type in trans_port"); }
|
2011-03-16 21:49:15 -04:00
|
|
|
}
|
2011-05-18 15:35:16 -07:00
|
|
|
auto llunit_ty = type_of(cx.fcx.lcx.ccx, cx.sp, unit_ty);
|
2011-03-16 21:49:15 -04:00
|
|
|
auto bcx = cx;
|
|
|
|
auto unit_sz = size_of(bcx, unit_ty);
|
|
|
|
bcx = unit_sz.bcx;
|
2011-06-15 11:19:50 -07:00
|
|
|
auto port_raw_val =
|
|
|
|
bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.new_port,
|
|
|
|
[bcx.fcx.lltaskptr, unit_sz.val]);
|
2011-05-18 15:35:16 -07:00
|
|
|
auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, t);
|
2011-05-10 14:03:47 -07:00
|
|
|
auto port_val = bcx.build.PointerCast(port_raw_val, llty);
|
2011-03-16 21:49:15 -04:00
|
|
|
auto dropref = clean(bind drop_ty(_, port_val, t));
|
2011-05-16 18:21:22 -07:00
|
|
|
find_scope_cx(bcx).cleanups += [dropref];
|
2011-03-16 21:49:15 -04:00
|
|
|
ret res(bcx, port_val);
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_chan(&@block_ctxt cx, &@ast::expr e, &ast::ann ann) -> result {
|
2011-03-16 21:49:15 -04:00
|
|
|
auto bcx = cx;
|
|
|
|
auto prt = trans_expr(bcx, e);
|
|
|
|
bcx = prt.bcx;
|
2011-05-10 14:03:47 -07:00
|
|
|
auto prt_val = bcx.build.PointerCast(prt.val, T_opaque_port_ptr());
|
2011-06-15 11:19:50 -07:00
|
|
|
auto chan_raw_val =
|
|
|
|
bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.new_chan,
|
|
|
|
[bcx.fcx.lltaskptr, prt_val]);
|
2011-04-17 14:24:45 +02:00
|
|
|
auto chan_ty = node_ann_type(bcx.fcx.lcx.ccx, ann);
|
2011-05-18 15:35:16 -07:00
|
|
|
auto chan_llty = type_of(bcx.fcx.lcx.ccx, e.span, chan_ty);
|
2011-05-10 14:03:47 -07:00
|
|
|
auto chan_val = bcx.build.PointerCast(chan_raw_val, chan_llty);
|
2011-03-16 21:49:15 -04:00
|
|
|
auto dropref = clean(bind drop_ty(_, chan_val, chan_ty));
|
2011-05-16 18:21:22 -07:00
|
|
|
find_scope_cx(bcx).cleanups += [dropref];
|
2011-03-16 21:49:15 -04:00
|
|
|
ret res(bcx, chan_val);
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_spawn(&@block_ctxt cx, &ast::spawn_dom dom, &option::t[str] name,
|
|
|
|
&@ast::expr func, &vec[@ast::expr] args, &ast::ann ann) ->
|
|
|
|
result {
|
2011-05-19 18:36:40 -07:00
|
|
|
auto bcx = cx;
|
2011-05-17 17:24:55 -07:00
|
|
|
// Make the task name
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto tname =
|
|
|
|
alt (name) {
|
|
|
|
case (none) {
|
|
|
|
auto argss = vec::map(expr_to_str, args);
|
|
|
|
#fmt("%s(%s)", expr_to_str(func), str::connect(argss, ", "))
|
|
|
|
}
|
|
|
|
case (some(?n)) { n }
|
|
|
|
};
|
2011-05-17 17:24:55 -07:00
|
|
|
// Generate code
|
2011-05-19 14:07:59 -07:00
|
|
|
//
|
|
|
|
// This is a several step process. The following things need to happen
|
|
|
|
// (not necessarily in order):
|
|
|
|
//
|
|
|
|
// 1. Evaluate all the arguments to the spawnee.
|
|
|
|
//
|
|
|
|
// 2. Alloca a tuple that holds these arguments (they must be in reverse
|
|
|
|
// order, so that they match the expected stack layout for the spawnee)
|
|
|
|
//
|
2011-05-19 18:36:40 -07:00
|
|
|
// 3. Fill the tuple with the arguments we evaluated.
|
2011-05-19 14:07:59 -07:00
|
|
|
//
|
2011-05-26 18:00:33 -07:00
|
|
|
// 3.5. Generate a wrapper function that takes the tuple and unpacks it to
|
|
|
|
// call the real task.
|
|
|
|
//
|
|
|
|
// 4. Pass a pointer to the wrapper function and the argument tuple to
|
|
|
|
// upcall_start_task. In order to do this, we need to allocate another
|
|
|
|
// tuple that matches the arguments expected by rust_task::start.
|
2011-05-20 14:29:26 -07:00
|
|
|
//
|
|
|
|
// 5. Oh yeah, we have to create the task before we start it...
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-19 18:36:40 -07:00
|
|
|
// Translate the arguments, remembering their types and where the values
|
|
|
|
// ended up.
|
2011-05-23 17:35:15 -07:00
|
|
|
|
2011-05-26 18:00:33 -07:00
|
|
|
let vec[ty::t] arg_tys = [];
|
2011-05-19 18:36:40 -07:00
|
|
|
let vec[ValueRef] arg_vals = [];
|
2011-06-15 11:19:50 -07:00
|
|
|
for (@ast::expr e in args) {
|
2011-05-19 18:36:40 -07:00
|
|
|
auto arg = trans_expr(bcx, e);
|
|
|
|
bcx = arg.bcx;
|
|
|
|
vec::push[ValueRef](arg_vals, arg.val);
|
2011-06-15 11:19:50 -07:00
|
|
|
vec::push[ty::t](arg_tys, ty::expr_ty(cx.fcx.lcx.ccx.tcx, e));
|
2011-05-19 18:36:40 -07:00
|
|
|
}
|
2011-05-23 19:29:45 -07:00
|
|
|
// Make the tuple.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-19 18:36:40 -07:00
|
|
|
auto args_ty = ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, arg_tys);
|
|
|
|
// Allocate and fill the tuple.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llargs = alloc_ty(bcx, args_ty);
|
2011-05-26 18:00:33 -07:00
|
|
|
auto i = 0u;
|
2011-06-15 11:19:50 -07:00
|
|
|
for (ValueRef v in arg_vals) {
|
2011-05-19 18:36:40 -07:00
|
|
|
// log_err #fmt("ty(llargs) = %s",
|
|
|
|
// val_str(bcx.fcx.lcx.ccx.tn, llargs.val));
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-19 18:36:40 -07:00
|
|
|
auto target = bcx.build.GEP(llargs.val, [C_int(0), C_int(i as int)]);
|
|
|
|
// log_err #fmt("ty(v) = %s", val_str(bcx.fcx.lcx.ccx.tn, v));
|
|
|
|
// log_err #fmt("ty(target) = %s",
|
|
|
|
// val_str(bcx.fcx.lcx.ccx.tn, target));
|
|
|
|
|
|
|
|
bcx.build.Store(v, target);
|
2011-05-23 17:35:15 -07:00
|
|
|
i += 1u;
|
2011-05-19 18:36:40 -07:00
|
|
|
}
|
|
|
|
// Now we're ready to do the upcall.
|
|
|
|
|
2011-05-20 14:29:26 -07:00
|
|
|
// But first, we'll create a task.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
let ValueRef lltname = C_str(bcx.fcx.lcx.ccx, tname);
|
|
|
|
auto new_task =
|
|
|
|
bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.new_task,
|
|
|
|
[bcx.fcx.lltaskptr, lltname]);
|
2011-05-20 16:45:51 -07:00
|
|
|
// Okay, start the task.
|
2011-05-26 18:00:33 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llargs_i = bcx.build.PointerCast(llargs.val, T_int());
|
2011-05-26 18:00:33 -07:00
|
|
|
// Generate the wrapper function
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-27 15:37:19 -07:00
|
|
|
auto wrapper = mk_spawn_wrapper(bcx, func, args_ty);
|
2011-05-26 18:00:33 -07:00
|
|
|
bcx = wrapper.bcx;
|
|
|
|
auto llfnptr_i = bcx.build.PointerCast(wrapper.val, T_int());
|
|
|
|
// And start the task
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-31 17:44:54 -07:00
|
|
|
auto args_size = size_of(bcx, args_ty).val;
|
2011-05-20 16:45:51 -07:00
|
|
|
bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.start_task,
|
2011-06-15 11:19:50 -07:00
|
|
|
[bcx.fcx.lltaskptr, new_task, llfnptr_i, llargs_i,
|
|
|
|
args_size]);
|
2011-05-24 12:18:42 -07:00
|
|
|
auto task_ty = node_ann_type(bcx.fcx.lcx.ccx, ann);
|
|
|
|
auto dropref = clean(bind drop_ty(_, new_task, task_ty));
|
|
|
|
find_scope_cx(bcx).cleanups += [dropref];
|
2011-05-20 14:29:26 -07:00
|
|
|
ret res(bcx, new_task);
|
2011-05-17 17:24:55 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn mk_spawn_wrapper(&@block_ctxt cx, &@ast::expr func, &ty::t args_ty) ->
|
|
|
|
result {
|
2011-05-26 18:00:33 -07:00
|
|
|
auto llmod = cx.fcx.lcx.ccx.llmod;
|
|
|
|
let TypeRef args_ty_tref = type_of(cx.fcx.lcx.ccx, cx.sp, args_ty);
|
|
|
|
let TypeRef wrapper_fn_type =
|
|
|
|
type_of_fn(cx.fcx.lcx.ccx, cx.sp, ast::proto_fn,
|
2011-06-15 11:19:50 -07:00
|
|
|
[rec(mode=ty::mo_alias(false), ty=args_ty)], ty::idx_nil,
|
2011-05-26 18:00:33 -07:00
|
|
|
0u);
|
|
|
|
// TODO: construct a name based on tname
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-06 15:48:36 -07:00
|
|
|
let str wrap_name =
|
2011-06-15 11:19:50 -07:00
|
|
|
mangle_internal_name_by_path_and_seq(cx.fcx.lcx.ccx, cx.fcx.lcx.path,
|
2011-06-07 17:54:22 -07:00
|
|
|
"spawn_wrapper");
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llfndecl = decl_fastcall_fn(llmod, wrap_name, wrapper_fn_type);
|
2011-05-26 18:00:33 -07:00
|
|
|
auto fcx = new_fn_ctxt(cx.fcx.lcx, cx.sp, llfndecl);
|
|
|
|
auto fbcx = new_top_block_ctxt(fcx);
|
|
|
|
// 3u to skip the three implicit args
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
let ValueRef arg = llvm::LLVMGetParam(fcx.llfn, 3u);
|
2011-06-07 17:54:22 -07:00
|
|
|
let vec[ValueRef] child_args =
|
2011-06-15 11:19:50 -07:00
|
|
|
[llvm::LLVMGetParam(fcx.llfn, 0u), llvm::LLVMGetParam(fcx.llfn, 1u),
|
2011-05-26 18:00:33 -07:00
|
|
|
llvm::LLVMGetParam(fcx.llfn, 2u)];
|
|
|
|
// unpack the arguments
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
alt (ty::struct(fcx.lcx.ccx.tcx, args_ty)) {
|
|
|
|
case (ty::ty_tup(?elements)) {
|
2011-05-26 18:00:33 -07:00
|
|
|
auto i = 0;
|
2011-06-15 11:19:50 -07:00
|
|
|
for (ty::mt m in elements) {
|
2011-05-26 18:00:33 -07:00
|
|
|
auto src = fbcx.build.GEP(arg, [C_int(0), C_int(i)]);
|
|
|
|
i += 1;
|
|
|
|
auto child_arg = fbcx.build.Load(src);
|
|
|
|
child_args += [child_arg];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Find the function
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-26 18:00:33 -07:00
|
|
|
auto fnptr = trans_lval(fbcx, func).res;
|
|
|
|
fbcx = fnptr.bcx;
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llfnptr = fbcx.build.GEP(fnptr.val, [C_int(0), C_int(0)]);
|
2011-05-26 18:00:33 -07:00
|
|
|
auto llfn = fbcx.build.Load(llfnptr);
|
2011-06-15 11:19:50 -07:00
|
|
|
fbcx.build.FastCall(llfn, child_args);
|
2011-05-26 18:00:33 -07:00
|
|
|
fbcx.build.RetVoid();
|
|
|
|
finish_fn(fcx, fbcx.llbb);
|
|
|
|
// TODO: make sure we clean up everything we need to.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-26 18:00:33 -07:00
|
|
|
ret res(cx, llfndecl);
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_send(&@block_ctxt cx, &@ast::expr lhs, &@ast::expr rhs,
|
|
|
|
&ast::ann ann) -> result {
|
2011-03-17 23:33:00 -04:00
|
|
|
auto bcx = cx;
|
|
|
|
auto chn = trans_expr(bcx, lhs);
|
|
|
|
bcx = chn.bcx;
|
|
|
|
auto data = trans_expr(bcx, rhs);
|
|
|
|
bcx = data.bcx;
|
2011-04-17 14:24:45 +02:00
|
|
|
auto chan_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
|
2011-03-17 23:33:00 -04:00
|
|
|
auto unit_ty;
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(cx.fcx.lcx.ccx.tcx, chan_ty)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_chan(?t)) { unit_ty = t; }
|
|
|
|
case (_) { bcx.fcx.lcx.ccx.sess.bug("non-chan type in trans_send"); }
|
2011-03-17 23:33:00 -04:00
|
|
|
}
|
2011-03-21 21:13:08 -04:00
|
|
|
auto data_alloc = alloc_ty(bcx, unit_ty);
|
|
|
|
bcx = data_alloc.bcx;
|
2011-05-27 17:58:22 -07:00
|
|
|
auto data_tmp = copy_val(bcx, INIT, data_alloc.val, data.val, unit_ty);
|
2011-03-21 21:13:08 -04:00
|
|
|
bcx = data_tmp.bcx;
|
2011-03-21 22:32:11 -04:00
|
|
|
find_scope_cx(bcx).cleanups +=
|
2011-05-16 18:21:22 -07:00
|
|
|
[clean(bind drop_ty(_, data_alloc.val, unit_ty))];
|
2011-05-10 14:03:47 -07:00
|
|
|
auto llchanval = bcx.build.PointerCast(chn.val, T_opaque_chan_ptr());
|
|
|
|
auto lldataptr = bcx.build.PointerCast(data_alloc.val, T_ptr(T_i8()));
|
|
|
|
bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.send,
|
2011-05-16 18:21:22 -07:00
|
|
|
[bcx.fcx.lltaskptr, llchanval, lldataptr]);
|
2011-03-21 21:13:08 -04:00
|
|
|
ret res(bcx, chn.val);
|
2011-03-16 21:49:15 -04:00
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_recv(&@block_ctxt cx, &@ast::expr lhs, &@ast::expr rhs,
|
|
|
|
&ast::ann ann) -> result {
|
2011-03-17 23:33:00 -04:00
|
|
|
auto bcx = cx;
|
2011-03-18 00:45:18 -04:00
|
|
|
auto data = trans_lval(bcx, lhs);
|
2011-05-02 17:47:24 -07:00
|
|
|
assert (data.is_mem);
|
2011-03-18 00:45:18 -04:00
|
|
|
bcx = data.res.bcx;
|
2011-04-17 14:24:45 +02:00
|
|
|
auto unit_ty = node_ann_type(bcx.fcx.lcx.ccx, ann);
|
2011-03-24 21:54:19 -04:00
|
|
|
// FIXME: calculate copy init-ness in typestate.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
ret recv_val(bcx, data.res.val, rhs, unit_ty, DROP_EXISTING);
|
|
|
|
}
|
2011-03-24 21:54:19 -04:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn recv_val(&@block_ctxt cx, ValueRef lhs, &@ast::expr rhs, &ty::t unit_ty,
|
|
|
|
copy_action action) -> result {
|
2011-03-24 21:54:19 -04:00
|
|
|
auto bcx = cx;
|
2011-03-17 23:33:00 -04:00
|
|
|
auto prt = trans_expr(bcx, rhs);
|
|
|
|
bcx = prt.bcx;
|
2011-05-10 14:03:47 -07:00
|
|
|
auto lldataptr = bcx.build.PointerCast(lhs, T_ptr(T_ptr(T_i8())));
|
|
|
|
auto llportptr = bcx.build.PointerCast(prt.val, T_opaque_port_ptr());
|
|
|
|
bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.recv,
|
2011-05-16 18:21:22 -07:00
|
|
|
[bcx.fcx.lltaskptr, lldataptr, llportptr]);
|
2011-04-12 12:06:20 -07:00
|
|
|
auto data_load = load_if_immediate(bcx, lhs, unit_ty);
|
2011-05-27 17:58:22 -07:00
|
|
|
auto cp = copy_val(bcx, action, lhs, data_load, unit_ty);
|
2011-03-21 21:13:08 -04:00
|
|
|
bcx = cp.bcx;
|
2011-03-21 22:32:11 -04:00
|
|
|
// TODO: Any cleanup need to be done here?
|
2011-03-17 23:33:00 -04:00
|
|
|
|
2011-03-24 21:54:19 -04:00
|
|
|
ret res(bcx, lhs);
|
2011-03-16 21:49:15 -04:00
|
|
|
}
|
|
|
|
|
2011-05-20 17:41:36 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
Suppose we create an anonymous object my_b from a regular object a:
|
|
|
|
|
|
|
|
obj a() {
|
|
|
|
fn foo() -> int {
|
|
|
|
ret 2;
|
|
|
|
}
|
|
|
|
fn bar() -> int {
|
|
|
|
ret self.foo();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto my_a = a();
|
|
|
|
auto my_b = obj { fn baz() -> int { ret self.foo() } with my_a };
|
|
|
|
|
|
|
|
Here we're extending the my_a object with an additional method baz, creating
|
|
|
|
an object my_b. Since it's an object, my_b is a pair of a vtable pointer and
|
|
|
|
a body pointer:
|
|
|
|
|
|
|
|
my_b: [vtbl* | body*]
|
|
|
|
|
|
|
|
my_b's vtable has entries for foo, bar, and baz, whereas my_a's vtable has
|
|
|
|
only foo and bar. my_b's 3-entry vtable consists of two forwarding functions
|
|
|
|
and one real method.
|
|
|
|
|
|
|
|
my_b's body just contains the pair a: [ a_vtable | a_body ], wrapped up with
|
|
|
|
any additional fields that my_b added. None were added, so my_b is just the
|
|
|
|
wrapped inner object.
|
|
|
|
|
|
|
|
*/
|
2011-06-09 18:15:55 -07:00
|
|
|
|
2011-06-15 12:18:02 -07:00
|
|
|
// trans_anon_obj: create and return a pointer to an object. This code
|
|
|
|
// differs from trans_obj in that, rather than creating an object constructor
|
|
|
|
// function and putting it in the generated code as an object item, we are
|
|
|
|
// instead "inlining" the construction of the object and returning the object
|
|
|
|
// itself.
|
|
|
|
fn trans_anon_obj(@block_ctxt bcx, &span sp, &ast::anon_obj anon_obj,
|
2011-06-15 11:19:50 -07:00
|
|
|
&vec[ast::ty_param] ty_params, ast::def_id oid,
|
2011-05-20 17:41:36 -07:00
|
|
|
&ast::ann ann) -> result {
|
|
|
|
|
2011-06-15 12:18:02 -07:00
|
|
|
// Right now, we're assuming that anon objs don't take ty params, even
|
|
|
|
// though the AST supports it. It's nonsensical to write an expression
|
|
|
|
// like "obj[T](){ ... with ... }", since T is never instantiated;
|
|
|
|
// nevertheless, such an expression will parse. FIXME for the future:
|
|
|
|
// support typarams (issue #n).
|
|
|
|
assert vec::len(ty_params) == 0u;
|
|
|
|
|
|
|
|
auto ccx = bcx.fcx.lcx.ccx;
|
|
|
|
|
2011-06-09 18:15:55 -07:00
|
|
|
// If with_obj (the object being extended) exists, translate it, producing
|
|
|
|
// a result.
|
2011-05-20 17:41:36 -07:00
|
|
|
let option::t[result] with_obj_val = none[result];
|
|
|
|
alt (anon_obj.with_obj) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (none) { }
|
|
|
|
case (some(?e)) {
|
2011-05-27 17:58:22 -07:00
|
|
|
// Translating with_obj returns a ValueRef (pointer to a 2-word
|
|
|
|
// value) wrapped in a result. We want to allocate space for this
|
|
|
|
// value in our outer object, then copy it into the outer object.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-15 12:18:02 -07:00
|
|
|
with_obj_val = some[result](trans_expr(bcx, e));
|
2011-05-20 17:41:36 -07:00
|
|
|
}
|
|
|
|
}
|
2011-06-09 18:15:55 -07:00
|
|
|
|
|
|
|
// FIXME (part of issue #417): all of the following code is copypasta from
|
|
|
|
// trans_obj for translating the anonymous wrapper object. Eventually we
|
|
|
|
// should abstract this code out of trans_anon_obj and trans_obj.
|
|
|
|
|
2011-06-15 12:18:02 -07:00
|
|
|
auto self_ty = ty::ann_to_type(ccx.tcx, ann);
|
2011-06-09 18:15:55 -07:00
|
|
|
auto llself_ty = type_of(ccx, sp, self_ty);
|
|
|
|
|
2011-06-15 12:18:02 -07:00
|
|
|
// Allocate the object that we're going to return. It's a two-word pair
|
|
|
|
// containing a vtable pointer and a body pointer.
|
|
|
|
auto pair = alloca(bcx, llself_ty);
|
|
|
|
|
2011-06-09 18:15:55 -07:00
|
|
|
// Grab onto the first and second elements of the pair.
|
|
|
|
// abi::obj_field_vtbl and abi::obj_field_box simply specify words 0 and 1
|
|
|
|
// of 'pair'.
|
2011-06-15 11:19:50 -07:00
|
|
|
auto pair_vtbl =
|
|
|
|
bcx.build.GEP(pair, [C_int(0), C_int(abi::obj_field_vtbl)]);
|
|
|
|
auto pair_box =
|
|
|
|
bcx.build.GEP(pair, [C_int(0), C_int(abi::obj_field_box)]);
|
2011-06-09 18:15:55 -07:00
|
|
|
|
2011-06-15 12:18:02 -07:00
|
|
|
// Make a vtable for the outer object. create_vtbl() wants an ast::_obj
|
|
|
|
// and all we have is an ast::anon_obj, so we need to roll our own.
|
|
|
|
let vec[ast::obj_field] addtl_fields = [];
|
|
|
|
alt (anon_obj.fields) {
|
|
|
|
case (none) { }
|
|
|
|
case (some(?fields)) { addtl_fields = fields; }
|
|
|
|
}
|
|
|
|
let ast::_obj wrapper_obj = rec(
|
|
|
|
fields = addtl_fields,
|
|
|
|
methods = anon_obj.methods,
|
|
|
|
dtor = none[@ast::method]);
|
|
|
|
|
|
|
|
auto vtbl = create_vtbl(bcx.fcx.lcx, llself_ty, self_ty, wrapper_obj,
|
|
|
|
ty_params);
|
2011-06-09 18:15:55 -07:00
|
|
|
|
|
|
|
bcx.build.Store(vtbl, pair_vtbl);
|
|
|
|
// FIXME (part of issue #417): This vtable needs to contain "forwarding
|
|
|
|
// slots" for the methods that exist in the with_obj, as well. How do we
|
|
|
|
// do that?
|
|
|
|
|
|
|
|
// Next we have to take care of the other half of the pair we're
|
|
|
|
// returning: a boxed (reference-counted) tuple containing a tydesc,
|
|
|
|
// typarams, and fields.
|
|
|
|
|
|
|
|
// FIXME (part of issue #417): Because this is an anonymous object, we
|
|
|
|
// also have to fill in the with_obj field of this tuple.
|
|
|
|
|
|
|
|
let TypeRef llbox_ty = T_opaque_obj_ptr(ccx.tn);
|
2011-06-15 12:18:02 -07:00
|
|
|
|
|
|
|
alt (anon_obj.fields) {
|
|
|
|
case (none) {
|
|
|
|
// If the object we're translating has no fields or type
|
|
|
|
// parameters, there's not much to do.
|
2011-06-09 18:15:55 -07:00
|
|
|
|
2011-06-15 12:18:02 -07:00
|
|
|
// Store null into pair, if no args or typarams.
|
|
|
|
bcx.build.Store(C_null(llbox_ty), pair_box);
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-09 18:15:55 -07:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-15 12:18:02 -07:00
|
|
|
case (some(?fields)) {
|
|
|
|
// For the moment let's pretend that there are no additional
|
|
|
|
// fields.
|
|
|
|
bcx.fcx.lcx.ccx.sess.unimpl("anon objs don't support "
|
|
|
|
+ "adding fields yet");
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-15 12:18:02 -07:00
|
|
|
// FIXME (issue #417): drop these fields into the newly created
|
|
|
|
// object.
|
2011-06-09 18:15:55 -07:00
|
|
|
}
|
|
|
|
}
|
2011-05-20 17:41:36 -07:00
|
|
|
|
2011-06-09 18:15:55 -07:00
|
|
|
// Return the object we built.
|
|
|
|
ret res(bcx, pair);
|
2011-05-20 17:41:36 -07:00
|
|
|
}
|
|
|
|
|
2011-06-13 17:04:15 -07:00
|
|
|
fn init_local(&@block_ctxt cx, &@ast::local_ local) -> result {
|
2011-01-21 07:58:16 -08:00
|
|
|
// Make a note to drop this slot on the way out.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-02 17:47:24 -07:00
|
|
|
assert (cx.fcx.lllocals.contains_key(local.id));
|
2011-01-21 07:58:16 -08:00
|
|
|
auto llptr = cx.fcx.lllocals.get(local.id);
|
2011-04-17 14:24:45 +02:00
|
|
|
auto ty = node_ann_type(cx.fcx.lcx.ccx, local.ann);
|
2011-01-21 07:58:16 -08:00
|
|
|
auto bcx = cx;
|
2011-06-15 11:19:50 -07:00
|
|
|
find_scope_cx(cx).cleanups += [clean(bind drop_slot(_, llptr, ty))];
|
2011-01-21 07:58:16 -08:00
|
|
|
alt (local.init) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(?init)) {
|
2011-03-24 21:54:19 -04:00
|
|
|
alt (init.op) {
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::init_assign) {
|
2011-06-10 13:39:13 -07:00
|
|
|
// Use the type of the RHS because if it's _|_, the LHS
|
|
|
|
// type might be something else, but we don't want to copy
|
|
|
|
// the value.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
ty =
|
|
|
|
node_ann_type(cx.fcx.lcx.ccx,
|
|
|
|
ty::expr_ann(init.expr));
|
2011-03-24 21:54:19 -04:00
|
|
|
auto sub = trans_expr(bcx, init.expr);
|
2011-05-27 17:58:22 -07:00
|
|
|
bcx = copy_val(sub.bcx, INIT, llptr, sub.val, ty).bcx;
|
2011-03-24 21:54:19 -04:00
|
|
|
}
|
2011-05-31 15:41:08 -07:00
|
|
|
case (ast::init_move) {
|
|
|
|
auto sub = trans_lval(bcx, init.expr);
|
2011-06-15 11:19:50 -07:00
|
|
|
bcx =
|
|
|
|
move_val(sub.res.bcx, INIT, llptr, sub.res.val,
|
|
|
|
ty).bcx;
|
2011-05-31 15:41:08 -07:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::init_recv) {
|
2011-03-24 21:54:19 -04:00
|
|
|
bcx = recv_val(bcx, llptr, init.expr, ty, INIT).bcx;
|
|
|
|
}
|
|
|
|
}
|
2011-01-21 07:58:16 -08:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { bcx = zero_alloca(bcx, llptr, ty).bcx; }
|
2011-01-21 07:58:16 -08:00
|
|
|
}
|
|
|
|
ret res(bcx, llptr);
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn zero_alloca(&@block_ctxt cx, ValueRef llptr, ty::t t) -> result {
|
2011-04-05 23:42:33 -04:00
|
|
|
auto bcx = cx;
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-04-05 23:42:33 -04:00
|
|
|
auto llsz = size_of(bcx, t);
|
2011-05-10 11:50:29 -07:00
|
|
|
auto llalign = align_of(llsz.bcx, t);
|
2011-06-15 11:19:50 -07:00
|
|
|
bcx = call_bzero(llalign.bcx, llptr, llsz.val, llalign.val).bcx;
|
2011-04-05 23:42:33 -04:00
|
|
|
} else {
|
2011-05-18 15:35:16 -07:00
|
|
|
auto llty = type_of(bcx.fcx.lcx.ccx, cx.sp, t);
|
2011-05-12 17:24:54 +02:00
|
|
|
auto null = lib::llvm::llvm::LLVMConstNull(llty);
|
2011-04-05 23:42:33 -04:00
|
|
|
bcx.build.Store(null, llptr);
|
|
|
|
}
|
|
|
|
ret res(bcx, llptr);
|
2011-06-15 11:19:50 -07:00
|
|
|
}
|
2011-04-05 23:42:33 -04:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_stmt(&@block_ctxt cx, &ast::stmt s) -> result {
|
2011-06-15 12:17:51 +02:00
|
|
|
// FIXME Fill in cx.sp
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
auto bcx = cx;
|
2010-10-05 18:21:44 -07:00
|
|
|
alt (s.node) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ast::stmt_expr(?e, _)) { bcx = trans_expr(cx, e).bcx; }
|
|
|
|
case (ast::stmt_decl(?d, _)) {
|
2010-10-19 14:54:10 -07:00
|
|
|
alt (d.node) {
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::decl_local(?local)) {
|
2011-01-21 07:58:16 -08:00
|
|
|
bcx = init_local(bcx, local).bcx;
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ast::decl_item(?i)) { trans_item(cx.fcx.lcx, *i); }
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { cx.fcx.lcx.ccx.sess.unimpl("stmt variant"); }
|
2010-09-23 13:15:51 -07:00
|
|
|
}
|
2011-01-21 07:58:16 -08:00
|
|
|
ret res(bcx, C_nil());
|
2010-10-01 18:25:42 -07:00
|
|
|
}
|
|
|
|
|
2010-12-17 18:42:15 -08:00
|
|
|
fn new_builder(BasicBlockRef llbb) -> builder {
|
2011-05-12 17:24:54 +02:00
|
|
|
let BuilderRef llbuild = llvm::LLVMCreateBuilder();
|
|
|
|
llvm::LLVMPositionBuilderAtEnd(llbuild, llbb);
|
2011-04-19 10:23:49 -07:00
|
|
|
ret builder(llbuild, @mutable false);
|
2010-09-27 13:43:53 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-10-04 15:55:12 -07:00
|
|
|
// You probably don't want to use this one. See the
|
|
|
|
// next three functions instead.
|
2011-06-15 11:19:50 -07:00
|
|
|
fn new_block_ctxt(&@fn_ctxt cx, &block_parent parent, block_kind kind,
|
2011-05-11 04:58:46 +00:00
|
|
|
&str name) -> @block_ctxt {
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[cleanup] cleanups = [];
|
2011-05-17 20:41:41 +02:00
|
|
|
auto s = str::buf("");
|
2011-05-10 16:43:34 -07:00
|
|
|
if (cx.lcx.ccx.sess.get_opts().save_temps) {
|
2011-05-17 20:41:41 +02:00
|
|
|
s = str::buf(cx.lcx.ccx.names.next(name));
|
2011-05-10 16:43:34 -07:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
let BasicBlockRef llbb = llvm::LLVMAppendBasicBlock(cx.llfn, s);
|
2010-09-27 15:38:34 -07:00
|
|
|
ret @rec(llbb=llbb,
|
2010-12-17 18:42:15 -08:00
|
|
|
build=new_builder(llbb),
|
2010-11-10 17:46:49 -08:00
|
|
|
parent=parent,
|
2011-01-24 15:26:10 -08:00
|
|
|
kind=kind,
|
2010-09-29 17:22:07 -07:00
|
|
|
mutable cleanups=cleanups,
|
2011-05-18 15:35:16 -07:00
|
|
|
sp=cx.sp,
|
2010-09-27 15:38:34 -07:00
|
|
|
fcx=cx);
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-10-04 15:55:12 -07:00
|
|
|
// Use this when you're at the top block of a function or the like.
|
2011-05-11 04:58:46 +00:00
|
|
|
fn new_top_block_ctxt(&@fn_ctxt fcx) -> @block_ctxt {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret new_block_ctxt(fcx, parent_none, SCOPE_BLOCK, "function top level");
|
2010-12-02 19:12:34 -08:00
|
|
|
}
|
2010-10-04 15:55:12 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-12-02 19:12:34 -08:00
|
|
|
// Use this when you're at a curly-brace or similar lexical scope.
|
2011-05-11 04:58:46 +00:00
|
|
|
fn new_scope_block_ctxt(&@block_ctxt bcx, &str n) -> @block_ctxt {
|
2011-01-24 15:26:10 -08:00
|
|
|
ret new_block_ctxt(bcx.fcx, parent_some(bcx), SCOPE_BLOCK, n);
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn new_loop_scope_block_ctxt(&@block_ctxt bcx, &option::t[@block_ctxt] _cont,
|
2011-05-11 04:58:46 +00:00
|
|
|
&@block_ctxt _break, &str n) -> @block_ctxt {
|
2011-03-25 16:28:16 +01:00
|
|
|
ret new_block_ctxt(bcx.fcx, parent_some(bcx),
|
|
|
|
LOOP_SCOPE_BLOCK(_cont, _break), n);
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-12-02 19:12:34 -08:00
|
|
|
// Use this when you're making a general CFG BB within a scope.
|
2011-05-11 04:58:46 +00:00
|
|
|
fn new_sub_block_ctxt(&@block_ctxt bcx, &str n) -> @block_ctxt {
|
2011-01-24 15:26:10 -08:00
|
|
|
ret new_block_ctxt(bcx.fcx, parent_some(bcx), NON_SCOPE_BLOCK, n);
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
2010-09-29 17:22:07 -07:00
|
|
|
|
2011-05-11 11:56:49 -07:00
|
|
|
fn new_raw_block_ctxt(&@fn_ctxt fcx, BasicBlockRef llbb) -> @block_ctxt {
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[cleanup] cleanups = [];
|
2011-06-15 11:19:50 -07:00
|
|
|
ret @rec(llbb=llbb,
|
|
|
|
build=new_builder(llbb),
|
|
|
|
parent=parent_none,
|
|
|
|
kind=NON_SCOPE_BLOCK,
|
|
|
|
mutable cleanups=cleanups,
|
|
|
|
sp=fcx.sp,
|
2011-05-18 15:35:16 -07:00
|
|
|
fcx=fcx);
|
2011-05-11 11:56:49 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-27 17:58:22 -07:00
|
|
|
// trans_block_cleanups: Go through all the cleanups attached to this
|
|
|
|
// block_ctxt and execute them.
|
|
|
|
//
|
|
|
|
// When translating a block that introdces new variables during its scope, we
|
|
|
|
// need to make sure those variables go out of scope when the block ends. We
|
|
|
|
// do that by running a 'cleanup' function for each variable.
|
|
|
|
// trans_block_cleanups runs all the cleanup functions for the block.
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_block_cleanups(&@block_ctxt cx, &@block_ctxt cleanup_cx) ->
|
|
|
|
@block_ctxt {
|
2010-10-04 15:55:12 -07:00
|
|
|
auto bcx = cx;
|
2011-03-25 16:28:16 +01:00
|
|
|
if (cleanup_cx.kind == NON_SCOPE_BLOCK) {
|
2011-05-17 20:41:41 +02:00
|
|
|
assert (vec::len[cleanup](cleanup_cx.cleanups) == 0u);
|
2010-12-02 19:12:34 -08:00
|
|
|
}
|
2011-05-17 20:41:41 +02:00
|
|
|
auto i = vec::len[cleanup](cleanup_cx.cleanups);
|
2011-01-31 12:06:27 -08:00
|
|
|
while (i > 0u) {
|
|
|
|
i -= 1u;
|
|
|
|
auto c = cleanup_cx.cleanups.(i);
|
2011-06-15 11:19:50 -07:00
|
|
|
alt (c) { case (clean(?cfn)) { bcx = cfn(bcx).bcx; } }
|
2010-09-29 17:22:07 -07:00
|
|
|
}
|
2010-10-04 15:55:12 -07:00
|
|
|
ret bcx;
|
|
|
|
}
|
|
|
|
|
2011-06-13 17:04:15 -07:00
|
|
|
iter block_locals(&ast::block b) -> @ast::local_ {
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-10-19 14:54:10 -07:00
|
|
|
// FIXME: putting from inside an iter block doesn't work, so we can't
|
|
|
|
// use the index here.
|
2011-05-12 17:24:54 +02:00
|
|
|
for (@ast::stmt s in b.node.stmts) {
|
2010-10-19 14:54:10 -07:00
|
|
|
alt (s.node) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ast::stmt_decl(?d, _)) {
|
2010-10-19 14:54:10 -07:00
|
|
|
alt (d.node) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ast::decl_local(?local)) { put local; }
|
|
|
|
case (_) {/* fall through */ }
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) {/* fall through */ }
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn llallocas_block_ctxt(&@fn_ctxt fcx) -> @block_ctxt {
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[cleanup] cleanups = [];
|
2011-03-28 18:04:52 -07:00
|
|
|
ret @rec(llbb=fcx.llallocas,
|
|
|
|
build=new_builder(fcx.llallocas),
|
|
|
|
parent=parent_none,
|
|
|
|
kind=SCOPE_BLOCK,
|
|
|
|
mutable cleanups=cleanups,
|
2011-05-18 15:35:16 -07:00
|
|
|
sp=fcx.sp,
|
2011-03-28 18:04:52 -07:00
|
|
|
fcx=fcx);
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn alloc_ty(&@block_ctxt cx, &ty::t t) -> result {
|
2011-01-21 07:58:16 -08:00
|
|
|
auto val = C_int(0);
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-03-28 18:04:52 -07:00
|
|
|
// NB: we have to run this particular 'size_of' in a
|
|
|
|
// block_ctxt built on the llallocas block for the fn,
|
|
|
|
// so that the size dominates the array_alloca that
|
|
|
|
// comes next.
|
|
|
|
|
|
|
|
auto n = size_of(llallocas_block_ctxt(cx.fcx), t);
|
|
|
|
cx.fcx.llallocas = n.bcx.llbb;
|
|
|
|
val = array_alloca(cx, T_i8(), n.val);
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { val = alloca(cx, type_of(cx.fcx.lcx.ccx, cx.sp, t)); }
|
2011-03-28 18:04:52 -07:00
|
|
|
// NB: since we've pushed all size calculations in this
|
|
|
|
// function up to the alloca block, we actually return the
|
|
|
|
// block passed into us unmodified; it doesn't really
|
|
|
|
// have to be passed-and-returned here, but it fits
|
|
|
|
// past caller conventions and may well make sense again,
|
|
|
|
// so we leave it as-is.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-28 18:04:52 -07:00
|
|
|
ret res(cx, val);
|
2011-01-21 07:58:16 -08:00
|
|
|
}
|
|
|
|
|
2011-06-13 17:04:15 -07:00
|
|
|
fn alloc_local(&@block_ctxt cx, &@ast::local_ local) -> result {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto t = node_ann_type(cx.fcx.lcx.ccx, local.ann);
|
2011-02-10 15:00:16 -08:00
|
|
|
auto r = alloc_ty(cx, t);
|
|
|
|
r.bcx.fcx.lllocals.insert(local.id, r.val);
|
|
|
|
ret r;
|
|
|
|
}
|
|
|
|
|
2011-05-31 14:24:04 +02:00
|
|
|
fn trans_block(&@block_ctxt cx, &ast::block b, &out_method output) -> result {
|
2010-10-04 15:55:12 -07:00
|
|
|
auto bcx = cx;
|
2011-06-13 17:04:15 -07:00
|
|
|
for each (@ast::local_ local in block_locals(b)) {
|
2011-06-15 12:17:51 +02:00
|
|
|
// FIXME Update bcx.sp
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
bcx = alloc_local(bcx, local).bcx;
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2010-11-10 17:46:49 -08:00
|
|
|
auto r = res(bcx, C_nil());
|
2011-05-12 17:24:54 +02:00
|
|
|
for (@ast::stmt s in b.node.stmts) {
|
2010-11-10 17:46:49 -08:00
|
|
|
r = trans_stmt(bcx, *s);
|
|
|
|
bcx = r.bcx;
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-11-12 10:15:40 -08:00
|
|
|
// If we hit a terminator, control won't go any further so
|
|
|
|
// we're in dead-code land. Stop here.
|
2011-06-15 11:19:50 -07:00
|
|
|
if (is_terminated(bcx)) { ret r; }
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
2011-05-31 14:24:04 +02:00
|
|
|
fn accept_out_method(&@ast::expr expr) -> bool {
|
|
|
|
ret alt (expr.node) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ast::expr_if(_, _, _, _)) { true }
|
|
|
|
case (ast::expr_alt(_, _, _)) { true }
|
|
|
|
case (ast::expr_block(_, _)) { true }
|
|
|
|
case (_) { false }
|
|
|
|
};
|
2011-05-31 14:24:04 +02:00
|
|
|
}
|
2010-11-29 17:11:03 -08:00
|
|
|
alt (b.node.expr) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(?e)) {
|
2011-05-31 14:24:04 +02:00
|
|
|
auto pass = output != return && accept_out_method(e);
|
|
|
|
if (pass) {
|
|
|
|
r = trans_expr_out(bcx, e, output);
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { r = trans_expr(bcx, e); }
|
2010-11-29 17:11:03 -08:00
|
|
|
bcx = r.bcx;
|
2011-05-31 14:24:04 +02:00
|
|
|
auto ccx = cx.fcx.lcx.ccx;
|
|
|
|
auto r_ty = ty::expr_ty(ccx.tcx, e);
|
2011-06-15 11:19:50 -07:00
|
|
|
if (is_terminated(bcx) || ty::type_is_bot(ccx.tcx, r_ty)) {
|
2010-11-29 17:11:03 -08:00
|
|
|
ret r;
|
2011-05-31 14:24:04 +02:00
|
|
|
} else if (!pass) {
|
|
|
|
alt (output) {
|
|
|
|
case (save_in(?target)) {
|
|
|
|
// The output method is to save the value at target,
|
|
|
|
// and we didn't pass it to the recursive trans_expr
|
|
|
|
// call.
|
|
|
|
// FIXME Use move semantics!
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
auto res_copy =
|
|
|
|
copy_val(bcx, INIT, target, r.val, r_ty);
|
2011-05-31 14:24:04 +02:00
|
|
|
bcx = res_copy.bcx;
|
|
|
|
r = res(bcx, C_nil());
|
2011-03-31 21:20:10 -04:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (return) { }
|
2011-03-31 21:20:10 -04:00
|
|
|
}
|
2010-11-29 17:11:03 -08:00
|
|
|
}
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (none) { r = res(bcx, C_nil()); }
|
2010-11-29 17:11:03 -08:00
|
|
|
}
|
2010-12-02 19:44:24 -08:00
|
|
|
bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
|
2010-11-10 17:46:49 -08:00
|
|
|
ret res(bcx, r.val);
|
2010-09-23 13:15:51 -07:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn new_local_ctxt(&@crate_ctxt ccx) -> @local_ctxt {
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[str] pth = [];
|
|
|
|
let vec[ast::ty_param] obj_typarams = [];
|
|
|
|
let vec[ast::obj_field] obj_fields = [];
|
2011-04-20 17:23:45 +02:00
|
|
|
ret @rec(path=pth,
|
2011-06-07 17:54:22 -07:00
|
|
|
module_path=[ccx.crate_meta_name],
|
2011-06-15 11:19:50 -07:00
|
|
|
obj_typarams=obj_typarams,
|
|
|
|
obj_fields=obj_fields,
|
|
|
|
ccx=ccx);
|
2011-04-20 17:23:45 +02:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-11 11:56:49 -07:00
|
|
|
// Creates the standard trio of basic blocks: allocas, copy-args, and derived
|
|
|
|
// tydescs.
|
|
|
|
fn mk_standard_basic_blocks(ValueRef llfn) ->
|
2011-06-15 11:19:50 -07:00
|
|
|
tup(BasicBlockRef, BasicBlockRef, BasicBlockRef) {
|
2011-05-17 20:41:41 +02:00
|
|
|
ret tup(llvm::LLVMAppendBasicBlock(llfn, str::buf("allocas")),
|
|
|
|
llvm::LLVMAppendBasicBlock(llfn, str::buf("copy_args")),
|
|
|
|
llvm::LLVMAppendBasicBlock(llfn, str::buf("derived_tydescs")));
|
2011-05-11 11:56:49 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-02-08 11:47:53 -08:00
|
|
|
// NB: must keep 4 fns in sync:
|
|
|
|
//
|
|
|
|
// - type_of_fn_full
|
|
|
|
// - create_llargs_for_fn_args.
|
|
|
|
// - new_fn_ctxt
|
|
|
|
// - trans_args
|
2011-06-15 11:19:50 -07:00
|
|
|
fn new_fn_ctxt(@local_ctxt cx, &span sp, ValueRef llfndecl) -> @fn_ctxt {
|
2011-05-12 17:24:54 +02:00
|
|
|
let ValueRef llretptr = llvm::LLVMGetParam(llfndecl, 0u);
|
|
|
|
let ValueRef lltaskptr = llvm::LLVMGetParam(llfndecl, 1u);
|
|
|
|
let ValueRef llenv = llvm::LLVMGetParam(llfndecl, 2u);
|
|
|
|
let hashmap[ast::def_id, ValueRef] llargs = new_def_hash[ValueRef]();
|
|
|
|
let hashmap[ast::def_id, ValueRef] llobjfields = new_def_hash[ValueRef]();
|
|
|
|
let hashmap[ast::def_id, ValueRef] lllocals = new_def_hash[ValueRef]();
|
|
|
|
let hashmap[ast::def_id, ValueRef] llupvars = new_def_hash[ValueRef]();
|
2011-05-11 11:56:49 -07:00
|
|
|
auto derived_tydescs =
|
2011-05-12 17:24:54 +02:00
|
|
|
map::mk_hashmap[ty::t, derived_tydesc_info](ty::hash_ty, ty::eq_ty);
|
2011-05-11 11:56:49 -07:00
|
|
|
auto llbbs = mk_standard_basic_blocks(llfndecl);
|
2010-12-09 15:26:16 -08:00
|
|
|
ret @rec(llfn=llfndecl,
|
2010-09-27 15:38:34 -07:00
|
|
|
lltaskptr=lltaskptr,
|
2011-02-08 11:47:53 -08:00
|
|
|
llenv=llenv,
|
|
|
|
llretptr=llretptr,
|
2011-05-11 11:56:49 -07:00
|
|
|
mutable llallocas=llbbs._0,
|
|
|
|
mutable llcopyargs=llbbs._1,
|
|
|
|
mutable llderivedtydescs=llbbs._2,
|
2011-06-01 11:34:52 -07:00
|
|
|
mutable llself=none[val_self_pair],
|
2011-02-17 12:20:55 -08:00
|
|
|
mutable lliterbody=none[ValueRef],
|
2010-10-21 18:13:57 -07:00
|
|
|
llargs=llargs,
|
2010-12-30 17:01:20 -08:00
|
|
|
llobjfields=llobjfields,
|
2010-10-19 14:54:10 -07:00
|
|
|
lllocals=lllocals,
|
2011-03-10 16:49:00 -08:00
|
|
|
llupvars=llupvars,
|
2011-05-17 20:41:41 +02:00
|
|
|
mutable lltydescs=vec::empty[ValueRef](),
|
2011-05-11 11:56:49 -07:00
|
|
|
derived_tydescs=derived_tydescs,
|
2011-05-18 15:35:16 -07:00
|
|
|
sp=sp,
|
2011-04-17 14:24:45 +02:00
|
|
|
lcx=cx);
|
2010-09-27 15:38:34 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-02-08 11:47:53 -08:00
|
|
|
// NB: must keep 4 fns in sync:
|
|
|
|
//
|
|
|
|
// - type_of_fn_full
|
|
|
|
// - create_llargs_for_fn_args.
|
|
|
|
// - new_fn_ctxt
|
|
|
|
// - trans_args
|
|
|
|
|
2011-06-01 11:34:52 -07:00
|
|
|
// create_llargs_for_fn_args: Creates a mapping from incoming arguments to
|
|
|
|
// allocas created for them.
|
|
|
|
//
|
|
|
|
// When we translate a function, we need to map its incoming arguments to the
|
|
|
|
// spaces that have been created for them (by code in the llallocas field of
|
|
|
|
// the function's fn_ctxt). create_llargs_for_fn_args populates the llargs
|
|
|
|
// field of the fn_ctxt with
|
2011-06-15 11:19:50 -07:00
|
|
|
fn create_llargs_for_fn_args(&@fn_ctxt cx, ast::proto proto,
|
|
|
|
option::t[ty_self_pair] ty_self, ty::t ret_ty,
|
2011-05-12 17:24:54 +02:00
|
|
|
&vec[ast::arg] args,
|
|
|
|
&vec[ast::ty_param] ty_params) {
|
2011-06-01 11:34:52 -07:00
|
|
|
// Skip the implicit arguments 0, 1, and 2. TODO: Pull out 3u and define
|
|
|
|
// it as a constant, since we're using it in several places in trans this
|
|
|
|
// way.
|
2010-12-23 17:31:16 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto arg_n = 3u;
|
2011-04-05 14:18:44 -07:00
|
|
|
alt (ty_self) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(?tt)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.llself = some[val_self_pair](rec(v=cx.llenv, t=tt._1));
|
2011-04-05 14:18:44 -07:00
|
|
|
}
|
2011-05-31 00:39:19 -04:00
|
|
|
case (none) {
|
2011-04-12 15:09:50 -07:00
|
|
|
auto i = 0u;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ast::ty_param tp in ty_params) {
|
|
|
|
auto llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
|
2011-05-02 17:47:24 -07:00
|
|
|
assert (llarg as int != 0);
|
2011-05-16 18:21:22 -07:00
|
|
|
cx.lltydescs += [llarg];
|
2011-04-05 14:18:44 -07:00
|
|
|
arg_n += 1u;
|
2011-04-12 15:09:50 -07:00
|
|
|
i += 1u;
|
2011-04-05 14:18:44 -07:00
|
|
|
}
|
2011-02-09 09:54:58 -08:00
|
|
|
}
|
2010-12-20 14:33:11 -08:00
|
|
|
}
|
2011-06-01 11:34:52 -07:00
|
|
|
// If the function is actually an iter, populate the lliterbody field of
|
|
|
|
// the function context with the ValueRef that we get from
|
|
|
|
// llvm::LLVMGetParam for the iter's body.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
if (proto == ast::proto_iter) {
|
|
|
|
auto llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
|
2011-05-02 17:47:24 -07:00
|
|
|
assert (llarg as int != 0);
|
2011-02-17 12:20:55 -08:00
|
|
|
cx.lliterbody = some[ValueRef](llarg);
|
|
|
|
arg_n += 1u;
|
|
|
|
}
|
2010-12-23 17:31:16 -08:00
|
|
|
|
2011-06-01 11:34:52 -07:00
|
|
|
// Populate the llargs field of the function context with the ValueRefs
|
|
|
|
// that we get from llvm::LLVMGetParam for each argument.
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ast::arg arg in args) {
|
|
|
|
auto llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
|
2011-05-02 17:47:24 -07:00
|
|
|
assert (llarg as int != 0);
|
2010-12-09 17:38:17 -08:00
|
|
|
cx.llargs.insert(arg.id, llarg);
|
|
|
|
arg_n += 1u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-11-26 17:47:27 -08:00
|
|
|
// Recommended LLVM style, strange though this is, is to copy from args to
|
|
|
|
// allocas immediately upon entry; this permits us to GEP into structures we
|
|
|
|
// were passed and whatnot. Apparently mem2reg will mop up.
|
2011-06-15 11:19:50 -07:00
|
|
|
fn copy_any_self_to_alloca(@fn_ctxt fcx, option::t[ty_self_pair] ty_self) {
|
2011-03-28 18:04:52 -07:00
|
|
|
auto bcx = llallocas_block_ctxt(fcx);
|
2011-06-15 11:19:50 -07:00
|
|
|
alt ({ fcx.llself }) {
|
2011-06-01 11:34:52 -07:00
|
|
|
case (some(?pair)) {
|
2010-12-30 17:01:20 -08:00
|
|
|
alt (ty_self) {
|
2011-06-01 11:34:52 -07:00
|
|
|
case (some[ty_self_pair](?tt)) {
|
2011-04-05 14:18:44 -07:00
|
|
|
auto a = alloca(bcx, tt._0);
|
2011-06-01 11:34:52 -07:00
|
|
|
bcx.build.Store(pair.v, a);
|
2011-06-15 11:19:50 -07:00
|
|
|
fcx.llself = some[val_self_pair](rec(v=a, t=pair.t));
|
2010-12-30 17:01:20 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { }
|
2010-12-30 17:01:20 -08:00
|
|
|
}
|
2011-03-28 18:04:52 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn copy_args_to_allocas(@fn_ctxt fcx, vec[ast::arg] args,
|
2011-05-12 17:24:54 +02:00
|
|
|
vec[ty::arg] arg_tys) {
|
2011-05-11 11:56:49 -07:00
|
|
|
auto bcx = new_raw_block_ctxt(fcx, fcx.llcopyargs);
|
|
|
|
let uint arg_n = 0u;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ast::arg aarg in args) {
|
2011-06-10 12:03:50 +02:00
|
|
|
if (aarg.mode == ast::val) {
|
2011-05-18 15:35:16 -07:00
|
|
|
auto arg_t = type_of_arg(bcx.fcx.lcx, fcx.sp, arg_tys.(arg_n));
|
2011-03-28 18:04:52 -07:00
|
|
|
auto a = alloca(bcx, arg_t);
|
2011-05-10 18:29:14 -07:00
|
|
|
auto argval = bcx.fcx.llargs.get(aarg.id);
|
2011-03-28 18:04:52 -07:00
|
|
|
bcx.build.Store(argval, a);
|
2010-12-07 12:34:10 -08:00
|
|
|
// Overwrite the llargs entry for this arg with its alloca.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-10 18:29:14 -07:00
|
|
|
bcx.fcx.llargs.insert(aarg.id, a);
|
2010-12-07 12:34:10 -08:00
|
|
|
}
|
2010-11-26 17:47:27 -08:00
|
|
|
arg_n += 1u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn add_cleanups_for_args(&@block_ctxt bcx, vec[ast::arg] args,
|
2011-05-12 17:24:54 +02:00
|
|
|
vec[ty::arg] arg_tys) {
|
2011-04-28 11:24:16 -07:00
|
|
|
let uint arg_n = 0u;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ast::arg aarg in args) {
|
2011-06-10 12:03:50 +02:00
|
|
|
if (aarg.mode == ast::val) {
|
2011-04-28 11:24:16 -07:00
|
|
|
auto argval = bcx.fcx.llargs.get(aarg.id);
|
|
|
|
find_scope_cx(bcx).cleanups +=
|
2011-05-16 18:21:22 -07:00
|
|
|
[clean(bind drop_slot(_, argval, arg_tys.(arg_n).ty))];
|
2011-04-28 11:24:16 -07:00
|
|
|
}
|
|
|
|
arg_n += 1u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-10 17:58:22 -07:00
|
|
|
fn is_terminated(&@block_ctxt cx) -> bool {
|
2011-05-12 17:24:54 +02:00
|
|
|
auto inst = llvm::LLVMGetLastInstruction(cx.llbb);
|
|
|
|
ret llvm::LLVMIsATerminatorInst(inst) as int != 0;
|
2010-11-10 17:46:49 -08:00
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn arg_tys_of_fn(&@crate_ctxt ccx, ast::ann ann) -> vec[ty::arg] {
|
2011-06-07 13:50:30 -07:00
|
|
|
alt (ty::struct(ccx.tcx, ty::ann_to_type(ccx.tcx, ann))) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_fn(_, ?arg_tys, _, _, _)) { ret arg_tys; }
|
2010-12-06 11:22:08 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn ret_ty_of_fn_ty(&@crate_ctxt ccx, ty::t t) -> ty::t {
|
|
|
|
alt (ty::struct(ccx.tcx, t)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_fn(_, _, ?ret_ty, _, _)) { ret ret_ty; }
|
2011-06-15 12:18:02 -07:00
|
|
|
case (_) {
|
|
|
|
ccx.sess.bug("ret_ty_of_fn_ty() called on non-function type: "
|
|
|
|
+ ty_to_str(ccx.tcx, t));
|
|
|
|
}
|
2010-12-16 15:55:28 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn ret_ty_of_fn(&@crate_ctxt ccx, ast::ann ann) -> ty::t {
|
2011-06-07 13:50:30 -07:00
|
|
|
ret ret_ty_of_fn_ty(ccx, ty::ann_to_type(ccx.tcx, ann));
|
2011-01-07 15:12:23 -08:00
|
|
|
}
|
|
|
|
|
2011-06-01 11:34:52 -07:00
|
|
|
fn populate_fn_ctxt_from_llself(@fn_ctxt fcx, val_self_pair llself) {
|
2011-03-28 18:04:52 -07:00
|
|
|
auto bcx = llallocas_block_ctxt(fcx);
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ty::t] field_tys = [];
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ast::obj_field f in bcx.fcx.lcx.obj_fields) {
|
2011-05-16 18:21:22 -07:00
|
|
|
field_tys += [node_ann_type(bcx.fcx.lcx.ccx, f.ann)];
|
2010-12-30 17:01:20 -08:00
|
|
|
}
|
2011-03-03 11:49:35 -08:00
|
|
|
// Synthesize a tuple type for the fields so that GEP_tup_like() can work
|
|
|
|
// its magic.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto fields_tup_ty = ty::mk_imm_tup(fcx.lcx.ccx.tcx, field_tys);
|
2011-05-17 20:41:41 +02:00
|
|
|
auto n_typarams = vec::len[ast::ty_param](bcx.fcx.lcx.obj_typarams);
|
2011-04-17 14:24:45 +02:00
|
|
|
let TypeRef llobj_box_ty = T_obj_ptr(bcx.fcx.lcx.ccx.tn, n_typarams);
|
2010-12-30 17:01:20 -08:00
|
|
|
auto box_cell =
|
2011-06-15 11:19:50 -07:00
|
|
|
bcx.build.GEP(llself.v, [C_int(0), C_int(abi::obj_field_box)]);
|
2011-03-03 11:49:35 -08:00
|
|
|
auto box_ptr = bcx.build.Load(box_cell);
|
|
|
|
box_ptr = bcx.build.PointerCast(box_ptr, llobj_box_ty);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto obj_typarams =
|
|
|
|
bcx.build.GEP(box_ptr,
|
|
|
|
[C_int(0), C_int(abi::box_rc_field_body),
|
|
|
|
C_int(abi::obj_body_elt_typarams)]);
|
2011-03-03 11:49:35 -08:00
|
|
|
// The object fields immediately follow the type parameters, so we skip
|
|
|
|
// over them to get the pointer.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto et = llvm::LLVMGetElementType(val_ty(obj_typarams));
|
|
|
|
auto obj_fields = bcx.build.Add(vp2i(bcx, obj_typarams), llsize_of(et));
|
2011-03-03 11:49:35 -08:00
|
|
|
// If we can (i.e. the type is statically sized), then cast the resulting
|
|
|
|
// fields pointer to the appropriate LLVM type. If not, just leave it as
|
|
|
|
// i8 *.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
if (!ty::type_has_dynamic_size(fcx.lcx.ccx.tcx, fields_tup_ty)) {
|
2011-05-18 15:35:16 -07:00
|
|
|
auto llfields_ty = type_of(fcx.lcx.ccx, fcx.sp, fields_tup_ty);
|
2011-03-03 11:49:35 -08:00
|
|
|
obj_fields = vi2p(bcx, obj_fields, T_ptr(llfields_ty));
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { obj_fields = vi2p(bcx, obj_fields, T_ptr(T_i8())); }
|
2010-12-30 17:01:20 -08:00
|
|
|
let int i = 0;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ast::ty_param p in fcx.lcx.obj_typarams) {
|
2011-06-15 11:19:50 -07:00
|
|
|
let ValueRef lltyparam =
|
|
|
|
bcx.build.GEP(obj_typarams, [C_int(0), C_int(i)]);
|
2011-03-03 11:49:35 -08:00
|
|
|
lltyparam = bcx.build.Load(lltyparam);
|
2011-05-16 18:21:22 -07:00
|
|
|
fcx.lltydescs += [lltyparam];
|
2011-02-03 14:40:57 -08:00
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
i = 0;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ast::obj_field f in fcx.lcx.obj_fields) {
|
2011-05-16 18:21:22 -07:00
|
|
|
auto rslt = GEP_tup_like(bcx, fields_tup_ty, obj_fields, [0, i]);
|
2011-03-28 18:04:52 -07:00
|
|
|
bcx = llallocas_block_ctxt(fcx);
|
2011-03-03 11:49:35 -08:00
|
|
|
auto llfield = rslt.val;
|
2011-03-28 18:04:52 -07:00
|
|
|
fcx.llobjfields.insert(f.id, llfield);
|
2010-12-30 17:01:20 -08:00
|
|
|
i += 1;
|
|
|
|
}
|
2011-03-28 18:04:52 -07:00
|
|
|
fcx.llallocas = bcx.llbb;
|
2010-12-30 17:01:20 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-11 11:56:49 -07:00
|
|
|
// Ties up the llallocas -> llcopyargs -> llderivedtydescs -> lltop edges.
|
|
|
|
fn finish_fn(&@fn_ctxt fcx, BasicBlockRef lltop) {
|
|
|
|
new_builder(fcx.llallocas).Br(fcx.llcopyargs);
|
|
|
|
new_builder(fcx.llcopyargs).Br(fcx.llderivedtydescs);
|
|
|
|
new_builder(fcx.llderivedtydescs).Br(lltop);
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-27 17:58:22 -07:00
|
|
|
// trans_fn: creates an LLVM function corresponding to a source language
|
|
|
|
// function.
|
2011-06-14 15:20:04 +02:00
|
|
|
fn trans_fn(@local_ctxt cx, &span sp, &ast::_fn f, ValueRef llfndecl,
|
2011-06-15 11:19:50 -07:00
|
|
|
option::t[ty_self_pair] ty_self, &vec[ast::ty_param] ty_params,
|
|
|
|
&ast::ann ann) {
|
2011-05-24 13:47:27 -04:00
|
|
|
set_uwtable(llfndecl);
|
2011-06-03 17:09:50 -07:00
|
|
|
// Set up arguments to the function.
|
2010-11-26 17:47:27 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto fcx = new_fn_ctxt(cx, sp, llfndecl);
|
|
|
|
create_llargs_for_fn_args(fcx, f.proto, ty_self,
|
|
|
|
ret_ty_of_fn(cx.ccx, ann), f.decl.inputs,
|
|
|
|
ty_params);
|
2011-03-28 18:04:52 -07:00
|
|
|
copy_any_self_to_alloca(fcx, ty_self);
|
2011-06-15 11:19:50 -07:00
|
|
|
alt ({ fcx.llself }) {
|
|
|
|
case (some(?llself)) { populate_fn_ctxt_from_llself(fcx, llself); }
|
|
|
|
case (_) { }
|
2010-12-30 17:01:20 -08:00
|
|
|
}
|
2011-04-28 11:24:16 -07:00
|
|
|
auto arg_tys = arg_tys_of_fn(fcx.lcx.ccx, ann);
|
2011-05-11 11:56:49 -07:00
|
|
|
copy_args_to_allocas(fcx, f.decl.inputs, arg_tys);
|
2011-06-03 17:09:50 -07:00
|
|
|
// Create the first basic block in the function and keep a handle on it to
|
|
|
|
// pass to finish_fn later.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-28 18:04:52 -07:00
|
|
|
auto bcx = new_top_block_ctxt(fcx);
|
2011-04-28 11:24:16 -07:00
|
|
|
add_cleanups_for_args(bcx, f.decl.inputs, arg_tys);
|
2011-03-28 18:04:52 -07:00
|
|
|
auto lltop = bcx.llbb;
|
2011-05-31 15:24:18 -04:00
|
|
|
auto block_ty = node_ann_type(cx.ccx, f.body.node.a);
|
2011-06-01 11:34:52 -07:00
|
|
|
// This call to trans_block is the place where we bridge between
|
|
|
|
// translation calls that don't have a return value (trans_crate,
|
|
|
|
// trans_mod, trans_item, trans_obj, et cetera) and those that do
|
|
|
|
// (trans_block, trans_expr, et cetera).
|
2011-05-31 15:24:18 -04:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto res =
|
|
|
|
if (!ty::type_is_nil(cx.ccx.tcx, block_ty) &&
|
|
|
|
!ty::type_is_bot(cx.ccx.tcx, block_ty)) {
|
|
|
|
trans_block(bcx, f.body, save_in(fcx.llretptr))
|
|
|
|
} else { trans_block(bcx, f.body, return) };
|
2010-11-10 17:46:49 -08:00
|
|
|
if (!is_terminated(res.bcx)) {
|
2010-11-14 13:04:01 -08:00
|
|
|
// FIXME: until LLVM has a unit type, we are moving around
|
|
|
|
// C_nil values rather than their void type.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-12-13 16:12:45 -08:00
|
|
|
res.bcx.build.RetVoid();
|
2010-11-10 17:46:49 -08:00
|
|
|
}
|
2011-06-03 17:09:50 -07:00
|
|
|
// Insert the mandatory first few basic blocks before lltop.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-11 11:56:49 -07:00
|
|
|
finish_fn(fcx, lltop);
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-03 17:09:50 -07:00
|
|
|
// Create a vtable for an object being translated. Returns a pointer into
|
|
|
|
// read-only memory.
|
2011-06-15 11:19:50 -07:00
|
|
|
fn create_vtbl(@local_ctxt cx, TypeRef llself_ty, ty::t self_ty,
|
|
|
|
&ast::_obj ob, &vec[ast::ty_param] ty_params) -> ValueRef {
|
2011-04-29 13:34:30 +02:00
|
|
|
auto dtor = C_null(T_ptr(T_i8()));
|
|
|
|
alt (ob.dtor) {
|
2011-05-31 00:39:19 -04:00
|
|
|
case (some(?d)) {
|
2011-04-29 13:34:30 +02:00
|
|
|
auto dtor_1 = trans_dtor(cx, llself_ty, self_ty, ty_params, d);
|
2011-05-12 17:24:54 +02:00
|
|
|
dtor = llvm::LLVMConstBitCast(dtor_1, val_ty(dtor));
|
2011-04-29 13:34:30 +02:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (none) { }
|
2011-04-29 13:34:30 +02:00
|
|
|
}
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ValueRef] methods = [dtor];
|
2011-05-12 17:24:54 +02:00
|
|
|
fn meth_lteq(&@ast::method a, &@ast::method b) -> bool {
|
2011-05-17 20:41:41 +02:00
|
|
|
ret str::lteq(a.node.ident, b.node.ident);
|
2010-12-30 17:01:20 -08:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
auto meths =
|
|
|
|
std::sort::merge_sort[@ast::method](bind meth_lteq(_, _), ob.methods);
|
2011-05-12 17:24:54 +02:00
|
|
|
for (@ast::method m in meths) {
|
2010-12-23 17:31:16 -08:00
|
|
|
auto llfnty = T_nil();
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(cx.ccx.tcx, node_ann_type(cx.ccx, m.node.ann))) {
|
2011-06-09 09:48:16 -07:00
|
|
|
case (ty::ty_fn(?proto, ?inputs, ?output, _, _)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
llfnty =
|
|
|
|
type_of_fn_full(cx.ccx, m.span, proto,
|
|
|
|
some[TypeRef](llself_ty), inputs, output,
|
|
|
|
vec::len[ast::ty_param](ty_params));
|
2010-12-23 17:31:16 -08:00
|
|
|
}
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
let @local_ctxt mcx =
|
|
|
|
@rec(path=cx.path + ["method", m.node.ident] with *cx);
|
2011-06-07 17:54:22 -07:00
|
|
|
let str s = mangle_internal_name_by_path(mcx.ccx, mcx.path);
|
2011-06-15 11:19:50 -07:00
|
|
|
let ValueRef llfn =
|
|
|
|
decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty);
|
2011-06-15 12:18:02 -07:00
|
|
|
|
|
|
|
// Every method on an object gets its def_id inserted into the
|
|
|
|
// crate-wide item_ids map, together with the ValueRef that points to
|
|
|
|
// where that method's definition will be in the executable.
|
2011-04-17 14:24:45 +02:00
|
|
|
cx.ccx.item_ids.insert(m.node.id, llfn);
|
|
|
|
cx.ccx.item_symbols.insert(m.node.id, s);
|
2011-06-14 15:20:04 +02:00
|
|
|
trans_fn(mcx, m.span, m.node.meth, llfn,
|
2011-06-15 11:19:50 -07:00
|
|
|
some[ty_self_pair](tup(llself_ty, self_ty)), ty_params,
|
|
|
|
m.node.ann);
|
2011-05-16 18:21:22 -07:00
|
|
|
methods += [llfn];
|
2010-12-16 18:34:04 -08:00
|
|
|
}
|
2010-12-20 11:41:22 -08:00
|
|
|
auto vtbl = C_struct(methods);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto vtbl_name = mangle_internal_name_by_path(cx.ccx, cx.path + ["vtbl"]);
|
|
|
|
auto gvar =
|
|
|
|
llvm::LLVMAddGlobal(cx.ccx.llmod, val_ty(vtbl), str::buf(vtbl_name));
|
2011-05-12 17:24:54 +02:00
|
|
|
llvm::LLVMSetInitializer(gvar, vtbl);
|
|
|
|
llvm::LLVMSetGlobalConstant(gvar, True);
|
2011-06-15 11:19:50 -07:00
|
|
|
llvm::LLVMSetLinkage(gvar,
|
|
|
|
lib::llvm::LLVMInternalLinkage as llvm::Linkage);
|
2010-12-20 11:41:22 -08:00
|
|
|
ret gvar;
|
2010-12-16 18:34:04 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_dtor(@local_ctxt cx, TypeRef llself_ty, ty::t self_ty,
|
|
|
|
&vec[ast::ty_param] ty_params, &@ast::method dtor) -> ValueRef {
|
2011-05-18 15:35:16 -07:00
|
|
|
auto llfnty = T_dtor(cx.ccx, dtor.span, llself_ty);
|
2011-06-07 17:54:22 -07:00
|
|
|
let str s = mangle_internal_name_by_path(cx.ccx, cx.path + ["drop"]);
|
2011-04-17 14:24:45 +02:00
|
|
|
let ValueRef llfn = decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty);
|
|
|
|
cx.ccx.item_ids.insert(dtor.node.id, llfn);
|
|
|
|
cx.ccx.item_symbols.insert(dtor.node.id, s);
|
2011-06-14 15:20:04 +02:00
|
|
|
trans_fn(cx, dtor.span, dtor.node.meth, llfn,
|
2011-06-15 11:19:50 -07:00
|
|
|
some[ty_self_pair](tup(llself_ty, self_ty)), ty_params,
|
|
|
|
dtor.node.ann);
|
2011-04-14 16:50:48 -07:00
|
|
|
ret llfn;
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-27 17:58:22 -07:00
|
|
|
// trans_obj: creates an LLVM function that is the object constructor for the
|
|
|
|
// object being translated.
|
2011-05-31 18:24:06 -07:00
|
|
|
fn trans_obj(@local_ctxt cx, &span sp, &ast::_obj ob, ast::def_id oid,
|
2011-05-12 17:24:54 +02:00
|
|
|
&vec[ast::ty_param] ty_params, &ast::ann ann) {
|
2011-05-27 17:58:22 -07:00
|
|
|
// To make a function, we have to create a function context and, inside
|
|
|
|
// that, a number of block contexts for which code is generated.
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
auto ccx = cx.ccx;
|
|
|
|
auto llctor_decl = ccx.item_ids.get(oid);
|
2011-05-27 17:58:22 -07:00
|
|
|
// Much like trans_fn, we must create an LLVM function, but since we're
|
|
|
|
// starting with an ast::_obj rather than an ast::_fn, we have some setup
|
|
|
|
// work to do.
|
|
|
|
|
2011-06-03 17:09:50 -07:00
|
|
|
// The fields of our object will become the arguments to the function
|
|
|
|
// we're creating.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ast::arg] fn_args = [];
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ast::obj_field f in ob.fields) {
|
2011-06-15 11:19:50 -07:00
|
|
|
fn_args +=
|
|
|
|
[rec(mode=ast::alias(false), ty=f.ty, ident=f.ident, id=f.id)];
|
2010-12-16 15:55:28 -08:00
|
|
|
}
|
2011-05-18 15:35:16 -07:00
|
|
|
auto fcx = new_fn_ctxt(cx, sp, llctor_decl);
|
2011-06-03 17:09:50 -07:00
|
|
|
// Both regular arguments and type parameters are handled here.
|
2010-12-16 15:55:28 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
create_llargs_for_fn_args(fcx, ast::proto_fn, none[ty_self_pair],
|
|
|
|
ret_ty_of_fn(ccx, ann), fn_args, ty_params);
|
2011-05-12 17:24:54 +02:00
|
|
|
let vec[ty::arg] arg_tys = arg_tys_of_fn(ccx, ann);
|
2011-05-11 11:56:49 -07:00
|
|
|
copy_args_to_allocas(fcx, fn_args, arg_tys);
|
2011-06-03 17:09:50 -07:00
|
|
|
// Create the first block context in the function and keep a handle on it
|
2011-05-27 17:58:22 -07:00
|
|
|
// to pass to finish_fn later.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-28 18:04:52 -07:00
|
|
|
auto bcx = new_top_block_ctxt(fcx);
|
|
|
|
auto lltop = bcx.llbb;
|
2011-06-03 17:09:50 -07:00
|
|
|
// Pick up the type of this object by looking at our own output type, that
|
|
|
|
// is, the output type of the object constructor we're building.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-29 13:34:30 +02:00
|
|
|
auto self_ty = ret_ty_of_fn(ccx, ann);
|
2011-05-18 15:35:16 -07:00
|
|
|
auto llself_ty = type_of(ccx, sp, self_ty);
|
2011-06-03 17:09:50 -07:00
|
|
|
// Set up the two-word pair that we're going to return from the object
|
|
|
|
// constructor we're building. The two elements of this pair will be a
|
|
|
|
// vtable pointer and a body pointer. (llretptr already points to the
|
|
|
|
// place where this two-word pair should go; it was pre-allocated by the
|
|
|
|
// caller of the function.)
|
2011-05-27 17:58:22 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto pair = bcx.fcx.llretptr;
|
2011-06-03 17:09:50 -07:00
|
|
|
// Grab onto the first and second elements of the pair.
|
|
|
|
// abi::obj_field_vtbl and abi::obj_field_box simply specify words 0 and 1
|
|
|
|
// of 'pair'.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto pair_vtbl =
|
|
|
|
bcx.build.GEP(pair, [C_int(0), C_int(abi::obj_field_vtbl)]);
|
|
|
|
auto pair_box =
|
|
|
|
bcx.build.GEP(pair, [C_int(0), C_int(abi::obj_field_box)]);
|
2011-06-03 17:09:50 -07:00
|
|
|
// Make a vtable for this object: a static array of pointers to functions.
|
|
|
|
// It will be located in the read-only memory of the executable we're
|
|
|
|
// creating and will contain ValueRefs for all of this object's methods.
|
|
|
|
// create_vtbl returns a pointer to the vtable, which we store.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-03 17:09:50 -07:00
|
|
|
auto vtbl = create_vtbl(cx, llself_ty, self_ty, ob, ty_params);
|
2010-12-17 00:31:41 -08:00
|
|
|
bcx.build.Store(vtbl, pair_vtbl);
|
2011-06-03 17:09:50 -07:00
|
|
|
// Next we have to take care of the other half of the pair we're
|
|
|
|
// returning: a boxed (reference-counted) tuple containing a tydesc,
|
|
|
|
// typarams, and fields.
|
2011-02-03 14:40:57 -08:00
|
|
|
|
2011-06-03 17:09:50 -07:00
|
|
|
// FIXME: What about with_obj? Do we have to think about it here?
|
|
|
|
// (Pertains to issue #417.)
|
|
|
|
|
|
|
|
let TypeRef llbox_ty = T_opaque_obj_ptr(ccx.tn);
|
|
|
|
// FIXME: we should probably also allocate a box for empty objs that have
|
|
|
|
// a dtor, since otherwise they are never dropped, and the dtor never
|
|
|
|
// runs.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-17 20:41:41 +02:00
|
|
|
if (vec::len[ast::ty_param](ty_params) == 0u &&
|
2011-06-15 11:19:50 -07:00
|
|
|
vec::len[ty::arg](arg_tys) == 0u) {
|
2011-06-03 17:09:50 -07:00
|
|
|
// If the object we're translating has no fields or type parameters,
|
|
|
|
// there's not much to do.
|
|
|
|
|
2011-02-03 14:40:57 -08:00
|
|
|
// Store null into pair, if no args or typarams.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-12-22 13:56:51 -08:00
|
|
|
bcx.build.Store(C_null(llbox_ty), pair_box);
|
|
|
|
} else {
|
2011-06-03 17:09:50 -07:00
|
|
|
// Otherwise, we have to synthesize a big structural type for the
|
|
|
|
// object body.
|
2011-05-27 17:58:22 -07:00
|
|
|
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ty::t] obj_fields = [];
|
2011-06-15 11:19:50 -07:00
|
|
|
for (ty::arg a in arg_tys) { vec::push[ty::t](obj_fields, a.ty); }
|
2011-06-03 17:09:50 -07:00
|
|
|
// Tuple type for fields: [field, ...]
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
let ty::t fields_ty = ty::mk_imm_tup(ccx.tcx, obj_fields);
|
2011-06-03 17:09:50 -07:00
|
|
|
// Tuple type for typarams: [typaram, ...]
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
auto tydesc_ty = ty::mk_type(ccx.tcx);
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ty::t] tps = [];
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ast::ty_param tp in ty_params) {
|
2011-05-17 20:41:41 +02:00
|
|
|
vec::push[ty::t](tps, tydesc_ty);
|
2011-02-03 14:40:57 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
let ty::t typarams_ty = ty::mk_imm_tup(ccx.tcx, tps);
|
2011-06-03 17:09:50 -07:00
|
|
|
// Tuple type for body: [tydesc_ty, [typaram, ...], [field, ...]]
|
2011-05-27 17:58:22 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
let ty::t body_ty =
|
|
|
|
ty::mk_imm_tup(ccx.tcx, [tydesc_ty, typarams_ty, fields_ty]);
|
2011-06-04 19:38:11 -07:00
|
|
|
// Hand this type we've synthesized off to trans_malloc_boxed, which
|
|
|
|
// allocates a box, including space for a refcount.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-07 14:05:16 -08:00
|
|
|
auto box = trans_malloc_boxed(bcx, body_ty);
|
2011-02-01 14:57:03 -08:00
|
|
|
bcx = box.bcx;
|
2011-06-04 19:38:11 -07:00
|
|
|
// mk_imm_box throws a refcount into the type we're synthesizing, so
|
|
|
|
// that it looks like: [rc, [tydesc_ty, [typaram, ...], [field, ...]]]
|
2011-06-03 17:09:50 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
let ty::t boxed_body_ty = ty::mk_imm_box(ccx.tcx, body_ty);
|
2011-06-04 19:38:11 -07:00
|
|
|
// Grab onto the refcount and body parts of the box we allocated.
|
2011-05-27 17:58:22 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto rc =
|
|
|
|
GEP_tup_like(bcx, boxed_body_ty, box.val,
|
|
|
|
[0, abi::box_rc_field_refcnt]);
|
|
|
|
bcx = rc.bcx;
|
|
|
|
auto body =
|
|
|
|
GEP_tup_like(bcx, boxed_body_ty, box.val,
|
|
|
|
[0, abi::box_rc_field_body]);
|
2011-02-01 14:57:03 -08:00
|
|
|
bcx = body.bcx;
|
|
|
|
bcx.build.Store(C_int(1), rc.val);
|
2011-05-27 17:58:22 -07:00
|
|
|
// Put together a tydesc for the body, so that the object can later be
|
|
|
|
// freed by calling through its tydesc.
|
2011-06-04 19:38:11 -07:00
|
|
|
|
|
|
|
// Every object (not just those with type parameters) needs to have a
|
|
|
|
// tydesc to describe its body, since all objects have unknown type to
|
|
|
|
// the user of the object. So the tydesc is needed to keep track of
|
|
|
|
// the types of the object's fields, so that the fields can be freed
|
|
|
|
// later.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-12-22 16:09:59 -08:00
|
|
|
auto body_tydesc =
|
2011-02-01 14:57:03 -08:00
|
|
|
GEP_tup_like(bcx, body_ty, body.val,
|
2011-05-16 18:21:22 -07:00
|
|
|
[0, abi::obj_body_elt_tydesc]);
|
2011-02-01 14:57:03 -08:00
|
|
|
bcx = body_tydesc.bcx;
|
2011-05-12 15:42:12 -07:00
|
|
|
auto ti = none[@tydesc_info];
|
|
|
|
auto body_td = get_tydesc(bcx, body_ty, true, ti);
|
|
|
|
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
|
2011-05-18 17:28:08 -07:00
|
|
|
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
|
2011-02-02 15:28:11 -08:00
|
|
|
bcx = body_td.bcx;
|
|
|
|
bcx.build.Store(body_td.val, body_tydesc.val);
|
2011-06-04 19:38:11 -07:00
|
|
|
// Copy the object's type parameters and fields into the space we
|
|
|
|
// allocated for the object body. (This is something like saving the
|
|
|
|
// lexical environment of a function in its closure: the "captured
|
|
|
|
// typarams" are any type parameters that are passed to the object
|
|
|
|
// constructor and are then available to the object's methods.
|
|
|
|
// Likewise for the object's fields.)
|
|
|
|
|
2011-02-03 14:40:57 -08:00
|
|
|
// Copy typarams into captured typarams.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-02-03 14:40:57 -08:00
|
|
|
auto body_typarams =
|
|
|
|
GEP_tup_like(bcx, body_ty, body.val,
|
2011-05-16 18:21:22 -07:00
|
|
|
[0, abi::obj_body_elt_typarams]);
|
2011-02-03 14:40:57 -08:00
|
|
|
bcx = body_typarams.bcx;
|
|
|
|
let int i = 0;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ast::ty_param tp in ty_params) {
|
2011-04-15 17:45:37 -07:00
|
|
|
auto typaram = bcx.fcx.lltydescs.(i);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto capture =
|
|
|
|
GEP_tup_like(bcx, typarams_ty, body_typarams.val, [0, i]);
|
2011-02-03 14:40:57 -08:00
|
|
|
bcx = capture.bcx;
|
2011-05-27 17:58:22 -07:00
|
|
|
bcx = copy_val(bcx, INIT, capture.val, typaram, tydesc_ty).bcx;
|
2011-02-03 14:40:57 -08:00
|
|
|
i += 1;
|
|
|
|
}
|
2010-12-22 16:09:59 -08:00
|
|
|
// Copy args into body fields.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-12-22 16:09:59 -08:00
|
|
|
auto body_fields =
|
2011-02-01 14:57:03 -08:00
|
|
|
GEP_tup_like(bcx, body_ty, body.val,
|
2011-05-16 18:21:22 -07:00
|
|
|
[0, abi::obj_body_elt_fields]);
|
2011-02-01 14:57:03 -08:00
|
|
|
bcx = body_fields.bcx;
|
2011-02-03 14:40:57 -08:00
|
|
|
i = 0;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ast::obj_field f in ob.fields) {
|
2011-01-31 15:03:05 -08:00
|
|
|
auto arg = bcx.fcx.llargs.get(f.id);
|
2011-04-12 12:06:20 -07:00
|
|
|
arg = load_if_immediate(bcx, arg, arg_tys.(i).ty);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto field =
|
|
|
|
GEP_tup_like(bcx, fields_ty, body_fields.val, [0, i]);
|
2011-02-01 14:57:03 -08:00
|
|
|
bcx = field.bcx;
|
2011-05-27 17:58:22 -07:00
|
|
|
bcx = copy_val(bcx, INIT, field.val, arg, arg_tys.(i).ty).bcx;
|
2010-12-22 16:09:59 -08:00
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
// Store box ptr in outer pair.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-02-01 14:57:03 -08:00
|
|
|
auto p = bcx.build.PointerCast(box.val, llbox_ty);
|
2011-01-31 15:03:05 -08:00
|
|
|
bcx.build.Store(p, pair_box);
|
2010-12-22 13:56:51 -08:00
|
|
|
}
|
2011-02-08 11:47:53 -08:00
|
|
|
bcx.build.RetVoid();
|
2011-06-03 17:09:50 -07:00
|
|
|
// Insert the mandatory first few basic blocks before lltop.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-11 11:56:49 -07:00
|
|
|
finish_fn(fcx, lltop);
|
2010-12-16 15:55:28 -08:00
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_tag_variant(@local_ctxt cx, ast::def_id tag_id,
|
|
|
|
&ast::variant variant, int index,
|
|
|
|
&vec[ast::ty_param] ty_params) {
|
2011-05-17 20:41:41 +02:00
|
|
|
if (vec::len[ast::variant_arg](variant.node.args) == 0u) {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret; // nullary constructors are just constants
|
2010-12-01 19:03:47 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
}
|
2010-12-06 16:50:24 -08:00
|
|
|
// Translate variant arguments to function arguments.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ast::arg] fn_args = [];
|
2010-12-06 16:50:24 -08:00
|
|
|
auto i = 0u;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ast::variant_arg varg in variant.node.args) {
|
2011-06-15 11:19:50 -07:00
|
|
|
fn_args +=
|
|
|
|
[rec(mode=ast::alias(false),
|
|
|
|
ty=varg.ty,
|
|
|
|
ident="arg" + uint::to_str(i, 10u),
|
|
|
|
id=varg.id)];
|
2010-12-06 16:50:24 -08:00
|
|
|
}
|
2011-05-02 17:47:24 -07:00
|
|
|
assert (cx.ccx.item_ids.contains_key(variant.node.id));
|
2011-04-17 14:24:45 +02:00
|
|
|
let ValueRef llfndecl = cx.ccx.item_ids.get(variant.node.id);
|
2011-05-18 15:35:16 -07:00
|
|
|
auto fcx = new_fn_ctxt(cx, variant.span, llfndecl);
|
2011-06-15 11:19:50 -07:00
|
|
|
create_llargs_for_fn_args(fcx, ast::proto_fn, none[ty_self_pair],
|
|
|
|
ret_ty_of_fn(cx.ccx, variant.node.ann), fn_args,
|
|
|
|
ty_params);
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ty::t] ty_param_substs = [];
|
2011-04-12 15:09:50 -07:00
|
|
|
i = 0u;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ast::ty_param tp in ty_params) {
|
2011-05-16 18:21:22 -07:00
|
|
|
ty_param_substs += [ty::mk_param(cx.ccx.tcx, i)];
|
2011-04-12 15:09:50 -07:00
|
|
|
i += 1u;
|
2011-03-09 17:48:07 -08:00
|
|
|
}
|
2011-04-22 17:00:46 -07:00
|
|
|
auto arg_tys = arg_tys_of_fn(cx.ccx, variant.node.ann);
|
2011-05-11 11:56:49 -07:00
|
|
|
copy_args_to_allocas(fcx, fn_args, arg_tys);
|
2011-03-28 18:04:52 -07:00
|
|
|
auto bcx = new_top_block_ctxt(fcx);
|
|
|
|
auto lltop = bcx.llbb;
|
2011-03-03 15:52:54 -08:00
|
|
|
// Cast the tag to a type we can GEP into.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto lltagptr =
|
|
|
|
bcx.build.PointerCast(fcx.llretptr, T_opaque_tag_ptr(fcx.lcx.ccx.tn));
|
|
|
|
auto lldiscrimptr = bcx.build.GEP(lltagptr, [C_int(0), C_int(0)]);
|
2010-12-06 16:50:24 -08:00
|
|
|
bcx.build.Store(C_int(index), lldiscrimptr);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llblobptr = bcx.build.GEP(lltagptr, [C_int(0), C_int(1)]);
|
2010-12-06 16:50:24 -08:00
|
|
|
i = 0u;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ast::variant_arg va in variant.node.args) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto rslt =
|
|
|
|
GEP_tag(bcx, llblobptr, tag_id, variant.node.id, ty_param_substs,
|
|
|
|
i as int);
|
2011-03-03 15:52:54 -08:00
|
|
|
bcx = rslt.bcx;
|
|
|
|
auto lldestptr = rslt.val;
|
2011-03-04 15:08:33 -08:00
|
|
|
// If this argument to this function is a tag, it'll have come in to
|
|
|
|
// this function as an opaque blob due to the way that type_of()
|
|
|
|
// works. So we have to cast to the destination's view of the type.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llargptr =
|
|
|
|
bcx.build.PointerCast(fcx.llargs.get(va.id), val_ty(lldestptr));
|
2011-03-04 18:05:48 -08:00
|
|
|
auto arg_ty = arg_tys.(i).ty;
|
|
|
|
auto llargval;
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_is_structural(cx.ccx.tcx, arg_ty) ||
|
|
|
|
ty::type_has_dynamic_size(cx.ccx.tcx, arg_ty)) {
|
2011-03-04 18:05:48 -08:00
|
|
|
llargval = llargptr;
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { llargval = bcx.build.Load(llargptr); }
|
2011-05-27 17:58:22 -07:00
|
|
|
rslt = copy_val(bcx, INIT, lldestptr, llargval, arg_ty);
|
2011-03-04 18:05:48 -08:00
|
|
|
bcx = rslt.bcx;
|
2010-12-06 16:50:24 -08:00
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
|
2011-02-08 11:47:53 -08:00
|
|
|
bcx.build.RetVoid();
|
2011-05-11 11:56:49 -07:00
|
|
|
finish_fn(fcx, lltop);
|
2010-12-01 19:03:47 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-01-21 12:09:25 -08:00
|
|
|
// FIXME: this should do some structural hash-consing to avoid
|
|
|
|
// duplicate constants. I think. Maybe LLVM has a magical mode
|
|
|
|
// that does so later on?
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_const_expr(&@crate_ctxt cx, @ast::expr e) -> ValueRef {
|
2011-01-21 12:09:25 -08:00
|
|
|
alt (e.node) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ast::expr_lit(?lit, ?ann)) { ret trans_lit(cx, *lit, ann); }
|
2011-05-12 09:17:59 +02:00
|
|
|
case (_) {
|
|
|
|
cx.sess.span_unimpl(e.span, "consts that's not a plain literal");
|
|
|
|
}
|
2011-01-21 12:09:25 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_const(&@crate_ctxt cx, @ast::expr e, &ast::def_id cid,
|
|
|
|
&ast::ann ann) {
|
2011-01-21 12:09:25 -08:00
|
|
|
auto t = node_ann_type(cx, ann);
|
|
|
|
auto v = trans_const_expr(cx, e);
|
2011-03-18 16:22:59 -07:00
|
|
|
// The scalars come back as 1st class LLVM vals
|
|
|
|
// which we have to stick into global constants.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-18 16:22:59 -07:00
|
|
|
auto g = cx.consts.get(cid);
|
2011-05-12 17:24:54 +02:00
|
|
|
llvm::LLVMSetInitializer(g, v);
|
|
|
|
llvm::LLVMSetGlobalConstant(g, True);
|
2011-01-21 12:09:25 -08:00
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_item(@local_ctxt cx, &ast::item item) {
|
2010-10-05 18:21:44 -07:00
|
|
|
alt (item.node) {
|
2011-06-14 17:06:06 -07:00
|
|
|
case (ast::item_fn(?name, ?f, ?tps, _, ?fid, ?ann)) {
|
2011-03-26 17:36:47 -07:00
|
|
|
auto sub_cx = extend_path(cx, name);
|
2011-06-14 15:20:04 +02:00
|
|
|
auto llfndecl = cx.ccx.item_ids.get(fid);
|
2011-06-15 11:19:50 -07:00
|
|
|
trans_fn(sub_cx, item.span, f, llfndecl, none[ty_self_pair], tps,
|
|
|
|
ann);
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
2011-06-14 17:06:06 -07:00
|
|
|
case (ast::item_obj(?name, ?ob, ?tps, _, ?oid, ?ann)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto sub_cx =
|
|
|
|
@rec(obj_typarams=tps, obj_fields=ob.fields
|
|
|
|
with *extend_path(cx, name));
|
2011-05-18 15:35:16 -07:00
|
|
|
trans_obj(sub_cx, item.span, ob, oid.ctor, tps, ann);
|
2010-12-16 15:55:28 -08:00
|
|
|
}
|
2011-06-14 14:39:28 -07:00
|
|
|
case (ast::item_mod(?name, ?m, _, _)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto sub_cx =
|
|
|
|
@rec(path=cx.path + [name],
|
|
|
|
module_path=cx.module_path + [name] with *cx);
|
2010-10-06 15:41:14 -07:00
|
|
|
trans_mod(sub_cx, m);
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
2011-06-14 17:06:06 -07:00
|
|
|
case (ast::item_tag(?name, ?variants, ?tps, _, ?tag_id, _)) {
|
2011-03-26 17:36:47 -07:00
|
|
|
auto sub_cx = extend_path(cx, name);
|
2010-12-06 16:50:24 -08:00
|
|
|
auto i = 0;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ast::variant variant in variants) {
|
2010-12-20 14:33:11 -08:00
|
|
|
trans_tag_variant(sub_cx, tag_id, variant, i, tps);
|
2010-12-06 16:50:24 -08:00
|
|
|
i += 1;
|
2010-12-01 19:03:47 -08:00
|
|
|
}
|
|
|
|
}
|
2011-06-14 17:06:06 -07:00
|
|
|
case (ast::item_const(?name, _, ?expr, _, ?cid, ?ann)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
trans_const(cx.ccx, expr, cid, ann);
|
2011-01-21 12:09:25 -08:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) {/* fall through */ }
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 12:18:02 -07:00
|
|
|
// Translate a module. Doing this amounts to translating the items in the
|
|
|
|
// module; there ends up being no artifact (aside from linkage names) of
|
|
|
|
// separate modules in the compiled program. That's because modules exist
|
|
|
|
// only as a convenience for humans working with the code, to organize names
|
|
|
|
// and control visibility.
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_mod(@local_ctxt cx, &ast::_mod m) {
|
2011-06-15 11:19:50 -07:00
|
|
|
for (@ast::item item in m.items) { trans_item(cx, *item); }
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
|
|
|
|
2011-01-07 15:12:23 -08:00
|
|
|
fn get_pair_fn_ty(TypeRef llpairty) -> TypeRef {
|
|
|
|
// Bit of a kludge: pick the fn typeref out of the pair.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-10 13:49:22 -07:00
|
|
|
ret struct_elt(llpairty, 0u);
|
2011-01-07 15:12:23 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn decl_fn_and_pair(&@crate_ctxt ccx, &span sp, vec[str] path, str flav,
|
|
|
|
vec[ast::ty_param] ty_params, &ast::ann ann,
|
2011-05-12 17:24:54 +02:00
|
|
|
ast::def_id id) {
|
2011-03-08 16:51:23 -08:00
|
|
|
auto llfty;
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(ccx.tcx, node_ann_type(ccx, ann))) {
|
2011-06-09 09:48:16 -07:00
|
|
|
case (ty::ty_fn(?proto, ?inputs, ?output, _, _)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
llfty =
|
|
|
|
type_of_fn(ccx, sp, proto, inputs, output,
|
|
|
|
vec::len[ast::ty_param](ty_params));
|
2011-03-08 16:51:23 -08:00
|
|
|
}
|
|
|
|
case (_) {
|
2011-04-17 14:24:45 +02:00
|
|
|
ccx.sess.bug("decl_fn_and_pair(): fn item doesn't have fn type!");
|
2011-03-08 16:51:23 -08:00
|
|
|
}
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
let bool is_main =
|
|
|
|
str::eq(vec::top(path), "main") && !ccx.sess.get_opts().shared;
|
2011-01-05 15:31:35 -08:00
|
|
|
// Declare the function itself.
|
2011-06-07 17:54:22 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
let str s =
|
|
|
|
if (is_main) {
|
|
|
|
"_rust_main"
|
|
|
|
} else { mangle_internal_name_by_path(ccx, path) };
|
2011-04-17 14:24:45 +02:00
|
|
|
let ValueRef llfn = decl_internal_fastcall_fn(ccx.llmod, s, llfty);
|
2011-01-05 15:31:35 -08:00
|
|
|
// Declare the global constant pair that points to it.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-07 17:54:22 -07:00
|
|
|
let str ps = mangle_exported_name(ccx, path, node_ann_type(ccx, ann));
|
2011-06-14 15:20:04 +02:00
|
|
|
register_fn_pair(ccx, ps, llfty, llfn, id);
|
2011-06-07 17:54:22 -07:00
|
|
|
if (is_main) {
|
2011-06-06 15:48:36 -07:00
|
|
|
if (ccx.main_fn != none[ValueRef]) {
|
|
|
|
ccx.sess.span_err(sp, "multiple 'main' functions");
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
llvm::LLVMSetLinkage(llfn,
|
|
|
|
lib::llvm::LLVMExternalLinkage as llvm::Linkage);
|
2011-06-06 15:48:36 -07:00
|
|
|
ccx.main_fn = some(llfn);
|
|
|
|
}
|
2011-02-28 17:33:46 -05:00
|
|
|
}
|
|
|
|
|
2011-06-14 15:20:04 +02:00
|
|
|
fn create_fn_pair(&@crate_ctxt cx, str ps, TypeRef llfnty, ValueRef llfn,
|
|
|
|
bool external) -> ValueRef {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto gvar =
|
|
|
|
llvm::LLVMAddGlobal(cx.llmod, T_fn_pair(cx.tn, llfnty), str::buf(ps));
|
2011-06-14 15:20:04 +02:00
|
|
|
auto pair = C_struct([llfn, C_null(T_opaque_closure_ptr(cx.tn))]);
|
2011-05-12 17:24:54 +02:00
|
|
|
llvm::LLVMSetInitializer(gvar, pair);
|
|
|
|
llvm::LLVMSetGlobalConstant(gvar, True);
|
2011-06-14 15:20:04 +02:00
|
|
|
if (!external) {
|
2011-06-15 11:19:50 -07:00
|
|
|
llvm::LLVMSetLinkage(gvar,
|
|
|
|
lib::llvm::LLVMInternalLinkage as llvm::Linkage);
|
2011-06-01 15:45:31 -04:00
|
|
|
}
|
2011-06-14 15:20:04 +02:00
|
|
|
ret gvar;
|
|
|
|
}
|
2011-01-05 15:31:35 -08:00
|
|
|
|
2011-06-14 15:20:04 +02:00
|
|
|
fn register_fn_pair(&@crate_ctxt cx, str ps, TypeRef llfnty, ValueRef llfn,
|
|
|
|
ast::def_id id) {
|
|
|
|
// FIXME: We should also hide the unexported pairs in crates.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
|
|
|
auto gvar =
|
|
|
|
create_fn_pair(cx, ps, llfnty, llfn, cx.sess.get_opts().shared);
|
2011-01-05 15:31:35 -08:00
|
|
|
cx.item_ids.insert(id, llfn);
|
2011-03-23 15:43:18 -07:00
|
|
|
cx.item_symbols.insert(id, ps);
|
2011-01-05 15:31:35 -08:00
|
|
|
cx.fn_pairs.insert(id, gvar);
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-03-08 16:51:23 -08:00
|
|
|
// Returns the number of type parameters that the given native function has.
|
2011-05-12 17:24:54 +02:00
|
|
|
fn native_fn_ty_param_count(&@crate_ctxt cx, &ast::def_id id) -> uint {
|
2011-03-08 16:51:23 -08:00
|
|
|
auto count;
|
|
|
|
auto native_item = cx.native_items.get(id);
|
|
|
|
alt (native_item.node) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ast::native_item_ty(_, _)) {
|
2011-03-08 16:51:23 -08:00
|
|
|
cx.sess.bug("decl_native_fn_and_pair(): native fn isn't " +
|
2011-06-15 11:19:50 -07:00
|
|
|
"actually a fn");
|
2011-03-08 16:51:23 -08:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::native_item_fn(_, _, _, ?tps, _, _)) {
|
2011-05-17 20:41:41 +02:00
|
|
|
count = vec::len[ast::ty_param](tps);
|
2011-03-08 16:51:23 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ret count;
|
|
|
|
}
|
|
|
|
|
2011-05-31 18:24:06 -07:00
|
|
|
fn native_fn_wrapper_type(&@crate_ctxt cx, &span sp, uint ty_param_count,
|
2011-05-18 15:35:16 -07:00
|
|
|
ty::t x) -> TypeRef {
|
2011-05-12 17:24:54 +02:00
|
|
|
alt (ty::struct(cx.tcx, x)) {
|
|
|
|
case (ty::ty_native_fn(?abi, ?args, ?out)) {
|
2011-05-18 15:35:16 -07:00
|
|
|
ret type_of_fn(cx, sp, ast::proto_fn, args, out, ty_param_count);
|
2011-02-28 17:33:46 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, vec[str] path,
|
|
|
|
str name, &ast::ann ann, ast::def_id id) {
|
2011-04-20 17:23:45 +02:00
|
|
|
auto num_ty_param = native_fn_ty_param_count(ccx, id);
|
2011-02-28 17:33:46 -05:00
|
|
|
// Declare the wrapper.
|
2011-05-20 18:36:35 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto t = node_ann_type(ccx, ann);
|
2011-05-18 15:35:16 -07:00
|
|
|
auto wrapper_type = native_fn_wrapper_type(ccx, sp, num_ty_param, t);
|
2011-06-07 17:54:22 -07:00
|
|
|
let str s = mangle_internal_name_by_path(ccx, path);
|
2011-06-15 11:19:50 -07:00
|
|
|
let ValueRef wrapper_fn =
|
|
|
|
decl_internal_fastcall_fn(ccx.llmod, s, wrapper_type);
|
2011-02-28 17:33:46 -05:00
|
|
|
// Declare the global constant pair that points to it.
|
2011-02-16 15:34:59 -05:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
let str ps = mangle_exported_name(ccx, path, node_ann_type(ccx, ann));
|
2011-06-14 15:20:04 +02:00
|
|
|
register_fn_pair(ccx, ps, wrapper_type, wrapper_fn, id);
|
2011-03-07 15:37:40 -05:00
|
|
|
// Build the wrapper.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-18 15:35:16 -07:00
|
|
|
auto fcx = new_fn_ctxt(new_local_ctxt(ccx), sp, wrapper_fn);
|
2011-03-07 15:37:40 -05:00
|
|
|
auto bcx = new_top_block_ctxt(fcx);
|
2011-03-28 18:04:52 -07:00
|
|
|
auto lltop = bcx.llbb;
|
2011-03-18 15:01:45 -07:00
|
|
|
// Declare the function itself.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
auto item = ccx.native_items.get(id);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto fn_type = node_ann_type(ccx, ann); // NB: has no type params
|
2011-03-18 15:01:45 -07:00
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
auto abi = ty::ty_fn_abi(ccx.tcx, fn_type);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llfnty =
|
|
|
|
type_of_native_fn(ccx, sp, abi, ty::ty_fn_args(ccx.tcx, fn_type),
|
|
|
|
ty::ty_fn_ret(ccx.tcx, fn_type), num_ty_param);
|
2011-04-26 18:48:34 -07:00
|
|
|
// FIXME: If the returned type is not nil, then we assume it's 32 bits
|
|
|
|
// wide. This is obviously wildly unsafe. We should have a better FFI
|
|
|
|
// that allows types of different sizes to be returned.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
auto rty_is_nil =
|
|
|
|
ty::type_is_nil(ccx.tcx, ty::ty_fn_ret(ccx.tcx, fn_type));
|
2011-03-21 17:47:38 -04:00
|
|
|
auto pass_task;
|
2011-05-05 17:47:30 -07:00
|
|
|
auto cast_to_i32;
|
2011-03-07 15:37:40 -05:00
|
|
|
alt (abi) {
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ast::native_abi_rust) { pass_task = true; cast_to_i32 = true; }
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::native_abi_rust_intrinsic) {
|
2011-05-03 18:03:59 -07:00
|
|
|
pass_task = true;
|
2011-05-05 17:47:30 -07:00
|
|
|
cast_to_i32 = false;
|
2011-05-03 18:03:59 -07:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::native_abi_cdecl) {
|
2011-03-21 17:47:38 -04:00
|
|
|
pass_task = false;
|
2011-05-05 17:47:30 -07:00
|
|
|
cast_to_i32 = true;
|
2011-03-07 15:37:40 -05:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::native_abi_llvm) {
|
2011-03-28 08:24:11 -07:00
|
|
|
pass_task = false;
|
2011-05-05 17:47:30 -07:00
|
|
|
cast_to_i32 = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
auto lltaskptr;
|
|
|
|
if (cast_to_i32) {
|
|
|
|
lltaskptr = vp2i(bcx, fcx.lltaskptr);
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { lltaskptr = fcx.lltaskptr; }
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ValueRef] call_args = [];
|
|
|
|
if (pass_task) { call_args += [lltaskptr]; }
|
2011-05-05 17:47:30 -07:00
|
|
|
auto arg_n = 3u;
|
2011-05-17 20:41:41 +02:00
|
|
|
for each (uint i in uint::range(0u, num_ty_param)) {
|
2011-05-12 17:24:54 +02:00
|
|
|
auto llarg = llvm::LLVMGetParam(fcx.llfn, arg_n);
|
2011-05-16 18:21:22 -07:00
|
|
|
fcx.lltydescs += [llarg];
|
2011-05-05 17:47:30 -07:00
|
|
|
assert (llarg as int != 0);
|
|
|
|
if (cast_to_i32) {
|
2011-05-16 18:21:22 -07:00
|
|
|
call_args += [vp2i(bcx, llarg)];
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { call_args += [llarg]; }
|
2011-05-05 17:47:30 -07:00
|
|
|
arg_n += 1u;
|
2011-03-07 15:37:40 -05:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
fn convert_arg_to_i32(&@block_ctxt cx, ValueRef v, ty::t t, ty::mode mode)
|
|
|
|
-> ValueRef {
|
2011-05-12 17:24:54 +02:00
|
|
|
if (mode == ty::mo_val) {
|
|
|
|
if (ty::type_is_integral(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-04-29 11:54:41 -07:00
|
|
|
auto lldsttype = T_int();
|
2011-05-18 15:35:16 -07:00
|
|
|
auto llsrctype = type_of(cx.fcx.lcx.ccx, cx.sp, t);
|
2011-05-12 17:24:54 +02:00
|
|
|
if (llvm::LLVMGetIntTypeWidth(lldsttype) >
|
2011-06-15 11:19:50 -07:00
|
|
|
llvm::LLVMGetIntTypeWidth(llsrctype)) {
|
2011-05-05 17:47:30 -07:00
|
|
|
ret cx.build.ZExtOrBitCast(v, T_int());
|
2011-04-29 11:54:41 -07:00
|
|
|
}
|
2011-05-05 17:47:30 -07:00
|
|
|
ret cx.build.TruncOrBitCast(v, T_int());
|
2011-04-29 11:54:41 -07:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
if (ty::type_is_fp(cx.fcx.lcx.ccx.tcx, t)) {
|
2011-05-05 17:47:30 -07:00
|
|
|
ret cx.build.FPToSI(v, T_int());
|
2011-04-05 21:21:32 +00:00
|
|
|
}
|
|
|
|
}
|
2011-05-05 17:47:30 -07:00
|
|
|
ret vp2i(cx, v);
|
2011-04-05 21:21:32 +00:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_simple_native_abi(&@block_ctxt bcx, str name,
|
2011-05-03 18:03:59 -07:00
|
|
|
&mutable vec[ValueRef] call_args,
|
2011-06-15 11:19:50 -07:00
|
|
|
ty::t fn_type, uint first_arg_n) ->
|
|
|
|
tup(ValueRef, ValueRef) {
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[TypeRef] call_arg_tys = [];
|
2011-06-15 11:19:50 -07:00
|
|
|
for (ValueRef arg in call_args) { call_arg_tys += [val_ty(arg)]; }
|
2011-05-03 18:03:59 -07:00
|
|
|
auto llnativefnty =
|
|
|
|
T_fn(call_arg_tys,
|
2011-05-18 15:35:16 -07:00
|
|
|
type_of(bcx.fcx.lcx.ccx, bcx.sp,
|
2011-05-12 17:24:54 +02:00
|
|
|
ty::ty_fn_ret(bcx.fcx.lcx.ccx.tcx, fn_type)));
|
2011-06-15 11:19:50 -07:00
|
|
|
auto llnativefn =
|
|
|
|
get_extern_fn(bcx.fcx.lcx.ccx.externs, bcx.fcx.lcx.ccx.llmod,
|
|
|
|
name, lib::llvm::LLVMCCallConv, llnativefnty);
|
2011-05-03 18:03:59 -07:00
|
|
|
auto r = bcx.build.Call(llnativefn, call_args);
|
|
|
|
auto rptr = bcx.fcx.llretptr;
|
|
|
|
ret tup(r, rptr);
|
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
auto args = ty::ty_fn_args(ccx.tcx, fn_type);
|
2011-05-05 17:47:30 -07:00
|
|
|
// Build up the list of arguments.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[tup(ValueRef, ty::t)] drop_args = [];
|
2011-05-05 17:47:30 -07:00
|
|
|
auto i = arg_n;
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ty::arg arg in args) {
|
|
|
|
auto llarg = llvm::LLVMGetParam(fcx.llfn, i);
|
2011-05-05 17:47:30 -07:00
|
|
|
assert (llarg as int != 0);
|
|
|
|
if (cast_to_i32) {
|
|
|
|
auto llarg_i32 = convert_arg_to_i32(bcx, llarg, arg.ty, arg.mode);
|
2011-05-16 18:21:22 -07:00
|
|
|
call_args += [llarg_i32];
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { call_args += [llarg]; }
|
|
|
|
if (arg.mode == ty::mo_val) { drop_args += [tup(llarg, arg.ty)]; }
|
2011-05-05 17:47:30 -07:00
|
|
|
i += 1u;
|
|
|
|
}
|
2011-05-03 18:03:59 -07:00
|
|
|
auto r;
|
|
|
|
auto rptr;
|
|
|
|
alt (abi) {
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::native_abi_llvm) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto result =
|
|
|
|
trans_simple_native_abi(bcx, name, call_args, fn_type, arg_n);
|
|
|
|
r = result._0;
|
|
|
|
rptr = result._1;
|
2011-05-03 18:03:59 -07:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::native_abi_rust_intrinsic) {
|
2011-05-05 17:47:30 -07:00
|
|
|
auto external_name = "rust_intrinsic_" + name;
|
2011-06-15 11:19:50 -07:00
|
|
|
auto result =
|
|
|
|
trans_simple_native_abi(bcx, external_name, call_args,
|
|
|
|
fn_type, arg_n);
|
|
|
|
r = result._0;
|
|
|
|
rptr = result._1;
|
2011-03-28 08:24:11 -07:00
|
|
|
}
|
2011-05-03 18:03:59 -07:00
|
|
|
case (_) {
|
2011-06-15 11:19:50 -07:00
|
|
|
r =
|
|
|
|
trans_native_call(bcx.build, ccx.glues, lltaskptr,
|
2011-05-03 18:03:59 -07:00
|
|
|
ccx.externs, ccx.tn, ccx.llmod, name,
|
|
|
|
pass_task, call_args);
|
|
|
|
rptr = bcx.build.BitCast(fcx.llretptr, T_ptr(T_i32()));
|
2011-04-28 14:30:31 -07:00
|
|
|
}
|
2011-03-07 15:37:40 -05:00
|
|
|
}
|
2011-04-26 18:48:34 -07:00
|
|
|
// We don't store the return value if it's nil, to avoid stomping on a nil
|
|
|
|
// pointer. This is the only concession made to non-i32 return values. See
|
|
|
|
// the FIXME above.
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
if (!rty_is_nil) { bcx.build.Store(r, rptr); }
|
2011-05-12 17:24:54 +02:00
|
|
|
for (tup(ValueRef, ty::t) d in drop_args) {
|
2011-05-05 17:47:30 -07:00
|
|
|
bcx = drop_ty(bcx, d._0, d._1).bcx;
|
|
|
|
}
|
2011-03-07 15:37:40 -05:00
|
|
|
bcx.build.RetVoid();
|
2011-05-11 11:56:49 -07:00
|
|
|
finish_fn(fcx, lltop);
|
2011-02-16 15:34:59 -05:00
|
|
|
}
|
|
|
|
|
2011-06-10 17:24:20 +02:00
|
|
|
fn item_path(&@ast::item item) -> vec[str] {
|
2011-04-20 17:23:45 +02:00
|
|
|
alt (item.node) {
|
2011-06-14 17:06:06 -07:00
|
|
|
case (ast::item_fn(?name, _, _, _, _, _)) { ret [name]; }
|
|
|
|
case (ast::item_obj(?name, _, _, _, _, _)) { ret [name]; }
|
2011-06-14 14:39:28 -07:00
|
|
|
case (ast::item_mod(?name, _, _, _)) { ret [name]; }
|
2011-06-10 17:24:20 +02:00
|
|
|
case (_) { ret []; }
|
2011-04-20 17:23:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn collect_native_item(@crate_ctxt ccx, &@ast::native_item i, &vec[str] pt,
|
|
|
|
&vt[vec[str]] v) {
|
2011-04-20 17:23:45 +02:00
|
|
|
alt (i.node) {
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::native_item_fn(?name, _, _, _, ?fid, ?ann)) {
|
2011-04-20 17:23:45 +02:00
|
|
|
ccx.native_items.insert(fid, i);
|
|
|
|
if (!ccx.obj_methods.contains_key(fid)) {
|
2011-06-10 17:24:20 +02:00
|
|
|
decl_native_fn_and_pair(ccx, i.span, pt, name, ann, fid);
|
2011-04-20 17:23:45 +02:00
|
|
|
}
|
2011-03-26 17:36:47 -07:00
|
|
|
}
|
2011-05-12 17:24:54 +02:00
|
|
|
case (ast::native_item_ty(_, ?tid)) {
|
2011-04-20 17:23:45 +02:00
|
|
|
ccx.native_items.insert(tid, i);
|
2011-03-26 17:36:47 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-01-05 15:31:35 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn collect_item_1(@crate_ctxt ccx, &@ast::item i, &vec[str] pt,
|
|
|
|
&vt[vec[str]] v) {
|
2011-06-10 17:24:20 +02:00
|
|
|
visit::visit_item(i, pt + item_path(i), v);
|
2011-03-14 16:56:03 -04:00
|
|
|
alt (i.node) {
|
2011-06-14 17:06:06 -07:00
|
|
|
case (ast::item_const(?name, _, _, _, ?cid, ?ann)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto typ = node_ann_type(ccx, ann);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto g =
|
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, type_of(ccx, i.span, typ),
|
|
|
|
str::buf(ccx.names.next(name)));
|
|
|
|
llvm::LLVMSetLinkage(g,
|
|
|
|
lib::llvm::LLVMInternalLinkage as
|
|
|
|
llvm::Linkage);
|
2011-04-17 14:24:45 +02:00
|
|
|
ccx.items.insert(cid, i);
|
|
|
|
ccx.consts.insert(cid, g);
|
2011-03-14 16:56:03 -04:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ast::item_mod(?name, ?m, _, ?mid)) { ccx.items.insert(mid, i); }
|
2011-06-14 17:06:06 -07:00
|
|
|
case (ast::item_native_mod(_, _, _, ?mid)) {
|
2011-05-09 12:40:09 +02:00
|
|
|
ccx.items.insert(mid, i);
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ast::item_ty(_, _, _, _, ?did, _)) { ccx.items.insert(did, i); }
|
2011-06-14 17:06:06 -07:00
|
|
|
case (ast::item_tag(?name, ?variants, ?tps, _, ?tag_id, _)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
ccx.items.insert(tag_id, i);
|
2011-03-14 16:56:03 -04:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { }
|
2011-03-14 16:56:03 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn collect_item_2(&@crate_ctxt ccx, &@ast::item i, &vec[str] pt,
|
|
|
|
&vt[vec[str]] v) {
|
2011-06-10 17:24:20 +02:00
|
|
|
auto new_pt = pt + item_path(i);
|
|
|
|
visit::visit_item(i, new_pt, v);
|
2010-10-22 19:31:33 -07:00
|
|
|
alt (i.node) {
|
2011-06-14 17:06:06 -07:00
|
|
|
case (ast::item_fn(?name, ?f, ?tps, _, ?fid, ?ann)) {
|
2011-04-20 17:23:45 +02:00
|
|
|
ccx.items.insert(fid, i);
|
|
|
|
if (!ccx.obj_methods.contains_key(fid)) {
|
2011-06-10 17:24:20 +02:00
|
|
|
decl_fn_and_pair(ccx, i.span, new_pt, "fn", tps, ann, fid);
|
2011-01-05 15:31:35 -08:00
|
|
|
}
|
2010-10-22 19:31:33 -07:00
|
|
|
}
|
2011-06-14 17:06:06 -07:00
|
|
|
case (ast::item_obj(?name, ?ob, ?tps, _, ?oid, ?ann)) {
|
2011-04-20 17:23:45 +02:00
|
|
|
ccx.items.insert(oid.ctor, i);
|
2011-06-15 11:19:50 -07:00
|
|
|
decl_fn_and_pair(ccx, i.span, new_pt, "obj_ctor", tps, ann,
|
|
|
|
oid.ctor);
|
2011-05-12 17:24:54 +02:00
|
|
|
for (@ast::method m in ob.methods) {
|
2011-04-20 17:23:45 +02:00
|
|
|
ccx.obj_methods.insert(m.node.id, ());
|
2011-01-05 15:31:35 -08:00
|
|
|
}
|
2010-12-16 10:23:47 -08:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { }
|
2010-10-22 19:31:33 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn collect_items(&@crate_ctxt ccx, @ast::crate crate) {
|
2011-06-10 17:24:20 +02:00
|
|
|
auto visitor0 = visit::default_visitor();
|
2011-06-15 11:19:50 -07:00
|
|
|
auto visitor1 =
|
|
|
|
@rec(visit_native_item=bind collect_native_item(ccx, _, _, _),
|
|
|
|
visit_item=bind collect_item_1(ccx, _, _, _) with *visitor0);
|
|
|
|
auto visitor2 =
|
|
|
|
@rec(visit_item=bind collect_item_2(ccx, _, _, _) with *visitor0);
|
2011-06-10 17:24:20 +02:00
|
|
|
visit::visit_crate(*crate, [], visit::vtor(visitor1));
|
|
|
|
visit::visit_crate(*crate, [], visit::vtor(visitor2));
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn collect_tag_ctor(@crate_ctxt ccx, &@ast::item i, &vec[str] pt,
|
|
|
|
&vt[vec[str]] v) {
|
2011-06-10 17:24:20 +02:00
|
|
|
auto new_pt = pt + item_path(i);
|
|
|
|
visit::visit_item(i, new_pt, v);
|
2011-01-05 15:31:35 -08:00
|
|
|
alt (i.node) {
|
2011-06-14 17:06:06 -07:00
|
|
|
case (ast::item_tag(_, ?variants, ?tps, _, _, _)) {
|
2011-05-12 17:24:54 +02:00
|
|
|
for (ast::variant variant in variants) {
|
2011-05-17 20:41:41 +02:00
|
|
|
if (vec::len[ast::variant_arg](variant.node.args) != 0u) {
|
2011-05-18 15:35:16 -07:00
|
|
|
decl_fn_and_pair(ccx, i.span,
|
2011-06-15 11:19:50 -07:00
|
|
|
new_pt + [variant.node.name], "tag", tps,
|
|
|
|
variant.node.ann, variant.node.id);
|
2011-01-05 15:31:35 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) {/* fall through */ }
|
2011-01-05 15:31:35 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn collect_tag_ctors(&@crate_ctxt ccx, @ast::crate crate) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto visitor =
|
|
|
|
@rec(visit_item=bind collect_tag_ctor(ccx, _, _, _)
|
|
|
|
with *visit::default_visitor());
|
2011-06-10 17:24:20 +02:00
|
|
|
visit::visit_crate(*crate, [], visit::vtor(visitor));
|
2011-01-05 15:31:35 -08:00
|
|
|
}
|
|
|
|
|
2010-12-02 19:30:06 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
// The constant translation pass.
|
|
|
|
fn trans_constant(@crate_ctxt ccx, &@ast::item it, &vec[str] pt,
|
|
|
|
&vt[vec[str]] v) {
|
2011-06-10 17:24:20 +02:00
|
|
|
auto new_pt = pt + item_path(it);
|
|
|
|
visit::visit_item(it, new_pt, v);
|
2010-12-02 19:30:06 -08:00
|
|
|
alt (it.node) {
|
2011-06-14 17:06:06 -07:00
|
|
|
case (ast::item_tag(?ident, ?variants, _, _, ?tag_id, _)) {
|
2010-12-02 19:30:06 -08:00
|
|
|
auto i = 0u;
|
2011-05-17 20:41:41 +02:00
|
|
|
auto n_variants = vec::len[ast::variant](variants);
|
2011-02-25 18:16:50 -08:00
|
|
|
while (i < n_variants) {
|
|
|
|
auto variant = variants.(i);
|
2011-02-28 16:08:05 -08:00
|
|
|
auto discrim_val = C_int(i as int);
|
2011-06-10 17:24:20 +02:00
|
|
|
auto p = new_pt + [ident, variant.node.name, "discrim"];
|
2011-06-07 17:54:22 -07:00
|
|
|
auto s = mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx));
|
2011-06-15 11:19:50 -07:00
|
|
|
auto discrim_gvar =
|
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, T_int(), str::buf(s));
|
2011-05-12 17:24:54 +02:00
|
|
|
llvm::LLVMSetInitializer(discrim_gvar, discrim_val);
|
|
|
|
llvm::LLVMSetGlobalConstant(discrim_gvar, True);
|
2011-04-20 17:43:13 +02:00
|
|
|
ccx.discrims.insert(variant.node.id, discrim_gvar);
|
|
|
|
ccx.discrim_symbols.insert(variant.node.id, s);
|
2010-12-02 19:30:06 -08:00
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
}
|
2011-06-14 17:06:06 -07:00
|
|
|
case (ast::item_const(?name, _, ?expr, _, ?cid, ?ann)) {
|
2010-12-09 14:37:50 -08:00
|
|
|
// FIXME: The whole expr-translation system needs cloning to deal
|
|
|
|
// with consts.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-12-09 14:37:50 -08:00
|
|
|
auto v = C_int(1);
|
2011-04-20 17:43:13 +02:00
|
|
|
ccx.item_ids.insert(cid, v);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto s =
|
|
|
|
mangle_exported_name(ccx, new_pt + [name],
|
|
|
|
node_ann_type(ccx, ann));
|
2011-04-20 17:43:13 +02:00
|
|
|
ccx.item_symbols.insert(cid, s);
|
2010-12-09 14:37:50 -08:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { }
|
2010-12-02 19:30:06 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn trans_constants(&@crate_ctxt ccx, @ast::crate crate) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto visitor =
|
|
|
|
@rec(visit_item=bind trans_constant(ccx, _, _, _)
|
|
|
|
with *visit::default_visitor());
|
2011-06-10 17:24:20 +02:00
|
|
|
visit::visit_crate(*crate, [], visit::vtor(visitor));
|
2010-12-02 19:30:06 -08:00
|
|
|
}
|
|
|
|
|
2011-05-10 17:58:22 -07:00
|
|
|
fn vp2i(&@block_ctxt cx, ValueRef v) -> ValueRef {
|
2011-03-02 16:42:09 -08:00
|
|
|
ret cx.build.PtrToInt(v, T_int());
|
|
|
|
}
|
|
|
|
|
2011-05-10 17:58:22 -07:00
|
|
|
fn vi2p(&@block_ctxt cx, ValueRef v, TypeRef t) -> ValueRef {
|
2011-03-02 16:42:09 -08:00
|
|
|
ret cx.build.IntToPtr(v, t);
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn p2i(ValueRef v) -> ValueRef { ret llvm::LLVMConstPtrToInt(v, T_int()); }
|
2010-09-27 13:43:53 -07:00
|
|
|
|
2011-02-01 14:57:03 -08:00
|
|
|
fn i2p(ValueRef v, TypeRef t) -> ValueRef {
|
2011-05-12 17:24:54 +02:00
|
|
|
ret llvm::LLVMConstIntToPtr(v, t);
|
2011-02-01 14:57:03 -08:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn create_typedefs(&@crate_ctxt cx) {
|
2011-05-17 20:41:41 +02:00
|
|
|
llvm::LLVMAddTypeName(cx.llmod, str::buf("task"), T_task(cx.tn));
|
|
|
|
llvm::LLVMAddTypeName(cx.llmod, str::buf("tydesc"), T_tydesc(cx.tn));
|
2010-12-10 16:29:41 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn declare_intrinsics(ModuleRef llmod) -> hashmap[str, ValueRef] {
|
|
|
|
let vec[TypeRef] T_memmove32_args =
|
|
|
|
[T_ptr(T_i8()), T_ptr(T_i8()), T_i32(), T_i32(), T_i1()];
|
|
|
|
let vec[TypeRef] T_memmove64_args =
|
|
|
|
[T_ptr(T_i8()), T_ptr(T_i8()), T_i64(), T_i32(), T_i1()];
|
|
|
|
let vec[TypeRef] T_memset32_args =
|
|
|
|
[T_ptr(T_i8()), T_i8(), T_i32(), T_i32(), T_i1()];
|
|
|
|
let vec[TypeRef] T_memset64_args =
|
|
|
|
[T_ptr(T_i8()), T_i8(), T_i64(), T_i32(), T_i1()];
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[TypeRef] T_trap_args = [];
|
2011-06-15 11:19:50 -07:00
|
|
|
auto memmove32 =
|
|
|
|
decl_cdecl_fn(llmod, "llvm.memmove.p0i8.p0i8.i32",
|
|
|
|
T_fn(T_memmove32_args, T_void()));
|
|
|
|
auto memmove64 =
|
|
|
|
decl_cdecl_fn(llmod, "llvm.memmove.p0i8.p0i8.i64",
|
|
|
|
T_fn(T_memmove64_args, T_void()));
|
|
|
|
auto memset32 =
|
|
|
|
decl_cdecl_fn(llmod, "llvm.memset.p0i8.i32",
|
|
|
|
T_fn(T_memset32_args, T_void()));
|
|
|
|
auto memset64 =
|
|
|
|
decl_cdecl_fn(llmod, "llvm.memset.p0i8.i64",
|
|
|
|
T_fn(T_memset64_args, T_void()));
|
|
|
|
auto trap =
|
|
|
|
decl_cdecl_fn(llmod, "llvm.trap", T_fn(T_trap_args, T_void()));
|
2010-11-25 17:45:26 -08:00
|
|
|
auto intrinsics = new_str_hash[ValueRef]();
|
2011-05-10 14:22:14 -07:00
|
|
|
intrinsics.insert("llvm.memmove.p0i8.p0i8.i32", memmove32);
|
|
|
|
intrinsics.insert("llvm.memmove.p0i8.p0i8.i64", memmove64);
|
2011-05-10 11:50:29 -07:00
|
|
|
intrinsics.insert("llvm.memset.p0i8.i32", memset32);
|
|
|
|
intrinsics.insert("llvm.memset.p0i8.i64", memset64);
|
2010-11-25 17:45:26 -08:00
|
|
|
intrinsics.insert("llvm.trap", trap);
|
|
|
|
ret intrinsics;
|
2010-11-14 11:21:49 -08:00
|
|
|
}
|
|
|
|
|
2011-05-10 17:58:22 -07:00
|
|
|
fn trace_str(&@block_ctxt cx, str s) {
|
2011-05-10 14:03:47 -07:00
|
|
|
cx.build.Call(cx.fcx.lcx.ccx.upcalls.trace_str,
|
2011-05-16 18:21:22 -07:00
|
|
|
[cx.fcx.lltaskptr, C_cstr(cx.fcx.lcx.ccx, s)]);
|
2011-02-02 15:23:49 -08:00
|
|
|
}
|
|
|
|
|
2011-05-10 17:58:22 -07:00
|
|
|
fn trace_word(&@block_ctxt cx, ValueRef v) {
|
2011-06-15 11:19:50 -07:00
|
|
|
cx.build.Call(cx.fcx.lcx.ccx.upcalls.trace_word, [cx.fcx.lltaskptr, v]);
|
2011-02-02 15:23:49 -08:00
|
|
|
}
|
|
|
|
|
2011-05-10 17:58:22 -07:00
|
|
|
fn trace_ptr(&@block_ctxt cx, ValueRef v) {
|
2011-02-02 15:23:49 -08:00
|
|
|
trace_word(cx, cx.build.PtrToInt(v, T_int()));
|
|
|
|
}
|
|
|
|
|
2011-05-10 17:58:22 -07:00
|
|
|
fn trap(&@block_ctxt bcx) {
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ValueRef] v = [];
|
2011-04-17 14:24:45 +02:00
|
|
|
bcx.build.Call(bcx.fcx.lcx.ccx.intrinsics.get("llvm.trap"), v);
|
2011-02-02 15:23:49 -08:00
|
|
|
}
|
2010-12-06 17:17:49 -08:00
|
|
|
|
2011-03-10 17:25:11 -08:00
|
|
|
fn decl_no_op_type_glue(ModuleRef llmod, type_names tn) -> ValueRef {
|
2011-05-16 18:21:22 -07:00
|
|
|
auto ty = T_fn([T_taskptr(tn), T_ptr(T_i8())], T_void());
|
2011-05-12 17:24:54 +02:00
|
|
|
ret decl_fastcall_fn(llmod, abi::no_op_type_glue_name(), ty);
|
2011-03-10 17:25:11 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn make_no_op_type_glue(ValueRef fun) {
|
2011-05-17 20:41:41 +02:00
|
|
|
auto bb_name = str::buf("_rust_no_op_type_glue_bb");
|
2011-05-12 17:24:54 +02:00
|
|
|
auto llbb = llvm::LLVMAppendBasicBlock(fun, bb_name);
|
2010-12-17 18:42:15 -08:00
|
|
|
new_builder(llbb).RetVoid();
|
2010-12-17 18:40:04 -08:00
|
|
|
}
|
|
|
|
|
2011-05-10 17:58:22 -07:00
|
|
|
fn vec_fill(&@block_ctxt bcx, ValueRef v) -> ValueRef {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret bcx.build.Load(bcx.build.GEP(v,
|
|
|
|
[C_int(0), C_int(abi::vec_elt_fill)]));
|
2011-03-09 20:14:19 -08:00
|
|
|
}
|
|
|
|
|
2011-05-10 17:58:22 -07:00
|
|
|
fn vec_p0(&@block_ctxt bcx, ValueRef v) -> ValueRef {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto p = bcx.build.GEP(v, [C_int(0), C_int(abi::vec_elt_data)]);
|
2011-03-09 20:14:19 -08:00
|
|
|
ret bcx.build.PointerCast(p, T_ptr(T_i8()));
|
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn make_glues(ModuleRef llmod, &type_names tn) -> @glue_fns {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret @rec(no_op_type_glue=decl_no_op_type_glue(llmod, tn));
|
2010-12-17 18:40:04 -08:00
|
|
|
}
|
|
|
|
|
2011-05-12 17:24:54 +02:00
|
|
|
fn make_common_glue(&session::session sess, &str output) {
|
2011-03-10 17:25:11 -08:00
|
|
|
// FIXME: part of this is repetitive and is probably a good idea
|
2011-05-10 14:22:14 -07:00
|
|
|
// to autogen it.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-09-22 15:21:06 -07:00
|
|
|
auto llmod =
|
2011-05-17 20:41:41 +02:00
|
|
|
llvm::LLVMModuleCreateWithNameInContext(str::buf("rust_out"),
|
2011-06-15 11:19:50 -07:00
|
|
|
llvm::LLVMGetGlobalContext());
|
2011-05-17 20:41:41 +02:00
|
|
|
llvm::LLVMSetDataLayout(llmod, str::buf(x86::get_data_layout()));
|
|
|
|
llvm::LLVMSetTarget(llmod, str::buf(x86::get_target_triple()));
|
2011-05-12 17:24:54 +02:00
|
|
|
auto td = mk_target_data(x86::get_data_layout());
|
2011-02-17 18:16:51 -08:00
|
|
|
auto tn = mk_type_names();
|
2011-03-10 17:25:11 -08:00
|
|
|
auto intrinsics = declare_intrinsics(llmod);
|
2011-05-17 20:41:41 +02:00
|
|
|
llvm::LLVMSetModuleInlineAsm(llmod, str::buf(x86::get_module_asm()));
|
2011-03-10 17:25:11 -08:00
|
|
|
auto glues = make_glues(llmod, tn);
|
2011-05-13 16:47:37 -04:00
|
|
|
link::write::run_passes(sess, llmod, output);
|
2011-03-10 17:25:11 -08:00
|
|
|
}
|
|
|
|
|
2011-05-11 04:58:46 +00:00
|
|
|
fn create_module_map(&@crate_ctxt ccx) -> ValueRef {
|
2011-05-16 18:21:22 -07:00
|
|
|
auto elttype = T_struct([T_int(), T_int()]);
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
auto maptype = T_array(elttype, ccx.module_data.size() + 1u);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto map =
|
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, maptype, str::buf("_rust_mod_map"));
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ValueRef] elts = [];
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
for each (@tup(str, ValueRef) item in ccx.module_data.items()) {
|
2011-05-16 18:21:22 -07:00
|
|
|
auto elt = C_struct([p2i(C_cstr(ccx, item._0)), p2i(item._1)]);
|
2011-05-17 20:41:41 +02:00
|
|
|
vec::push[ValueRef](elts, elt);
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
}
|
2011-05-16 18:21:22 -07:00
|
|
|
auto term = C_struct([C_int(0), C_int(0)]);
|
2011-05-17 20:41:41 +02:00
|
|
|
vec::push[ValueRef](elts, term);
|
2011-05-12 17:24:54 +02:00
|
|
|
llvm::LLVMSetInitializer(map, C_array(elttype, elts));
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
ret map;
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
// FIXME use hashed metadata instead of crate names once we have that
|
2011-05-11 04:58:46 +00:00
|
|
|
fn create_crate_map(&@crate_ctxt ccx) -> ValueRef {
|
2011-05-16 18:21:22 -07:00
|
|
|
let vec[ValueRef] subcrates = [];
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
auto i = 1;
|
|
|
|
while (ccx.sess.has_external_crate(i)) {
|
|
|
|
auto name = ccx.sess.get_external_crate(i).name;
|
2011-06-15 11:19:50 -07:00
|
|
|
auto cr =
|
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, T_int(),
|
|
|
|
str::buf("_rust_crate_map_" + name));
|
2011-05-17 20:41:41 +02:00
|
|
|
vec::push[ValueRef](subcrates, p2i(cr));
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
i += 1;
|
|
|
|
}
|
2011-05-17 20:41:41 +02:00
|
|
|
vec::push[ValueRef](subcrates, C_int(0));
|
2011-06-07 16:41:19 -04:00
|
|
|
auto mapname;
|
|
|
|
if (ccx.sess.get_opts().shared) {
|
2011-06-07 17:54:22 -07:00
|
|
|
mapname = ccx.crate_meta_name;
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { mapname = "toplevel"; }
|
2011-06-07 16:41:19 -04:00
|
|
|
auto sym_name = "_rust_crate_map_" + mapname;
|
2011-05-17 20:41:41 +02:00
|
|
|
auto arrtype = T_array(T_int(), vec::len[ValueRef](subcrates));
|
2011-05-16 18:21:22 -07:00
|
|
|
auto maptype = T_struct([T_int(), arrtype]);
|
2011-05-17 20:41:41 +02:00
|
|
|
auto map = llvm::LLVMAddGlobal(ccx.llmod, maptype, str::buf(sym_name));
|
2011-06-15 11:19:50 -07:00
|
|
|
llvm::LLVMSetLinkage(map,
|
|
|
|
lib::llvm::LLVMExternalLinkage as llvm::Linkage);
|
|
|
|
llvm::LLVMSetInitializer(map,
|
|
|
|
C_struct([p2i(create_module_map(ccx)),
|
|
|
|
C_array(T_int(), subcrates)]));
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
ret map;
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn trans_crate(&session::session sess, &@ast::crate crate, &ty::ctxt tcx,
|
|
|
|
&str output) -> ModuleRef {
|
2011-03-10 17:25:11 -08:00
|
|
|
auto llmod =
|
2011-05-17 20:41:41 +02:00
|
|
|
llvm::LLVMModuleCreateWithNameInContext(str::buf("rust_out"),
|
2011-06-15 11:19:50 -07:00
|
|
|
llvm::LLVMGetGlobalContext());
|
2011-05-17 20:41:41 +02:00
|
|
|
llvm::LLVMSetDataLayout(llmod, str::buf(x86::get_data_layout()));
|
|
|
|
llvm::LLVMSetTarget(llmod, str::buf(x86::get_target_triple()));
|
2011-05-12 17:24:54 +02:00
|
|
|
auto td = mk_target_data(x86::get_data_layout());
|
2011-03-10 17:25:11 -08:00
|
|
|
auto tn = mk_type_names();
|
2010-11-25 17:45:26 -08:00
|
|
|
auto intrinsics = declare_intrinsics(llmod);
|
2011-02-17 18:16:51 -08:00
|
|
|
auto glues = make_glues(llmod, tn);
|
2011-05-12 17:24:54 +02:00
|
|
|
auto hasher = ty::hash_ty;
|
|
|
|
auto eqer = ty::eq_ty;
|
2011-06-15 11:19:50 -07:00
|
|
|
auto tag_sizes = map::mk_hashmap[ty::t, uint](hasher, eqer);
|
|
|
|
auto tydescs = map::mk_hashmap[ty::t, @tydesc_info](hasher, eqer);
|
|
|
|
auto lltypes = map::mk_hashmap[ty::t, TypeRef](hasher, eqer);
|
|
|
|
auto sha1s = map::mk_hashmap[ty::t, str](hasher, eqer);
|
|
|
|
auto abbrevs = map::mk_hashmap[ty::t, metadata::ty_abbrev](hasher, eqer);
|
|
|
|
auto short_names = map::mk_hashmap[ty::t, str](hasher, eqer);
|
2011-06-07 17:54:22 -07:00
|
|
|
auto sha = std::sha1::mk_sha1();
|
2011-06-15 11:19:50 -07:00
|
|
|
auto ccx =
|
|
|
|
@rec(sess=sess,
|
|
|
|
llmod=llmod,
|
|
|
|
td=td,
|
|
|
|
tn=tn,
|
|
|
|
externs=new_str_hash[ValueRef](),
|
|
|
|
intrinsics=intrinsics,
|
|
|
|
item_ids=new_def_hash[ValueRef](),
|
|
|
|
items=new_def_hash[@ast::item](),
|
|
|
|
native_items=new_def_hash[@ast::native_item](),
|
|
|
|
item_symbols=new_def_hash[str](),
|
|
|
|
mutable main_fn=none[ValueRef],
|
|
|
|
crate_meta_name=crate_meta_name(sess, *crate, output),
|
|
|
|
crate_meta_vers=crate_meta_vers(sess, *crate),
|
|
|
|
crate_meta_extras_hash=crate_meta_extras_hash(sha, *crate),
|
|
|
|
tag_sizes=tag_sizes,
|
|
|
|
discrims=new_def_hash[ValueRef](),
|
|
|
|
discrim_symbols=new_def_hash[str](),
|
|
|
|
fn_pairs=new_def_hash[ValueRef](),
|
|
|
|
consts=new_def_hash[ValueRef](),
|
|
|
|
obj_methods=new_def_hash[()](),
|
|
|
|
tydescs=tydescs,
|
|
|
|
module_data=new_str_hash[ValueRef](),
|
|
|
|
lltypes=lltypes,
|
|
|
|
glues=glues,
|
|
|
|
names=namegen(0),
|
|
|
|
sha=sha,
|
|
|
|
type_sha1s=sha1s,
|
|
|
|
type_abbrevs=abbrevs,
|
|
|
|
type_short_names=short_names,
|
|
|
|
tcx=tcx,
|
|
|
|
stats=rec(mutable n_static_tydescs=0u,
|
|
|
|
mutable n_derived_tydescs=0u,
|
|
|
|
mutable n_glues_created=0u,
|
|
|
|
mutable n_null_glues=0u,
|
|
|
|
mutable n_real_glues=0u),
|
|
|
|
upcalls=upcall::declare_upcalls(tn, llmod));
|
2011-04-20 17:23:45 +02:00
|
|
|
auto cx = new_local_ctxt(ccx);
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
create_typedefs(ccx);
|
2011-04-20 17:23:45 +02:00
|
|
|
collect_items(ccx, crate);
|
2011-04-20 17:43:13 +02:00
|
|
|
collect_tag_ctors(ccx, crate);
|
|
|
|
trans_constants(ccx, crate);
|
2010-10-05 18:21:44 -07:00
|
|
|
trans_mod(cx, crate.node.module);
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
auto crate_map = create_crate_map(ccx);
|
2011-05-12 15:42:12 -07:00
|
|
|
emit_tydescs(ccx);
|
2011-05-12 17:24:54 +02:00
|
|
|
// Translate the metadata:
|
2011-03-11 15:35:20 -08:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
middle::metadata::write_metadata(cx.ccx, crate);
|
2011-05-12 15:42:12 -07:00
|
|
|
if (ccx.sess.get_opts().stats) {
|
|
|
|
log_err "--- trans stats ---";
|
|
|
|
log_err #fmt("n_static_tydescs: %u", ccx.stats.n_static_tydescs);
|
|
|
|
log_err #fmt("n_derived_tydescs: %u", ccx.stats.n_derived_tydescs);
|
|
|
|
log_err #fmt("n_glues_created: %u", ccx.stats.n_glues_created);
|
|
|
|
log_err #fmt("n_null_glues: %u", ccx.stats.n_null_glues);
|
|
|
|
log_err #fmt("n_real_glues: %u", ccx.stats.n_real_glues);
|
|
|
|
}
|
2011-05-02 17:45:07 -07:00
|
|
|
ret llmod;
|
2010-09-22 15:21:06 -07:00
|
|
|
}
|
|
|
|
//
|
|
|
|
// Local Variables:
|
|
|
|
// mode: rust
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
2011-03-25 15:07:27 -07:00
|
|
|
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
2010-09-22 15:21:06 -07:00
|
|
|
// End:
|
|
|
|
//
|