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,
|
2012-01-13 10:58:31 +01:00
|
|
|
// trans_impl, and trans_item, are called only for the side effect of adding a
|
2011-06-01 11:34:52 -07:00
|
|
|
// 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-12-13 16:25:51 -08:00
|
|
|
|
2012-01-16 18:21:01 +08:00
|
|
|
import core::ctypes::c_uint;
|
2011-12-13 16:25:51 -08:00
|
|
|
import std::{map, time};
|
2011-05-12 17:24:54 +02:00
|
|
|
import std::map::hashmap;
|
2011-09-12 16:13:28 -07:00
|
|
|
import std::map::{new_int_hash, new_str_hash};
|
2011-12-13 16:25:51 -08:00
|
|
|
import option::{some, none};
|
2011-05-12 17:24:54 +02:00
|
|
|
import driver::session;
|
2012-01-12 17:59:49 +01:00
|
|
|
import session::session;
|
2011-11-14 21:06:39 +08:00
|
|
|
import front::attr;
|
2011-11-10 00:55:09 -05:00
|
|
|
import middle::{ty, gc, resolve, debuginfo};
|
2011-07-21 14:49:58 -07:00
|
|
|
import middle::freevars::*;
|
2011-11-11 00:41:42 +08:00
|
|
|
import back::{link, abi, upcall};
|
2011-11-18 02:55:01 -05:00
|
|
|
import syntax::{ast, ast_util, codemap};
|
2011-07-05 11:48:19 +02:00
|
|
|
import syntax::visit;
|
2011-09-12 16:13:28 -07:00
|
|
|
import syntax::codemap::span;
|
2012-01-14 16:05:07 -08:00
|
|
|
import syntax::print::pprust::{expr_to_str, stmt_to_str, path_to_str};
|
|
|
|
import pat_util::*;
|
2011-06-10 17:24:20 +02:00
|
|
|
import visit::vt;
|
2011-07-13 17:26:06 -07:00
|
|
|
import util::common::*;
|
2011-11-11 00:41:42 +08:00
|
|
|
import lib::llvm::{llvm, mk_target_data, mk_type_names};
|
|
|
|
import lib::llvm::llvm::{ModuleRef, ValueRef, TypeRef, BasicBlockRef};
|
|
|
|
import lib::llvm::{True, False};
|
2011-09-12 16:13:28 -07:00
|
|
|
import link::{mangle_internal_name_by_type_only,
|
|
|
|
mangle_internal_name_by_seq,
|
|
|
|
mangle_internal_name_by_path,
|
|
|
|
mangle_internal_name_by_path_and_seq,
|
|
|
|
mangle_exported_name};
|
2011-11-11 00:41:42 +08:00
|
|
|
import metadata::{csearch, cstore};
|
2011-09-12 16:13:28 -07:00
|
|
|
import util::ppaux::{ty_to_str, ty_to_short_str};
|
2011-06-07 17:54:22 -07:00
|
|
|
|
2011-07-14 17:08:22 -07:00
|
|
|
import trans_common::*;
|
2011-08-30 09:59:30 +02:00
|
|
|
import trans_build::*;
|
2011-09-02 16:09:41 +02:00
|
|
|
import tvec = trans_vec;
|
2011-08-09 16:42:55 -07:00
|
|
|
|
2011-10-10 09:51:09 +02:00
|
|
|
fn type_of_1(bcx: @block_ctxt, t: ty::t) -> TypeRef {
|
|
|
|
let cx = bcx_ccx(bcx);
|
|
|
|
check type_has_static_size(cx, t);
|
|
|
|
type_of(cx, bcx.sp, t)
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn type_of(cx: @crate_ctxt, sp: span, t: ty::t) : type_has_static_size(cx, t)
|
|
|
|
-> TypeRef {
|
2011-09-15 20:47:38 -07:00
|
|
|
// Should follow from type_has_static_size -- argh.
|
2011-09-16 13:04:14 -07:00
|
|
|
// FIXME (requires Issue #586)
|
2011-09-15 20:47:38 -07:00
|
|
|
check non_ty_var(cx, t);
|
2011-09-12 11:27:30 +02:00
|
|
|
type_of_inner(cx, sp, t)
|
|
|
|
}
|
2010-11-20 22:04:34 -08:00
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn type_of_explicit_args(cx: @crate_ctxt, sp: span, inputs: [ty::arg]) ->
|
2011-08-04 16:20:09 -07:00
|
|
|
[TypeRef] {
|
2011-09-07 15:13:19 +02:00
|
|
|
let atys = [];
|
2011-09-15 20:47:38 -07:00
|
|
|
for arg in inputs {
|
|
|
|
let arg_ty = arg.ty;
|
2011-09-16 13:04:14 -07:00
|
|
|
// FIXME: would be nice to have a constraint on arg
|
|
|
|
// that would obviate the need for this check
|
2011-09-15 20:47:38 -07:00
|
|
|
check non_ty_var(cx, arg_ty);
|
2011-10-06 14:17:56 +02:00
|
|
|
let llty = type_of_inner(cx, sp, arg_ty);
|
2011-11-16 12:32:38 +01:00
|
|
|
atys += [arg.mode == ast::by_val ? llty : T_ptr(llty)];
|
2011-09-15 20:47:38 -07:00
|
|
|
}
|
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:
|
|
|
|
//
|
2011-09-14 14:34:50 +02:00
|
|
|
// - type_of_fn
|
2011-02-08 11:47:53 -08:00
|
|
|
// - create_llargs_for_fn_args.
|
|
|
|
// - new_fn_ctxt
|
|
|
|
// - trans_args
|
2012-01-13 10:58:31 +01:00
|
|
|
fn type_of_fn(cx: @crate_ctxt, sp: span, inputs: [ty::arg],
|
2012-01-02 13:26:51 +01:00
|
|
|
output: ty::t, params: [ty::param_bounds]) -> TypeRef {
|
2011-08-19 15:16:48 -07:00
|
|
|
let atys: [TypeRef] = [];
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-28 18:54:05 -07:00
|
|
|
// Arg 0: Output pointer.
|
2012-01-02 13:26:51 +01:00
|
|
|
check non_ty_var(cx, output);
|
2011-09-14 14:34:50 +02:00
|
|
|
let out_ty = T_ptr(type_of_inner(cx, sp, output));
|
2011-11-23 10:56:10 +01:00
|
|
|
atys += [out_ty];
|
2011-02-08 11:47:53 -08:00
|
|
|
|
2012-01-13 10:58:31 +01:00
|
|
|
// Arg 1: Environment
|
|
|
|
atys += [T_opaque_cbox_ptr(cx)];
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-10-20 11:56:45 +02:00
|
|
|
// Args >2: ty params, if not acquired via capture...
|
2012-01-13 10:58:31 +01:00
|
|
|
for bounds in params {
|
|
|
|
atys += [T_ptr(cx.tydesc_type)];
|
|
|
|
for bound in *bounds {
|
|
|
|
alt bound {
|
|
|
|
ty::bound_iface(_) { atys += [T_ptr(T_dict())]; }
|
|
|
|
_ {}
|
2012-01-02 16:50:51 +01:00
|
|
|
}
|
2012-01-02 12:00:40 +01:00
|
|
|
}
|
2011-02-08 11:47:53 -08:00
|
|
|
}
|
2011-06-28 18:54:05 -07:00
|
|
|
// ... then explicit args.
|
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-07-26 17:59:43 -07:00
|
|
|
// Given a function type and a count of ty params, construct an llvm type
|
2011-09-12 11:27:30 +02:00
|
|
|
fn type_of_fn_from_ty(cx: @crate_ctxt, sp: span, fty: ty::t,
|
2012-01-04 22:12:43 +01:00
|
|
|
param_bounds: [ty::param_bounds]) -> TypeRef {
|
2011-09-16 13:04:14 -07:00
|
|
|
// FIXME: Check should be unnecessary, b/c it's implied
|
|
|
|
// by returns_non_ty_var(t). Make that a postcondition
|
|
|
|
// (see Issue #586)
|
2011-09-15 20:47:38 -07:00
|
|
|
let ret_ty = ty::ty_fn_ret(cx.tcx, fty);
|
2012-01-13 10:58:31 +01:00
|
|
|
ret type_of_fn(cx, sp, ty::ty_fn_args(cx.tcx, fty),
|
2012-01-02 12:00:40 +01:00
|
|
|
ret_ty, param_bounds);
|
2011-07-26 17:59:43 -07:00
|
|
|
}
|
|
|
|
|
2011-09-15 20:47:38 -07:00
|
|
|
fn type_of_inner(cx: @crate_ctxt, sp: span, t: ty::t)
|
|
|
|
: non_ty_var(cx, t) -> TypeRef {
|
2011-04-19 16:40:46 -07:00
|
|
|
// Check the cache.
|
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
if cx.lltypes.contains_key(t) { ret cx.lltypes.get(t); }
|
2011-12-15 11:06:48 -08:00
|
|
|
let llty = alt ty::struct(cx.tcx, t) {
|
2011-09-15 20:47:38 -07:00
|
|
|
ty::ty_native(_) { T_ptr(T_i8()) }
|
2012-01-18 22:37:22 -08:00
|
|
|
ty::ty_nil { T_nil() }
|
|
|
|
ty::ty_bot {
|
2011-09-15 20:47:38 -07:00
|
|
|
T_nil() /* ...I guess? */
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ty::ty_bool { T_bool() }
|
2011-12-07 21:06:12 +01:00
|
|
|
ty::ty_int(t) { T_int_ty(cx, t) }
|
|
|
|
ty::ty_uint(t) { T_uint_ty(cx, t) }
|
|
|
|
ty::ty_float(t) { T_float_ty(cx, t) }
|
2012-01-18 22:37:22 -08:00
|
|
|
ty::ty_str { T_ptr(T_vec(cx, T_i8())) }
|
2011-09-15 20:47:38 -07:00
|
|
|
ty::ty_tag(did, _) { type_of_tag(cx, sp, did, t) }
|
|
|
|
ty::ty_box(mt) {
|
|
|
|
let mt_ty = mt.ty;
|
|
|
|
check non_ty_var(cx, mt_ty);
|
2011-10-14 16:45:25 -07:00
|
|
|
T_ptr(T_box(cx, type_of_inner(cx, sp, mt_ty))) }
|
2011-09-21 18:54:54 -07:00
|
|
|
ty::ty_uniq(mt) {
|
|
|
|
let mt_ty = mt.ty;
|
|
|
|
check non_ty_var(cx, mt_ty);
|
|
|
|
T_ptr(type_of_inner(cx, sp, mt_ty)) }
|
2011-08-18 14:11:06 -07:00
|
|
|
ty::ty_vec(mt) {
|
2011-09-15 20:47:38 -07:00
|
|
|
let mt_ty = mt.ty;
|
|
|
|
if ty::type_has_dynamic_size(cx.tcx, mt_ty) {
|
2011-10-14 20:38:24 -07:00
|
|
|
T_ptr(cx.opaque_vec_type)
|
2011-09-15 20:47:38 -07:00
|
|
|
} else {
|
|
|
|
// should be unnecessary
|
|
|
|
check non_ty_var(cx, mt_ty);
|
2011-10-14 16:45:25 -07:00
|
|
|
T_ptr(T_vec(cx, type_of_inner(cx, sp, mt_ty))) }
|
2011-09-15 20:47:38 -07:00
|
|
|
}
|
|
|
|
ty::ty_ptr(mt) {
|
|
|
|
let mt_ty = mt.ty;
|
|
|
|
check non_ty_var(cx, mt_ty);
|
|
|
|
T_ptr(type_of_inner(cx, sp, mt_ty)) }
|
2011-07-27 14:19:39 +02:00
|
|
|
ty::ty_rec(fields) {
|
2011-08-19 15:16:48 -07:00
|
|
|
let tys: [TypeRef] = [];
|
2011-08-15 21:54:52 -07:00
|
|
|
for f: ty::field in fields {
|
2011-09-15 20:47:38 -07:00
|
|
|
let mt_ty = f.mt.ty;
|
|
|
|
check non_ty_var(cx, mt_ty);
|
|
|
|
tys += [type_of_inner(cx, sp, mt_ty)];
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-09-15 20:47:38 -07:00
|
|
|
T_struct(tys)
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-12-23 16:09:52 +01:00
|
|
|
ty::ty_fn(_) {
|
2012-01-02 12:00:40 +01:00
|
|
|
T_fn_pair(cx, type_of_fn_from_ty(cx, sp, t, []))
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-11-21 02:15:40 +08:00
|
|
|
ty::ty_native_fn(args, out) {
|
2012-01-02 12:00:40 +01:00
|
|
|
let nft = native_fn_wrapper_type(cx, sp, [], t);
|
2011-11-18 15:40:23 -08:00
|
|
|
T_fn_pair(cx, nft)
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-07 22:44:14 +01:00
|
|
|
ty::ty_iface(_, _) { T_opaque_iface_ptr(cx) }
|
2011-07-27 14:19:39 +02:00
|
|
|
ty::ty_res(_, sub, tps) {
|
|
|
|
let sub1 = ty::substitute_type_params(cx.tcx, tps, sub);
|
2011-09-15 20:47:38 -07:00
|
|
|
check non_ty_var(cx, sub1);
|
2011-11-17 13:43:34 -08:00
|
|
|
// FIXME #1184: Resource flag is larger than necessary
|
2011-11-17 13:36:09 -08:00
|
|
|
ret T_struct([cx.int_type, type_of_inner(cx, sp, sub1)]);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
ty::ty_var(_) {
|
2011-09-15 23:14:24 -07:00
|
|
|
// Should be unreachable b/c of precondition.
|
|
|
|
// FIXME: would be nice to have a way of expressing this
|
|
|
|
// through postconditions, and then making it sound to omit
|
|
|
|
// cases in the alt
|
|
|
|
std::util::unreachable()
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-09-15 20:47:38 -07:00
|
|
|
ty::ty_param(_, _) { T_typaram(cx.tn) }
|
2012-01-18 22:37:22 -08:00
|
|
|
ty::ty_send_type | ty::ty_type { T_ptr(cx.tydesc_type) }
|
2011-08-15 11:40:26 +02:00
|
|
|
ty::ty_tup(elts) {
|
2011-08-19 15:16:48 -07:00
|
|
|
let tys = [];
|
2011-09-15 20:47:38 -07:00
|
|
|
for elt in elts {
|
|
|
|
check non_ty_var(cx, elt);
|
|
|
|
tys += [type_of_inner(cx, sp, elt)];
|
|
|
|
}
|
|
|
|
T_struct(tys)
|
2011-08-15 11:40:26 +02:00
|
|
|
}
|
2012-01-05 16:19:12 -08:00
|
|
|
ty::ty_opaque_closure_ptr(_) {
|
|
|
|
T_opaque_cbox_ptr(cx)
|
2011-12-15 11:06:48 -08:00
|
|
|
}
|
2012-01-03 15:50:05 -08:00
|
|
|
ty::ty_constr(subt,_) {
|
|
|
|
// FIXME: could be a constraint on ty_fn
|
|
|
|
check non_ty_var(cx, subt);
|
|
|
|
type_of_inner(cx, sp, subt)
|
|
|
|
}
|
2011-12-15 14:30:19 -08:00
|
|
|
_ {
|
|
|
|
fail "type_of_inner not implemented for this kind of type";
|
|
|
|
}
|
2011-09-15 20:47:38 -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-09-17 09:12:26 -07:00
|
|
|
fn type_of_tag(cx: @crate_ctxt, sp: span, did: ast::def_id, t: ty::t)
|
|
|
|
-> TypeRef {
|
2011-12-15 17:14:58 -08:00
|
|
|
let degen = vec::len(*ty::tag_variants(cx.tcx, did)) == 1u;
|
2011-09-17 09:12:26 -07:00
|
|
|
if check type_has_static_size(cx, t) {
|
2011-07-27 14:19:39 +02:00
|
|
|
let size = static_size_of_tag(cx, sp, t);
|
2011-10-25 13:13:55 -07:00
|
|
|
if !degen { T_tag(cx, size) }
|
2011-11-23 12:01:15 -08:00
|
|
|
else if size == 0u { T_struct([T_tag_variant(cx)]) }
|
2011-10-13 14:45:34 +02:00
|
|
|
else { T_array(T_i8(), size) }
|
2011-07-01 12:36:49 +02:00
|
|
|
}
|
2011-09-17 09:12:26 -07:00
|
|
|
else {
|
2011-11-23 12:01:15 -08:00
|
|
|
if degen { T_struct([T_tag_variant(cx)]) }
|
2011-10-25 13:13:55 -07:00
|
|
|
else { T_opaque_tag(cx) }
|
2011-09-17 09:12:26 -07:00
|
|
|
}
|
2011-07-01 12:36:49 +02:00
|
|
|
}
|
|
|
|
|
2011-12-28 17:50:12 +01:00
|
|
|
fn type_of_ty_param_bounds_and_ty(lcx: @local_ctxt, sp: span,
|
|
|
|
tpt: ty::ty_param_bounds_and_ty) -> TypeRef {
|
2011-09-02 18:59:22 -07:00
|
|
|
let cx = lcx.ccx;
|
|
|
|
let t = tpt.ty;
|
|
|
|
alt ty::struct(cx.tcx, t) {
|
2011-12-23 16:09:52 +01:00
|
|
|
ty::ty_fn(_) | ty::ty_native_fn(_, _) {
|
2012-01-02 12:09:26 +01:00
|
|
|
ret type_of_fn_from_ty(cx, sp, t, *tpt.bounds);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ {
|
|
|
|
// fall through
|
|
|
|
}
|
2011-03-30 18:15:29 -07:00
|
|
|
}
|
2011-09-02 18:59:22 -07:00
|
|
|
// FIXME: could have a precondition on tpt, but that
|
|
|
|
// doesn't work right now because one predicate can't imply
|
|
|
|
// another
|
2011-09-12 11:27:30 +02:00
|
|
|
check (type_has_static_size(cx, t));
|
2011-09-02 18:59:22 -07:00
|
|
|
type_of(cx, sp, t)
|
2011-03-30 18:15:29 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn type_of_or_i8(bcx: @block_ctxt, typ: ty::t) -> TypeRef {
|
2011-09-02 18:59:22 -07:00
|
|
|
let ccx = bcx_ccx(bcx);
|
|
|
|
if check type_has_static_size(ccx, typ) {
|
|
|
|
let sp = bcx.sp;
|
|
|
|
type_of(ccx, sp, typ)
|
2011-09-12 11:27:30 +02:00
|
|
|
} else { T_i8() }
|
|
|
|
}
|
2011-06-10 19:35:59 -07:00
|
|
|
|
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-09-12 11:27:30 +02:00
|
|
|
fn sanitize(s: str) -> str {
|
2011-09-02 15:34:58 -07:00
|
|
|
let result = "";
|
2011-08-15 21:54:52 -07:00
|
|
|
for c: u8 in s {
|
2011-07-27 14:19:39 +02:00
|
|
|
if c == '@' as u8 {
|
2011-09-02 15:34:58 -07:00
|
|
|
result += "boxed_";
|
2010-12-10 15:02:23 -08:00
|
|
|
} else {
|
2011-07-27 14:19:39 +02:00
|
|
|
if c == ',' as u8 {
|
2011-09-02 15:34:58 -07:00
|
|
|
result += "_";
|
2010-12-20 19:52:14 -08:00
|
|
|
} else {
|
2011-07-27 14:19:39 +02:00
|
|
|
if c == '{' as u8 || c == '(' as u8 {
|
2011-09-02 15:34:58 -07:00
|
|
|
result += "_of_";
|
2010-12-20 19:52:14 -08:00
|
|
|
} else {
|
2011-07-27 14:19:39 +02:00
|
|
|
if c != 10u8 && c != '}' as u8 && c != ')' as u8 &&
|
|
|
|
c != ' ' as u8 && c != '\t' as u8 && c != ';' as u8
|
|
|
|
{
|
2011-08-19 15:16:48 -07:00
|
|
|
let v = [c];
|
2011-09-01 17:27:58 -07:00
|
|
|
result += str::unsafe_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-09-12 11:27:30 +02:00
|
|
|
fn log_fn_time(ccx: @crate_ctxt, name: str, start: time::timeval,
|
|
|
|
end: time::timeval) {
|
2011-07-27 14:19:39 +02:00
|
|
|
let elapsed =
|
|
|
|
1000 * (end.sec - start.sec as int) +
|
|
|
|
((end.usec as int) - (start.usec as int)) / 1000;
|
2011-08-19 15:16:48 -07:00
|
|
|
*ccx.stats.fn_times += [{ident: name, time: elapsed}];
|
2011-07-19 11:56:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-16 18:21:01 +08:00
|
|
|
fn decl_fn(llmod: ModuleRef, name: str, cc: uint, llty: TypeRef) ->
|
|
|
|
ValueRef {
|
2011-09-02 15:34:58 -07:00
|
|
|
let llfn: ValueRef =
|
2011-11-15 00:32:31 +08:00
|
|
|
str::as_buf(name, {|buf|
|
|
|
|
llvm::LLVMGetOrInsertFunction(llmod, buf, llty) });
|
2012-01-16 18:21:01 +08:00
|
|
|
llvm::LLVMSetFunctionCallConv(llfn, cc as c_uint);
|
2010-09-23 17:16:34 -07:00
|
|
|
ret llfn;
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn decl_cdecl_fn(llmod: ModuleRef, name: str, llty: TypeRef) -> 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-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-09-27 18:42:06 -07:00
|
|
|
fn decl_internal_cdecl_fn(llmod: ModuleRef, name: str, llty: TypeRef) ->
|
2011-06-15 11:19:50 -07:00
|
|
|
ValueRef {
|
2011-09-27 18:42:06 -07:00
|
|
|
let llfn = decl_cdecl_fn(llmod, name, 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-09-12 11:27:30 +02:00
|
|
|
fn get_extern_fn(externs: hashmap<str, ValueRef>, llmod: ModuleRef, name: str,
|
|
|
|
cc: uint, ty: TypeRef) -> ValueRef {
|
2011-09-02 15:34:58 -07:00
|
|
|
if externs.contains_key(name) { ret externs.get(name); }
|
2011-07-27 14:19:39 +02:00
|
|
|
let f = decl_fn(llmod, name, cc, ty);
|
2011-08-26 21:34:56 -07:00
|
|
|
externs.insert(name, f);
|
2010-09-23 18:38:37 -07:00
|
|
|
ret f;
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn get_extern_const(externs: hashmap<str, ValueRef>, llmod: ModuleRef,
|
|
|
|
name: str, ty: TypeRef) -> ValueRef {
|
2011-09-02 15:34:58 -07:00
|
|
|
if externs.contains_key(name) { ret externs.get(name); }
|
|
|
|
let c = str::as_buf(name, {|buf| llvm::LLVMAddGlobal(llmod, ty, buf) });
|
2011-08-26 21:34:56 -07:00
|
|
|
externs.insert(name, c);
|
2011-03-25 17:59:45 -07:00
|
|
|
ret c;
|
|
|
|
}
|
|
|
|
|
2011-10-14 16:45:25 -07:00
|
|
|
fn get_simple_extern_fn(cx: @block_ctxt,
|
|
|
|
externs: hashmap<str, ValueRef>,
|
|
|
|
llmod: ModuleRef,
|
2011-09-12 11:27:30 +02:00
|
|
|
name: str, n_args: int) -> ValueRef {
|
2011-10-14 16:45:25 -07:00
|
|
|
let ccx = cx.fcx.lcx.ccx;
|
2012-01-18 16:02:29 -05:00
|
|
|
let inputs = vec::init_elt::<TypeRef>(n_args as uint, ccx.int_type);
|
2011-10-14 17:00:17 -07:00
|
|
|
let output = ccx.int_type;
|
2011-07-27 14:19:39 +02:00
|
|
|
let t = T_fn(inputs, output);
|
2012-01-16 18:21:01 +08:00
|
|
|
ret get_extern_fn(externs, llmod, name,
|
|
|
|
lib::llvm::LLVMCCallConv, t);
|
2011-03-25 17:59:45 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trans_native_call(cx: @block_ctxt, externs: hashmap<str, ValueRef>,
|
|
|
|
llmod: ModuleRef, name: str, args: [ValueRef]) ->
|
2011-08-19 15:16:48 -07:00
|
|
|
ValueRef {
|
2011-12-13 16:25:51 -08:00
|
|
|
let n: int = vec::len::<ValueRef>(args) as int;
|
2011-10-14 16:45:25 -07:00
|
|
|
let llnative: ValueRef =
|
|
|
|
get_simple_extern_fn(cx, externs, llmod, name, n);
|
2011-08-19 15:16:48 -07:00
|
|
|
let call_args: [ValueRef] = [];
|
2011-10-14 16:45:25 -07:00
|
|
|
for a: ValueRef in args {
|
2011-10-14 20:38:24 -07:00
|
|
|
call_args += [ZExtOrBitCast(cx, a, bcx_ccx(cx).int_type)];
|
2011-10-14 16:45:25 -07:00
|
|
|
}
|
2011-08-30 09:59:30 +02:00
|
|
|
ret Call(cx, llnative, call_args);
|
2010-09-24 14:56:04 -07:00
|
|
|
}
|
|
|
|
|
2011-12-14 07:31:12 -08:00
|
|
|
fn trans_free_if_not_gc(cx: @block_ctxt, v: ValueRef) -> @block_ctxt {
|
|
|
|
let ccx = bcx_ccx(cx);
|
2012-01-12 17:59:49 +01:00
|
|
|
if !ccx.sess.opts.do_gc {
|
2011-12-14 07:31:12 -08:00
|
|
|
Call(cx, ccx.upcalls.free,
|
|
|
|
[PointerCast(cx, v, T_ptr(T_i8())),
|
|
|
|
C_int(bcx_ccx(cx), 0)]);
|
|
|
|
}
|
2011-08-30 13:50:58 +02:00
|
|
|
ret cx;
|
2010-09-29 17:22:07 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trans_shared_free(cx: @block_ctxt, v: ValueRef) -> @block_ctxt {
|
2011-08-30 09:59:30 +02:00
|
|
|
Call(cx, bcx_ccx(cx).upcalls.shared_free,
|
2011-10-20 11:42:40 +02:00
|
|
|
[PointerCast(cx, v, T_ptr(T_i8()))]);
|
2011-08-30 13:50:58 +02:00
|
|
|
ret cx;
|
2011-07-05 22:55:41 -07:00
|
|
|
}
|
|
|
|
|
2012-01-19 10:37:40 -08:00
|
|
|
fn umax(cx: @block_ctxt, a: ValueRef, b: ValueRef) -> ValueRef {
|
|
|
|
let cond = ICmp(cx, lib::llvm::LLVMIntULT, a, b);
|
|
|
|
ret Select(cx, cond, b, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn umin(cx: @block_ctxt, a: ValueRef, b: ValueRef) -> ValueRef {
|
|
|
|
let cond = ICmp(cx, lib::llvm::LLVMIntULT, a, b);
|
|
|
|
ret Select(cx, cond, a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn align_to(cx: @block_ctxt, off: ValueRef, align: ValueRef) -> ValueRef {
|
|
|
|
let mask = Sub(cx, align, C_int(bcx_ccx(cx), 1));
|
|
|
|
let bumped = Add(cx, off, mask);
|
|
|
|
ret And(cx, bumped, Not(cx, mask));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Returns the real size of the given type for the current target.
|
|
|
|
fn llsize_of_real(cx: @crate_ctxt, t: TypeRef) -> uint {
|
|
|
|
ret llvm::LLVMStoreSizeOfType(cx.td.lltd, t) as uint;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the real alignment of the given type for the current target.
|
|
|
|
fn llalign_of_real(cx: @crate_ctxt, t: TypeRef) -> uint {
|
|
|
|
ret llvm::LLVMPreferredAlignmentOfType(cx.td.lltd, t) as uint;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn llsize_of(cx: @crate_ctxt, t: TypeRef) -> ValueRef {
|
|
|
|
ret llvm::LLVMConstIntCast(lib::llvm::llvm::LLVMSizeOf(t), cx.int_type,
|
|
|
|
False);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn llalign_of(cx: @crate_ctxt, t: TypeRef) -> ValueRef {
|
|
|
|
ret llvm::LLVMConstIntCast(lib::llvm::llvm::LLVMAlignOf(t), cx.int_type,
|
|
|
|
False);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn size_of(cx: @block_ctxt, t: ty::t) -> result {
|
|
|
|
size_of_(cx, t)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn size_of_(cx: @block_ctxt, t: ty::t) -> result {
|
|
|
|
let ccx = bcx_ccx(cx);
|
|
|
|
if check type_has_static_size(ccx, t) {
|
|
|
|
let sp = cx.sp;
|
|
|
|
rslt(cx, llsize_of(bcx_ccx(cx), type_of(ccx, sp, t)))
|
|
|
|
} else { dynamic_size_of(cx, t) }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn align_of(cx: @block_ctxt, t: ty::t) -> result {
|
|
|
|
let ccx = bcx_ccx(cx);
|
|
|
|
if check type_has_static_size(ccx, t) {
|
|
|
|
let sp = cx.sp;
|
|
|
|
rslt(cx, llalign_of(bcx_ccx(cx), type_of(ccx, sp, t)))
|
|
|
|
} else { dynamic_align_of(cx, t) }
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn alloca(cx: @block_ctxt, t: TypeRef) -> ValueRef {
|
2011-09-26 03:57:08 +02:00
|
|
|
if cx.unreachable { ret llvm::LLVMGetUndef(t); }
|
2011-08-30 09:59:30 +02:00
|
|
|
ret Alloca(new_raw_block_ctxt(cx.fcx, cx.fcx.llstaticallocas), t);
|
2011-03-28 18:04:52 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn dynastack_alloca(cx: @block_ctxt, t: TypeRef, n: ValueRef, ty: ty::t) ->
|
2011-09-02 15:34:58 -07:00
|
|
|
ValueRef {
|
2011-09-26 03:57:08 +02:00
|
|
|
if cx.unreachable { ret llvm::LLVMGetUndef(t); }
|
2011-08-17 18:14:47 -07:00
|
|
|
let bcx = cx;
|
2011-08-24 14:54:55 +02:00
|
|
|
let dy_cx = new_raw_block_ctxt(cx.fcx, cx.fcx.lldynamicallocas);
|
2011-08-17 17:27:31 -07:00
|
|
|
alt bcx_fcx(cx).llobstacktoken {
|
2012-01-18 22:37:22 -08:00
|
|
|
none {
|
2011-08-19 15:16:48 -07:00
|
|
|
bcx_fcx(cx).llobstacktoken =
|
2011-10-20 11:42:40 +02:00
|
|
|
some(mk_obstack_token(bcx_ccx(cx), cx.fcx));
|
2011-08-19 15:16:48 -07:00
|
|
|
}
|
|
|
|
some(_) {/* no-op */ }
|
2011-08-17 17:27:31 -07:00
|
|
|
}
|
2011-08-17 18:14:47 -07:00
|
|
|
|
|
|
|
let dynastack_alloc = bcx_ccx(bcx).upcalls.dynastack_alloc;
|
2011-10-14 16:45:25 -07:00
|
|
|
let llsz = Mul(dy_cx,
|
|
|
|
C_uint(bcx_ccx(bcx), llsize_of_real(bcx_ccx(bcx), t)),
|
|
|
|
n);
|
2011-08-31 19:19:05 -07:00
|
|
|
|
|
|
|
let ti = none;
|
2012-01-13 10:58:31 +01:00
|
|
|
let lltydesc = get_tydesc(cx, ty, false, ti).result.val;
|
2011-08-31 19:19:05 -07:00
|
|
|
|
2011-10-20 11:42:40 +02:00
|
|
|
let llresult = Call(dy_cx, dynastack_alloc, [llsz, lltydesc]);
|
2011-08-30 09:59:30 +02:00
|
|
|
ret PointerCast(dy_cx, llresult, T_ptr(t));
|
2011-08-17 18:14:47 -07:00
|
|
|
}
|
|
|
|
|
2011-10-20 11:42:40 +02:00
|
|
|
fn mk_obstack_token(ccx: @crate_ctxt, fcx: @fn_ctxt) ->
|
2011-09-02 15:34:58 -07:00
|
|
|
ValueRef {
|
2011-08-24 14:54:55 +02:00
|
|
|
let cx = new_raw_block_ctxt(fcx, fcx.lldynamicallocas);
|
2011-10-20 11:42:40 +02:00
|
|
|
ret Call(cx, ccx.upcalls.dynastack_mark, []);
|
2011-03-28 18:04:52 -07:00
|
|
|
}
|
|
|
|
|
2012-01-19 10:37:40 -08: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.
|
|
|
|
fn simplify_type(ccx: @crate_ctxt, typ: ty::t) -> ty::t {
|
|
|
|
fn simplifier(ccx: @crate_ctxt, typ: ty::t) -> ty::t {
|
|
|
|
alt ty::struct(ccx.tcx, typ) {
|
|
|
|
ty::ty_box(_) | ty::ty_iface(_, _) {
|
|
|
|
ret ty::mk_imm_box(ccx.tcx, ty::mk_nil(ccx.tcx));
|
|
|
|
}
|
|
|
|
ty::ty_uniq(_) {
|
|
|
|
ret ty::mk_imm_uniq(ccx.tcx, ty::mk_nil(ccx.tcx));
|
|
|
|
}
|
|
|
|
ty::ty_fn(_) {
|
|
|
|
ret ty::mk_tup(ccx.tcx,
|
|
|
|
[ty::mk_imm_box(ccx.tcx, ty::mk_nil(ccx.tcx)),
|
|
|
|
ty::mk_imm_box(ccx.tcx, ty::mk_nil(ccx.tcx))]);
|
|
|
|
}
|
|
|
|
ty::ty_res(_, sub, tps) {
|
|
|
|
let sub1 = ty::substitute_type_params(ccx.tcx, tps, sub);
|
|
|
|
ret ty::mk_tup(ccx.tcx,
|
|
|
|
[ty::mk_int(ccx.tcx), simplify_type(ccx, sub1)]);
|
|
|
|
}
|
|
|
|
_ { ret typ; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret ty::fold_ty(ccx.tcx, ty::fm_general(bind simplifier(ccx, _)), typ);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Computes the size of the data part of a non-dynamically-sized tag.
|
|
|
|
fn static_size_of_tag(cx: @crate_ctxt, sp: span, t: ty::t)
|
|
|
|
: type_has_static_size(cx, t) -> uint {
|
|
|
|
if cx.tag_sizes.contains_key(t) { ret cx.tag_sizes.get(t); }
|
|
|
|
alt ty::struct(cx.tcx, t) {
|
|
|
|
ty::ty_tag(tid, subtys) {
|
|
|
|
// Compute max(variant sizes).
|
|
|
|
|
|
|
|
let max_size = 0u;
|
|
|
|
let variants = ty::tag_variants(cx.tcx, tid);
|
|
|
|
for variant: ty::variant_info in *variants {
|
|
|
|
let tup_ty = simplify_type(cx, ty::mk_tup(cx.tcx, variant.args));
|
|
|
|
// Perform any type parameter substitutions.
|
|
|
|
|
|
|
|
tup_ty = ty::substitute_type_params(cx.tcx, subtys, tup_ty);
|
|
|
|
// Here we possibly do a recursive call.
|
|
|
|
|
|
|
|
// FIXME: Avoid this check. Since the parent has static
|
|
|
|
// size, any field must as well. There should be a way to
|
|
|
|
// express that with constrained types.
|
|
|
|
check (type_has_static_size(cx, tup_ty));
|
|
|
|
let this_size = llsize_of_real(cx, type_of(cx, sp, tup_ty));
|
|
|
|
if max_size < this_size { max_size = this_size; }
|
|
|
|
}
|
|
|
|
cx.tag_sizes.insert(t, max_size);
|
|
|
|
ret max_size;
|
|
|
|
}
|
|
|
|
_ {
|
|
|
|
cx.tcx.sess.span_fatal(sp, "non-tag passed to static_size_of_tag()");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn dynamic_size_of(cx: @block_ctxt, t: ty::t) -> result {
|
|
|
|
fn align_elements(cx: @block_ctxt, elts: [ty::t]) -> result {
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
|
|
|
|
let off = C_int(bcx_ccx(cx), 0);
|
|
|
|
let max_align = C_int(bcx_ccx(cx), 1);
|
|
|
|
let bcx = cx;
|
|
|
|
for e: ty::t in elts {
|
|
|
|
let elt_align = align_of(bcx, e);
|
|
|
|
bcx = elt_align.bcx;
|
|
|
|
let elt_size = size_of(bcx, e);
|
|
|
|
bcx = elt_size.bcx;
|
|
|
|
let aligned_off = align_to(bcx, off, elt_align.val);
|
|
|
|
off = Add(bcx, aligned_off, elt_size.val);
|
|
|
|
max_align = umax(bcx, max_align, elt_align.val);
|
|
|
|
}
|
|
|
|
off = align_to(bcx, off, max_align);
|
|
|
|
//off = alt mode {
|
|
|
|
// align_total. {
|
|
|
|
// align_to(bcx, off, max_align)
|
|
|
|
// }
|
|
|
|
// align_next(t) {
|
|
|
|
// let {bcx, val: align} = align_of(bcx, t);
|
|
|
|
// align_to(bcx, off, align)
|
|
|
|
// }
|
|
|
|
//};
|
|
|
|
ret rslt(bcx, off);
|
|
|
|
}
|
|
|
|
alt ty::struct(bcx_tcx(cx), t) {
|
|
|
|
ty::ty_param(p, _) {
|
|
|
|
let szptr = field_of_tydesc(cx, t, false, abi::tydesc_field_size);
|
|
|
|
ret rslt(szptr.bcx, Load(szptr.bcx, szptr.val));
|
|
|
|
}
|
|
|
|
ty::ty_rec(flds) {
|
|
|
|
let tys: [ty::t] = [];
|
|
|
|
for f: ty::field in flds { tys += [f.mt.ty]; }
|
|
|
|
ret align_elements(cx, tys);
|
|
|
|
}
|
|
|
|
ty::ty_tup(elts) {
|
|
|
|
let tys = [];
|
|
|
|
for tp in elts { tys += [tp]; }
|
|
|
|
ret align_elements(cx, tys);
|
|
|
|
}
|
|
|
|
ty::ty_tag(tid, tps) {
|
|
|
|
let bcx = cx;
|
|
|
|
let ccx = bcx_ccx(bcx);
|
|
|
|
// Compute max(variant sizes).
|
|
|
|
|
|
|
|
let max_size: ValueRef = alloca(bcx, ccx.int_type);
|
|
|
|
Store(bcx, C_int(ccx, 0), max_size);
|
|
|
|
let variants = ty::tag_variants(bcx_tcx(bcx), tid);
|
|
|
|
for variant: ty::variant_info in *variants {
|
|
|
|
// Perform type substitution on the raw argument types.
|
|
|
|
|
|
|
|
let raw_tys: [ty::t] = variant.args;
|
|
|
|
let tys: [ty::t] = [];
|
|
|
|
for raw_ty: ty::t in raw_tys {
|
|
|
|
let t = ty::substitute_type_params(bcx_tcx(cx), tps, raw_ty);
|
|
|
|
tys += [t];
|
|
|
|
}
|
|
|
|
let rslt = align_elements(bcx, tys);
|
|
|
|
bcx = rslt.bcx;
|
|
|
|
let this_size = rslt.val;
|
|
|
|
let old_max_size = Load(bcx, max_size);
|
|
|
|
Store(bcx, umax(bcx, this_size, old_max_size), max_size);
|
|
|
|
}
|
|
|
|
let max_size_val = Load(bcx, max_size);
|
|
|
|
let total_size =
|
|
|
|
if vec::len(*variants) != 1u {
|
|
|
|
Add(bcx, max_size_val, llsize_of(ccx, ccx.int_type))
|
|
|
|
} else { max_size_val };
|
|
|
|
ret rslt(bcx, total_size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn dynamic_align_of(cx: @block_ctxt, t: ty::t) -> result {
|
|
|
|
// FIXME: Typestate constraint that shows this alt is
|
|
|
|
// exhaustive
|
|
|
|
alt ty::struct(bcx_tcx(cx), t) {
|
|
|
|
ty::ty_param(p, _) {
|
|
|
|
let aptr = field_of_tydesc(cx, t, false, abi::tydesc_field_align);
|
|
|
|
ret rslt(aptr.bcx, Load(aptr.bcx, aptr.val));
|
|
|
|
}
|
|
|
|
ty::ty_rec(flds) {
|
|
|
|
let a = C_int(bcx_ccx(cx), 1);
|
|
|
|
let bcx = cx;
|
|
|
|
for f: ty::field in flds {
|
|
|
|
let align = align_of(bcx, f.mt.ty);
|
|
|
|
bcx = align.bcx;
|
|
|
|
a = umax(bcx, a, align.val);
|
|
|
|
}
|
|
|
|
ret rslt(bcx, a);
|
|
|
|
}
|
|
|
|
ty::ty_tag(_, _) {
|
|
|
|
ret rslt(cx, C_int(bcx_ccx(cx), 1)); // FIXME: stub
|
|
|
|
}
|
|
|
|
ty::ty_tup(elts) {
|
|
|
|
let a = C_int(bcx_ccx(cx), 1);
|
|
|
|
let bcx = cx;
|
|
|
|
for e in elts {
|
|
|
|
let align = align_of(bcx, e);
|
|
|
|
bcx = align.bcx;
|
|
|
|
a = umax(bcx, a, align.val);
|
|
|
|
}
|
|
|
|
ret rslt(bcx, a);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-05 10:44:59 -08:00
|
|
|
// Given a pointer p, returns a pointer sz(p) (i.e., inc'd by sz bytes).
|
|
|
|
// The type of the returned pointer is always i8*. If you care about the
|
|
|
|
// return type, use bump_ptr().
|
|
|
|
fn ptr_offs(bcx: @block_ctxt, base: ValueRef, sz: ValueRef) -> ValueRef {
|
|
|
|
let raw = PointerCast(bcx, base, T_ptr(T_i8()));
|
2012-01-05 12:05:22 -08:00
|
|
|
GEP(bcx, raw, [sz])
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
|
|
|
|
2011-08-01 15:08:16 -07:00
|
|
|
// Increment a pointer by a given amount and then cast it to be a pointer
|
|
|
|
// to a given type.
|
2011-09-12 11:27:30 +02:00
|
|
|
fn bump_ptr(bcx: @block_ctxt, t: ty::t, base: ValueRef, sz: ValueRef) ->
|
2011-08-19 15:16:48 -07:00
|
|
|
ValueRef {
|
2011-09-02 18:59:22 -07:00
|
|
|
let ccx = bcx_ccx(bcx);
|
2012-01-05 10:44:59 -08:00
|
|
|
let bumped = ptr_offs(bcx, base, sz);
|
2011-09-02 18:59:22 -07:00
|
|
|
if check type_has_static_size(ccx, t) {
|
|
|
|
let sp = bcx.sp;
|
|
|
|
let typ = T_ptr(type_of(ccx, sp, t));
|
|
|
|
PointerCast(bcx, bumped, typ)
|
2011-09-12 11:27:30 +02:00
|
|
|
} else { bumped }
|
2011-08-01 15:08:16 -07:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-09-26 13:21:47 +02:00
|
|
|
// GEP_tup_like is a pain to use if you always have to precede it with a
|
|
|
|
// check.
|
|
|
|
fn GEP_tup_like_1(cx: @block_ctxt, t: ty::t, base: ValueRef, ixs: [int])
|
|
|
|
-> result {
|
|
|
|
check type_is_tup_like(cx, t);
|
|
|
|
ret GEP_tup_like(cx, t, base, ixs);
|
|
|
|
}
|
|
|
|
|
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.
|
2012-01-05 10:44:59 -08:00
|
|
|
fn GEP_tup_like(bcx: @block_ctxt, t: ty::t, base: ValueRef, ixs: [int])
|
|
|
|
: type_is_tup_like(bcx, t) -> result {
|
2012-01-18 15:42:00 -08:00
|
|
|
|
2012-01-17 20:59:49 -08:00
|
|
|
fn compute_off(bcx: @block_ctxt,
|
|
|
|
off: ValueRef,
|
|
|
|
t: ty::t,
|
|
|
|
ixs: [int],
|
|
|
|
n: uint) -> (@block_ctxt, ValueRef, ty::t) {
|
|
|
|
if n == vec::len(ixs) {
|
|
|
|
ret (bcx, off, t);
|
2011-01-19 16:29:14 -08:00
|
|
|
}
|
2012-01-17 20:59:49 -08:00
|
|
|
|
|
|
|
let tcx = bcx_tcx(bcx);
|
|
|
|
let ix = ixs[n];
|
|
|
|
let bcx = bcx, off = off;
|
|
|
|
int::range(0, ix) {|i|
|
|
|
|
let comp_t = ty::get_element_type(tcx, t, i as uint);
|
|
|
|
let align = align_of(bcx, comp_t);
|
|
|
|
bcx = align.bcx;
|
|
|
|
off = align_to(bcx, off, align.val);
|
|
|
|
let sz = size_of(bcx, comp_t);
|
|
|
|
bcx = sz.bcx;
|
|
|
|
off = Add(bcx, off, sz.val);
|
2011-01-19 16:29:14 -08:00
|
|
|
}
|
|
|
|
|
2012-01-17 20:59:49 -08:00
|
|
|
let comp_t = ty::get_element_type(tcx, t, ix as uint);
|
|
|
|
let align = align_of(bcx, comp_t);
|
|
|
|
bcx = align.bcx;
|
|
|
|
off = align_to(bcx, off, align.val);
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2012-01-17 20:59:49 -08:00
|
|
|
be compute_off(bcx, off, comp_t, ixs, n+1u);
|
2011-01-19 16:29:14 -08:00
|
|
|
}
|
|
|
|
|
2012-01-17 20:59:49 -08:00
|
|
|
if !ty::type_has_dynamic_size(bcx_tcx(bcx), t) {
|
|
|
|
ret rslt(bcx, GEPi(bcx, base, ixs));
|
|
|
|
}
|
2011-06-30 11:28:38 -07:00
|
|
|
|
2012-01-17 20:59:49 -08:00
|
|
|
#debug["GEP_tup_like(t=%s,base=%s,ixs=%?)",
|
|
|
|
ty_to_str(bcx_tcx(bcx), t),
|
|
|
|
val_str(bcx_ccx(bcx).tn, base),
|
|
|
|
ixs];
|
2012-01-06 19:39:18 -08:00
|
|
|
|
2012-01-17 20:59:49 -08:00
|
|
|
// We require that ixs start with 0 and we expect the input to be a
|
|
|
|
// pointer to an instance of type t, so we can safely ignore ixs[0],
|
|
|
|
// basically.
|
|
|
|
assert ixs[0] == 0;
|
2012-01-18 15:42:00 -08:00
|
|
|
|
2012-01-17 20:59:49 -08:00
|
|
|
let (bcx, off, tar_t) = {
|
|
|
|
compute_off(bcx, C_int(bcx_ccx(bcx), 0), t, ixs, 1u)
|
|
|
|
};
|
|
|
|
ret rslt(bcx, bump_ptr(bcx, tar_t, base, off));
|
2011-01-19 16:29:14 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2012-01-19 14:24:03 -08:00
|
|
|
// Replacement for the LLVM 'GEP' instruction when field indexing into a enum.
|
2011-03-04 15:08:33 -08:00
|
|
|
// This function uses GEP_tup_like() above and automatically performs casts as
|
2012-01-19 14:34:23 -08:00
|
|
|
// appropriate. @llblobptr is the data part of a enum value; its actual type
|
|
|
|
// is meaningless, as it will be cast away.
|
2011-09-12 11:27:30 +02:00
|
|
|
fn GEP_tag(cx: @block_ctxt, llblobptr: ValueRef, tag_id: ast::def_id,
|
|
|
|
variant_id: ast::def_id, ty_substs: [ty::t],
|
2011-09-02 15:34:58 -07:00
|
|
|
ix: uint) : valid_variant_index(ix, cx, tag_id, variant_id) ->
|
|
|
|
result {
|
2011-07-27 14:19:39 +02:00
|
|
|
let variant = ty::tag_variant_with_id(bcx_tcx(cx), 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-07-27 14:19:39 +02:00
|
|
|
let arg_tys = variant.args;
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-08-19 15:16:48 -07:00
|
|
|
let true_arg_tys: [ty::t] = [];
|
2011-08-15 21:54:52 -07:00
|
|
|
for aty: ty::t in arg_tys {
|
2012-01-14 16:05:07 -08:00
|
|
|
// Would be nice to have a way of stating the invariant
|
|
|
|
// that ty_substs is valid for aty
|
2011-07-27 14:19:39 +02:00
|
|
|
let arg_ty = ty::substitute_type_params(bcx_tcx(cx), ty_substs, aty);
|
2011-08-19 15:16:48 -07:00
|
|
|
true_arg_tys += [arg_ty];
|
2011-03-04 15:08:33 -08:00
|
|
|
}
|
2011-09-01 17:25:06 -07:00
|
|
|
|
|
|
|
// We know that ix < len(variant.args) -- so
|
|
|
|
// it's safe to do this. (Would be nice to have
|
|
|
|
// typestate guarantee that a dynamic bounds check
|
|
|
|
// error can't happen here, but that's in the future.)
|
|
|
|
let elem_ty = true_arg_tys[ix];
|
|
|
|
|
2011-08-15 12:08:05 +02:00
|
|
|
let tup_ty = ty::mk_tup(bcx_tcx(cx), 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-07-27 14:19:39 +02:00
|
|
|
let llunionptr: ValueRef;
|
2011-09-02 18:59:22 -07:00
|
|
|
let sp = cx.sp;
|
|
|
|
let ccx = bcx_ccx(cx);
|
|
|
|
if check type_has_static_size(ccx, tup_ty) {
|
|
|
|
let llty = type_of(ccx, sp, tup_ty);
|
2011-08-30 09:59:30 +02:00
|
|
|
llunionptr = TruncOrBitCast(cx, llblobptr, T_ptr(llty));
|
2011-09-12 11:27:30 +02:00
|
|
|
} else { llunionptr = llblobptr; }
|
2011-03-04 15:08:33 -08:00
|
|
|
|
2011-09-02 18:59:22 -07:00
|
|
|
// Do the GEP_tup_like().
|
2011-09-17 10:18:30 -07:00
|
|
|
// Silly check -- postcondition on mk_tup?
|
|
|
|
check type_is_tup_like(cx, tup_ty);
|
2011-09-01 16:31:18 -07:00
|
|
|
let rs = GEP_tup_like(cx, tup_ty, llunionptr, [0, ix as int]);
|
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-09-02 18:59:22 -07:00
|
|
|
let rs_ccx = bcx_ccx(rs.bcx);
|
2011-09-12 11:27:30 +02:00
|
|
|
let val =
|
|
|
|
if check type_has_static_size(rs_ccx, elem_ty) {
|
|
|
|
let llelemty = type_of(rs_ccx, sp, elem_ty);
|
|
|
|
PointerCast(rs.bcx, rs.val, T_ptr(llelemty))
|
|
|
|
} else { rs.val };
|
2011-09-02 18:59:22 -07:00
|
|
|
|
2011-06-24 19:04:08 +02:00
|
|
|
ret rslt(rs.bcx, val);
|
2011-03-04 15:08:33 -08:00
|
|
|
}
|
|
|
|
|
2011-07-05 22:55:41 -07:00
|
|
|
// trans_shared_malloc: expects a type indicating which pointer type we want
|
|
|
|
// and a size indicating how much space we want malloc'd.
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trans_shared_malloc(cx: @block_ctxt, llptr_ty: TypeRef, llsize: ValueRef)
|
2011-07-27 14:19:39 +02:00
|
|
|
-> result {
|
2011-07-05 22:55:41 -07:00
|
|
|
// FIXME: need a table to collect tydesc globals.
|
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
let tydesc = C_null(T_ptr(bcx_ccx(cx).tydesc_type));
|
|
|
|
let rval =
|
2011-08-30 09:59:30 +02:00
|
|
|
Call(cx, bcx_ccx(cx).upcalls.shared_malloc,
|
2011-10-20 11:42:40 +02:00
|
|
|
[llsize, tydesc]);
|
2011-08-30 09:59:30 +02:00
|
|
|
ret rslt(cx, PointerCast(cx, rval, llptr_ty));
|
2011-07-05 22:55:41 -07:00
|
|
|
}
|
2011-06-03 17:16:28 -07:00
|
|
|
|
2011-07-28 15:44:51 -07:00
|
|
|
// trans_malloc_boxed_raw: 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-09-12 11:27:30 +02:00
|
|
|
fn trans_malloc_boxed_raw(cx: @block_ctxt, t: ty::t) -> result {
|
2011-09-20 13:38:35 -07:00
|
|
|
let bcx = cx;
|
|
|
|
|
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
|
|
|
|
2011-07-27 14:48:34 +02:00
|
|
|
// The mk_int here is the space being
|
|
|
|
// reserved for the refcount.
|
2011-09-20 13:38:35 -07:00
|
|
|
let boxed_body = ty::mk_tup(bcx_tcx(bcx), [ty::mk_int(bcx_tcx(cx)), t]);
|
|
|
|
let box_ptr = ty::mk_imm_box(bcx_tcx(bcx), t);
|
|
|
|
let r = size_of(cx, boxed_body);
|
|
|
|
let llsz = r.val; bcx = r.bcx;
|
2011-07-28 15:44:51 -07:00
|
|
|
|
2011-06-03 17:16:28 -07:00
|
|
|
// Grab the TypeRef type of box_ptr, because that's what trans_raw_malloc
|
|
|
|
// wants.
|
2011-09-02 18:59:22 -07:00
|
|
|
// FIXME: Could avoid this check with a postcondition on mk_imm_box?
|
|
|
|
// (requires Issue #586)
|
2011-09-20 13:48:22 -07:00
|
|
|
let ccx = bcx_ccx(bcx);
|
|
|
|
let sp = bcx.sp;
|
2011-09-12 11:27:30 +02:00
|
|
|
check (type_has_static_size(ccx, box_ptr));
|
2011-09-02 18:59:22 -07:00
|
|
|
let llty = type_of(ccx, sp, box_ptr);
|
2011-09-20 13:38:35 -07:00
|
|
|
|
2011-09-20 13:48:22 -07:00
|
|
|
let ti = none;
|
2012-01-13 10:58:31 +01:00
|
|
|
let tydesc_result = get_tydesc(bcx, t, true, ti);
|
2011-09-20 13:48:22 -07:00
|
|
|
let lltydesc = tydesc_result.result.val; bcx = tydesc_result.result.bcx;
|
|
|
|
|
|
|
|
let rval = Call(cx, ccx.upcalls.malloc,
|
2011-10-20 11:42:40 +02:00
|
|
|
[llsz, lltydesc]);
|
2011-09-20 13:38:35 -07:00
|
|
|
ret rslt(cx, PointerCast(cx, rval, llty));
|
2010-12-02 17:43:05 -08:00
|
|
|
}
|
|
|
|
|
2011-07-28 15:44:51 -07:00
|
|
|
// trans_malloc_boxed: usefully wraps trans_malloc_box_raw; allocates a box,
|
|
|
|
// initializes the reference count to 1, and pulls out the body and rc
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trans_malloc_boxed(cx: @block_ctxt, t: ty::t) ->
|
2011-08-19 15:16:48 -07:00
|
|
|
{bcx: @block_ctxt, box: ValueRef, body: ValueRef} {
|
2011-07-28 15:44:51 -07:00
|
|
|
let res = trans_malloc_boxed_raw(cx, t);
|
|
|
|
let box = res.val;
|
2011-08-19 15:16:48 -07:00
|
|
|
let rc = GEPi(res.bcx, box, [0, abi::box_rc_field_refcnt]);
|
2011-10-14 16:45:25 -07:00
|
|
|
Store(res.bcx, C_int(bcx_ccx(cx), 1), rc);
|
2011-08-19 15:16:48 -07:00
|
|
|
let body = GEPi(res.bcx, box, [0, abi::box_rc_field_body]);
|
2011-08-02 16:24:38 -07:00
|
|
|
ret {bcx: res.bcx, box: res.val, body: body};
|
2011-07-28 15:44:51 -07:00
|
|
|
}
|
2010-12-02 17:43:05 -08:00
|
|
|
|
2010-12-20 10:23:37 -08:00
|
|
|
// Type descriptor and type glue stuff
|
|
|
|
|
2012-01-19 10:37:40 -08:00
|
|
|
// 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.
|
|
|
|
fn field_of_tydesc(cx: @block_ctxt, t: ty::t, escapes: bool, field: int) ->
|
|
|
|
result {
|
|
|
|
let ti = none::<@tydesc_info>;
|
|
|
|
let tydesc = get_tydesc(cx, t, escapes, ti).result;
|
|
|
|
ret rslt(tydesc.bcx,
|
|
|
|
GEPi(tydesc.bcx, tydesc.val, [0, field]));
|
|
|
|
}
|
|
|
|
|
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-09-12 11:27:30 +02:00
|
|
|
fn linearize_ty_params(cx: @block_ctxt, t: ty::t) ->
|
2011-08-04 16:20:09 -07:00
|
|
|
{params: [uint], descs: [ValueRef]} {
|
2011-08-19 15:16:48 -07:00
|
|
|
let param_vals: [ValueRef] = [];
|
|
|
|
let param_defs: [uint] = [];
|
2011-07-27 14:19:39 +02:00
|
|
|
type rr =
|
2011-08-04 16:20:09 -07:00
|
|
|
{cx: @block_ctxt, mutable vals: [ValueRef], mutable defs: [uint]};
|
2011-07-27 14:19:39 +02:00
|
|
|
|
|
|
|
fn linearizer(r: @rr, t: ty::t) {
|
|
|
|
alt ty::struct(bcx_tcx(r.cx), t) {
|
2011-08-19 15:16:48 -07:00
|
|
|
ty::ty_param(pid, _) {
|
2011-07-27 14:19:39 +02:00
|
|
|
let seen: bool = false;
|
2011-08-15 21:54:52 -07:00
|
|
|
for d: uint in r.defs { if d == pid { seen = true; } }
|
2012-01-02 16:50:51 +01:00
|
|
|
if !seen {
|
|
|
|
r.vals += [r.cx.fcx.lltyparams[pid].desc];
|
|
|
|
r.defs += [pid];
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ { }
|
2011-01-27 17:07:52 -08:00
|
|
|
}
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
let x = @{cx: cx, mutable vals: param_vals, mutable defs: param_defs};
|
|
|
|
let f = bind linearizer(x, _);
|
2011-07-26 13:02:26 -07:00
|
|
|
ty::walk_ty(bcx_tcx(cx), f, t);
|
2011-07-27 14:19:39 +02:00
|
|
|
ret {params: x.defs, descs: x.vals};
|
2011-01-27 17:07:52 -08:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trans_stack_local_derived_tydesc(cx: @block_ctxt, llsz: ValueRef,
|
2011-07-27 14:19:39 +02:00
|
|
|
llalign: ValueRef, llroottydesc: ValueRef,
|
2012-01-13 10:58:31 +01:00
|
|
|
llfirstparam: ValueRef, n_params: uint)
|
|
|
|
-> ValueRef {
|
2011-07-27 14:19:39 +02:00
|
|
|
let llmyroottydesc = alloca(cx, bcx_ccx(cx).tydesc_type);
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-08-24 18:36:51 -07:00
|
|
|
// By convention, desc 0 is the root descriptor.
|
2011-11-03 10:57:54 +01:00
|
|
|
let llroottydesc = Load(cx, llroottydesc);
|
2011-08-30 09:59:30 +02:00
|
|
|
Store(cx, llroottydesc, llmyroottydesc);
|
2011-05-08 16:24:24 -07:00
|
|
|
|
2011-08-24 18:36:51 -07:00
|
|
|
// Store a pointer to the rest of the descriptors.
|
2011-10-14 16:45:25 -07:00
|
|
|
let ccx = bcx_ccx(cx);
|
2011-08-04 11:25:09 -07:00
|
|
|
store_inbounds(cx, llfirstparam, llmyroottydesc,
|
2011-10-26 17:09:07 -07:00
|
|
|
[0, abi::tydesc_field_first_param]);
|
2011-10-14 16:45:25 -07:00
|
|
|
store_inbounds(cx, C_uint(ccx, n_params), llmyroottydesc,
|
2011-10-26 17:09:07 -07:00
|
|
|
[0, abi::tydesc_field_n_params]);
|
2011-08-04 11:25:09 -07:00
|
|
|
store_inbounds(cx, llsz, llmyroottydesc,
|
2011-10-26 17:09:07 -07:00
|
|
|
[0, abi::tydesc_field_size]);
|
2011-08-04 11:25:09 -07:00
|
|
|
store_inbounds(cx, llalign, llmyroottydesc,
|
2011-10-26 17:09:07 -07:00
|
|
|
[0, abi::tydesc_field_align]);
|
2012-01-13 10:58:31 +01:00
|
|
|
// FIXME legacy field, can be dropped
|
|
|
|
store_inbounds(cx, C_uint(ccx, 0u), llmyroottydesc,
|
2011-10-26 17:09:07 -07:00
|
|
|
[0, abi::tydesc_field_obj_params]);
|
2011-05-11 11:56:49 -07:00
|
|
|
ret llmyroottydesc;
|
2011-05-02 15:28:22 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn get_derived_tydesc(cx: @block_ctxt, t: ty::t, escapes: bool,
|
2011-09-12 12:39:38 +02:00
|
|
|
&static_ti: option::t<@tydesc_info>) -> result {
|
2011-07-27 14:19:39 +02:00
|
|
|
alt cx.fcx.derived_tydescs.find(t) {
|
|
|
|
some(info) {
|
|
|
|
// If the tydesc escapes in this context, the cached derived
|
|
|
|
// tydesc also has to be one that was marked as escaping.
|
2012-01-13 10:58:31 +01:00
|
|
|
if !(escapes && !info.escapes) {
|
2011-08-25 14:20:21 -07:00
|
|
|
ret rslt(cx, info.lltydesc);
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
none {/* fall through */ }
|
2011-05-11 11:56:49 -07:00
|
|
|
}
|
2011-08-25 14:20:21 -07:00
|
|
|
|
2011-07-26 13:02:26 -07:00
|
|
|
bcx_ccx(cx).stats.n_derived_tydescs += 1u;
|
2011-07-27 14:19:39 +02:00
|
|
|
let bcx = new_raw_block_ctxt(cx.fcx, cx.fcx.llderivedtydescs);
|
|
|
|
let tys = linearize_ty_params(bcx, t);
|
2012-01-13 10:58:31 +01:00
|
|
|
let root_ti = get_static_tydesc(bcx, t, tys.params);
|
2011-08-13 00:09:25 -07:00
|
|
|
static_ti = some::<@tydesc_info>(root_ti);
|
2011-05-12 15:42:12 -07:00
|
|
|
lazily_emit_all_tydesc_glue(cx, static_ti);
|
2011-07-27 14:19:39 +02:00
|
|
|
let root = root_ti.tydesc;
|
|
|
|
let sz = size_of(bcx, t);
|
2011-05-06 10:38:38 -07:00
|
|
|
bcx = sz.bcx;
|
2011-07-27 14:19:39 +02:00
|
|
|
let align = align_of(bcx, t);
|
2011-05-06 10:38:38 -07:00
|
|
|
bcx = align.bcx;
|
2011-08-24 18:36:51 -07:00
|
|
|
|
|
|
|
// Store the captured type descriptors in an alloca if the caller isn't
|
|
|
|
// promising to do so itself.
|
|
|
|
let n_params = ty::count_ty_params(bcx_tcx(bcx), t);
|
|
|
|
|
2011-12-13 16:25:51 -08:00
|
|
|
assert (n_params == vec::len::<uint>(tys.params));
|
|
|
|
assert (n_params == vec::len::<ValueRef>(tys.descs));
|
2011-08-24 18:36:51 -07:00
|
|
|
|
|
|
|
let llparamtydescs =
|
|
|
|
alloca(bcx, T_array(T_ptr(bcx_ccx(bcx).tydesc_type), n_params + 1u));
|
|
|
|
let i = 0;
|
|
|
|
|
|
|
|
// If the type descriptor escapes, we need to add in the root as
|
|
|
|
// the first parameter, because upcall_get_type_desc() expects it.
|
2011-07-27 14:19:39 +02:00
|
|
|
if escapes {
|
2011-08-30 09:59:30 +02:00
|
|
|
Store(bcx, root, GEPi(bcx, llparamtydescs, [0, 0]));
|
2011-05-06 11:35:04 -07:00
|
|
|
i += 1;
|
2011-08-24 18:36:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
for td: ValueRef in tys.descs {
|
2011-08-30 09:59:30 +02:00
|
|
|
Store(bcx, td, GEPi(bcx, llparamtydescs, [0, i]));
|
2011-08-24 18:36:51 -07:00
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
let llfirstparam =
|
2011-08-30 09:59:30 +02:00
|
|
|
PointerCast(bcx, llparamtydescs,
|
2011-09-02 15:34:58 -07:00
|
|
|
T_ptr(T_ptr(bcx_ccx(bcx).tydesc_type)));
|
2011-08-24 18:36:51 -07:00
|
|
|
|
|
|
|
let v;
|
|
|
|
if escapes {
|
2011-10-14 16:45:25 -07:00
|
|
|
let ccx = bcx_ccx(bcx);
|
2011-07-27 14:19:39 +02:00
|
|
|
let td_val =
|
2011-10-14 16:45:25 -07:00
|
|
|
Call(bcx, ccx.upcalls.get_type_desc,
|
2011-10-20 11:42:40 +02:00
|
|
|
[C_null(T_ptr(T_nil())), sz.val,
|
2011-10-14 16:45:25 -07:00
|
|
|
align.val, C_uint(ccx, 1u + n_params), llfirstparam,
|
2012-01-13 10:58:31 +01:00
|
|
|
C_uint(ccx, 0u)]);
|
2011-05-11 11:56:49 -07:00
|
|
|
v = td_val;
|
2011-05-06 10:38:38 -07:00
|
|
|
} else {
|
2012-01-13 10:58:31 +01:00
|
|
|
v = trans_stack_local_derived_tydesc(bcx, sz.val, align.val, root,
|
|
|
|
llfirstparam, n_params);
|
2011-05-06 10:38:38 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
bcx.fcx.derived_tydescs.insert(t, {lltydesc: v, escapes: escapes});
|
2011-06-24 19:04:08 +02:00
|
|
|
ret rslt(cx, v);
|
2011-05-06 10:38:38 -07:00
|
|
|
}
|
|
|
|
|
2011-08-19 15:16:48 -07:00
|
|
|
type get_tydesc_result = {kind: tydesc_kind, result: result};
|
2011-08-17 19:11:01 -07:00
|
|
|
|
2011-12-19 13:52:58 +01:00
|
|
|
fn get_tydesc(cx: @block_ctxt, t: ty::t, escapes: bool,
|
2012-01-13 10:58:31 +01:00
|
|
|
&static_ti: option::t<@tydesc_info>)
|
2011-09-12 12:39:38 +02:00
|
|
|
-> get_tydesc_result {
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-29 17:29:24 -07:00
|
|
|
// Is the supplied type a type param? If so, return the passed-in tydesc.
|
2011-07-27 14:19:39 +02:00
|
|
|
alt ty::type_param(bcx_tcx(cx), t) {
|
2011-08-10 15:57:03 -07:00
|
|
|
some(id) {
|
2012-01-02 16:50:51 +01:00
|
|
|
if id < vec::len(cx.fcx.lltyparams) {
|
|
|
|
ret {kind: tk_param,
|
|
|
|
result: rslt(cx, cx.fcx.lltyparams[id].desc)};
|
2011-08-19 15:16:48 -07:00
|
|
|
} else {
|
2011-09-02 15:34:58 -07:00
|
|
|
bcx_tcx(cx).sess.span_bug(cx.sp,
|
|
|
|
"Unbound typaram in get_tydesc: " +
|
2011-12-19 13:52:58 +01:00
|
|
|
"t = " +
|
|
|
|
ty_to_str(bcx_tcx(cx), t) +
|
2011-09-02 15:34:58 -07:00
|
|
|
" ty_param = " +
|
2011-12-13 16:25:51 -08:00
|
|
|
uint::str(id));
|
2011-08-10 15:57:03 -07:00
|
|
|
}
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
none {/* fall through */ }
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
2011-01-28 15:28:20 -08:00
|
|
|
|
2011-06-29 17:29:24 -07:00
|
|
|
// Does it contain a type param? If so, generate a derived tydesc.
|
2011-07-27 14:19:39 +02:00
|
|
|
if ty::type_contains_params(bcx_tcx(cx), t) {
|
2011-08-19 15:16:48 -07:00
|
|
|
ret {kind: tk_derived,
|
2012-01-13 10:58:31 +01:00
|
|
|
result: get_derived_tydesc(cx, t, escapes, static_ti)};
|
2010-12-20 15:23:24 -08:00
|
|
|
}
|
2011-06-29 17:29:24 -07:00
|
|
|
// Otherwise, generate a tydesc if necessary, and return it.
|
2012-01-13 10:58:31 +01:00
|
|
|
let info = get_static_tydesc(cx, t, []);
|
|
|
|
static_ti = some(info);
|
2011-08-19 15:16:48 -07:00
|
|
|
ret {kind: tk_static, result: rslt(cx, info.tydesc)};
|
2011-04-26 17:19:44 -07:00
|
|
|
}
|
|
|
|
|
2012-01-13 10:58:31 +01:00
|
|
|
fn get_static_tydesc(cx: @block_ctxt, t: ty::t, ty_params: [uint])
|
|
|
|
-> @tydesc_info {
|
2011-07-27 14:19:39 +02:00
|
|
|
alt bcx_ccx(cx).tydescs.find(t) {
|
|
|
|
some(info) { ret info; }
|
2012-01-18 22:37:22 -08:00
|
|
|
none {
|
2011-07-27 14:19:39 +02:00
|
|
|
bcx_ccx(cx).stats.n_static_tydescs += 1u;
|
2012-01-13 10:58:31 +01:00
|
|
|
let info = declare_tydesc(cx.fcx.lcx, cx.sp, t, ty_params);
|
2011-07-27 14:19:39 +02:00
|
|
|
bcx_ccx(cx).tydescs.insert(t, info);
|
|
|
|
ret info;
|
|
|
|
}
|
2010-12-20 15:23:24 -08:00
|
|
|
}
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
fn set_no_inline(f: ValueRef) {
|
2011-06-15 11:19:50 -07:00
|
|
|
llvm::LLVMAddFunctionAttr(f,
|
|
|
|
lib::llvm::LLVMNoInlineAttribute as
|
2011-09-30 18:20:28 -07:00
|
|
|
lib::llvm::llvm::Attribute,
|
2012-01-18 19:29:37 +08:00
|
|
|
0u as c_uint);
|
2011-05-20 14:57:52 -07:00
|
|
|
}
|
|
|
|
|
2011-07-06 17:02:56 -07:00
|
|
|
// Tell LLVM to emit the information necessary to unwind the stack for the
|
|
|
|
// function f.
|
2011-07-27 14:19:39 +02:00
|
|
|
fn set_uwtable(f: ValueRef) {
|
2011-06-15 11:19:50 -07:00
|
|
|
llvm::LLVMAddFunctionAttr(f,
|
|
|
|
lib::llvm::LLVMUWTableAttribute as
|
2011-09-30 18:20:28 -07:00
|
|
|
lib::llvm::llvm::Attribute,
|
2012-01-18 19:29:37 +08:00
|
|
|
0u as c_uint);
|
2011-05-24 13:47:27 -04:00
|
|
|
}
|
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
fn set_always_inline(f: ValueRef) {
|
2011-06-15 11:19:50 -07:00
|
|
|
llvm::LLVMAddFunctionAttr(f,
|
|
|
|
lib::llvm::LLVMAlwaysInlineAttribute as
|
2011-09-30 18:20:28 -07:00
|
|
|
lib::llvm::llvm::Attribute,
|
2012-01-18 19:29:37 +08:00
|
|
|
0u as c_uint);
|
2011-09-30 18:20:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn set_custom_stack_growth_fn(f: ValueRef) {
|
|
|
|
// TODO: Remove this hack to work around the lack of u64 in the FFI.
|
2012-01-18 19:29:37 +08:00
|
|
|
llvm::LLVMAddFunctionAttr(f, 0 as lib::llvm::llvm::Attribute,
|
|
|
|
1u as c_uint);
|
2011-05-20 14:57:52 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn set_glue_inlining(cx: @local_ctxt, f: ValueRef, t: ty::t) {
|
2011-07-27 14:19:39 +02:00
|
|
|
if ty::type_is_structural(cx.ccx.tcx, t) {
|
2011-05-20 14:57:52 -07:00
|
|
|
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.
|
2012-01-13 10:58:31 +01:00
|
|
|
fn declare_tydesc(cx: @local_ctxt, sp: span, t: ty::t, ty_params: [uint])
|
|
|
|
-> @tydesc_info {
|
2011-12-22 17:53:53 -08:00
|
|
|
log(debug, "+++ declare_tydesc " + ty_to_str(cx.ccx.tcx, t));
|
2011-07-27 14:19:39 +02:00
|
|
|
let ccx = cx.ccx;
|
|
|
|
let llsize;
|
|
|
|
let llalign;
|
2011-09-02 18:59:22 -07:00
|
|
|
if check type_has_static_size(ccx, t) {
|
2011-07-27 14:19:39 +02:00
|
|
|
let llty = type_of(ccx, sp, t);
|
2011-10-14 16:45:25 -07:00
|
|
|
llsize = llsize_of(ccx, llty);
|
|
|
|
llalign = llalign_of(ccx, llty);
|
2011-03-02 16:23:14 -08:00
|
|
|
} 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-10-14 16:45:25 -07:00
|
|
|
llsize = C_int(ccx, 0);
|
|
|
|
llalign = C_int(ccx, 0);
|
2011-03-02 16:23:14 -08:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
let name;
|
2012-01-12 17:59:49 +01:00
|
|
|
if cx.ccx.sess.opts.debuginfo {
|
2011-09-02 15:34:58 -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-09-02 15:34:58 -07:00
|
|
|
} else { name = mangle_internal_name_by_seq(cx.ccx, "tydesc"); }
|
|
|
|
let gvar =
|
|
|
|
str::as_buf(name,
|
|
|
|
{|buf|
|
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, ccx.tydesc_type, buf)
|
|
|
|
});
|
2011-07-27 14:19:39 +02:00
|
|
|
let info =
|
|
|
|
@{ty: t,
|
|
|
|
tydesc: gvar,
|
|
|
|
size: llsize,
|
|
|
|
align: llalign,
|
2011-08-19 10:24:13 +02:00
|
|
|
mutable take_glue: none::<ValueRef>,
|
2011-08-13 00:09:25 -07:00
|
|
|
mutable drop_glue: none::<ValueRef>,
|
|
|
|
mutable free_glue: none::<ValueRef>,
|
|
|
|
mutable cmp_glue: none::<ValueRef>,
|
2012-01-13 10:58:31 +01:00
|
|
|
ty_params: ty_params};
|
2011-12-22 17:53:53 -08:00
|
|
|
log(debug, "--- 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
|
|
|
}
|
|
|
|
|
2012-01-11 09:58:05 -08:00
|
|
|
type glue_helper = fn@(@block_ctxt, ValueRef, ty::t);
|
2011-04-18 10:56:52 -07:00
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn declare_generic_glue(cx: @local_ctxt, t: ty::t, llfnty: TypeRef, name: str)
|
|
|
|
-> ValueRef {
|
2011-08-26 21:34:56 -07:00
|
|
|
let name = name;
|
2011-07-27 14:19:39 +02:00
|
|
|
let fn_nm;
|
2012-01-12 17:59:49 +01:00
|
|
|
if cx.ccx.sess.opts.debuginfo {
|
2011-09-02 15:34:58 -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-09-02 15:34:58 -07:00
|
|
|
} else { fn_nm = mangle_internal_name_by_seq(cx.ccx, "glue_" + name); }
|
2011-08-26 21:34:56 -07:00
|
|
|
let 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-09-15 20:47:38 -07:00
|
|
|
// FIXME: was this causing the leak?
|
2011-09-12 11:27:30 +02:00
|
|
|
fn make_generic_glue_inner(cx: @local_ctxt, sp: span, t: ty::t,
|
|
|
|
llfn: ValueRef, helper: glue_helper,
|
|
|
|
ty_params: [uint]) -> ValueRef {
|
2011-07-27 14:19:39 +02:00
|
|
|
let 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-09-02 18:59:22 -07:00
|
|
|
let ccx = cx.ccx;
|
2011-09-12 11:27:30 +02:00
|
|
|
let llty =
|
|
|
|
if check type_has_static_size(ccx, t) {
|
|
|
|
T_ptr(type_of(ccx, sp, t))
|
|
|
|
} else { T_ptr(T_i8()) };
|
2011-09-02 18:59:22 -07:00
|
|
|
|
2011-12-13 16:25:51 -08:00
|
|
|
let ty_param_count = vec::len::<uint>(ty_params);
|
2012-01-18 19:29:37 +08:00
|
|
|
let lltyparams = llvm::LLVMGetParam(llfn, 2u as c_uint);
|
2011-09-23 11:01:09 +02:00
|
|
|
let load_env_bcx = new_raw_block_ctxt(fcx, fcx.llloadenv);
|
2011-08-19 15:16:48 -07:00
|
|
|
let lltydescs = [mutable];
|
2011-07-27 14:19:39 +02:00
|
|
|
let p = 0u;
|
|
|
|
while p < ty_param_count {
|
2011-10-25 22:23:28 -07:00
|
|
|
let llparam = GEPi(load_env_bcx, lltyparams, [p as int]);
|
2011-09-23 11:01:09 +02:00
|
|
|
llparam = Load(load_env_bcx, llparam);
|
2011-12-13 16:25:51 -08:00
|
|
|
vec::grow_set(lltydescs, ty_params[p], 0 as ValueRef, llparam);
|
2011-04-19 11:25:40 -07:00
|
|
|
p += 1u;
|
|
|
|
}
|
2011-07-07 18:30:35 -07:00
|
|
|
|
2012-01-02 16:50:51 +01:00
|
|
|
fcx.lltyparams = vec::map_mut(lltydescs, {|d| {desc: d, dicts: none}});
|
2011-07-07 18:30:35 -07:00
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
let bcx = new_top_block_ctxt(fcx);
|
|
|
|
let lltop = bcx.llbb;
|
2012-01-18 19:29:37 +08:00
|
|
|
let llrawptr0 = llvm::LLVMGetParam(llfn, 3u as c_uint);
|
2011-08-30 09:59:30 +02:00
|
|
|
let llval0 = BitCast(bcx, llrawptr0, llty);
|
2011-12-12 09:39:41 -08:00
|
|
|
helper(bcx, llval0, t);
|
2011-05-11 11:56:49 -07:00
|
|
|
finish_fn(fcx, lltop);
|
2010-12-10 15:02:23 -08:00
|
|
|
ret llfn;
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn make_generic_glue(cx: @local_ctxt, sp: span, t: ty::t, llfn: ValueRef,
|
|
|
|
helper: glue_helper, ty_params: [uint], name: str) ->
|
2011-09-02 15:34:58 -07:00
|
|
|
ValueRef {
|
2012-01-12 17:59:49 +01:00
|
|
|
if !cx.ccx.sess.opts.stats {
|
2011-07-19 11:56:46 -07:00
|
|
|
ret make_generic_glue_inner(cx, sp, t, llfn, helper, ty_params);
|
|
|
|
}
|
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
let start = time::get_time();
|
|
|
|
let llval = make_generic_glue_inner(cx, sp, t, llfn, helper, ty_params);
|
|
|
|
let end = time::get_time();
|
2011-09-02 15:34:58 -07:00
|
|
|
log_fn_time(cx.ccx, "glue " + name + " " + ty_to_short_str(cx.ccx.tcx, t),
|
2011-07-19 11:56:46 -07:00
|
|
|
start, end);
|
|
|
|
ret llval;
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn emit_tydescs(ccx: @crate_ctxt) {
|
2011-10-21 12:21:27 +02:00
|
|
|
ccx.tydescs.items {|key, val|
|
2011-10-14 16:45:25 -07:00
|
|
|
let glue_fn_ty = T_ptr(T_glue_fn(ccx));
|
|
|
|
let cmp_fn_ty = T_ptr(T_cmp_glue_fn(ccx));
|
2011-10-21 12:21:27 +02:00
|
|
|
let ti = val;
|
2011-08-19 10:24:13 +02:00
|
|
|
let take_glue =
|
2011-09-20 17:29:09 +02:00
|
|
|
alt ti.take_glue {
|
2012-01-18 22:37:22 -08:00
|
|
|
none { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
|
2011-07-27 14:19:39 +02:00
|
|
|
some(v) { ccx.stats.n_real_glues += 1u; v }
|
2011-06-15 11:19:50 -07:00
|
|
|
};
|
2011-07-27 14:19:39 +02:00
|
|
|
let drop_glue =
|
2011-09-20 17:29:09 +02:00
|
|
|
alt ti.drop_glue {
|
2012-01-18 22:37:22 -08:00
|
|
|
none { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
|
2011-07-27 14:19:39 +02:00
|
|
|
some(v) { ccx.stats.n_real_glues += 1u; v }
|
2011-06-15 11:19:50 -07:00
|
|
|
};
|
2011-07-27 14:19:39 +02:00
|
|
|
let free_glue =
|
2011-09-20 17:29:09 +02:00
|
|
|
alt ti.free_glue {
|
2012-01-18 22:37:22 -08:00
|
|
|
none { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
|
2011-07-27 14:19:39 +02:00
|
|
|
some(v) { ccx.stats.n_real_glues += 1u; v }
|
2011-06-15 11:19:50 -07:00
|
|
|
};
|
2011-07-27 14:19:39 +02:00
|
|
|
let cmp_glue =
|
2011-09-20 17:29:09 +02:00
|
|
|
alt ti.cmp_glue {
|
2012-01-18 22:37:22 -08:00
|
|
|
none { ccx.stats.n_null_glues += 1u; C_null(cmp_fn_ty) }
|
2011-07-27 14:19:39 +02:00
|
|
|
some(v) { ccx.stats.n_real_glues += 1u; v }
|
2011-06-15 11:19:50 -07:00
|
|
|
};
|
2011-08-04 11:25:09 -07:00
|
|
|
|
2012-01-13 10:58:31 +01:00
|
|
|
let shape = shape::shape_of(ccx, key, ti.ty_params);
|
2011-08-04 11:25:09 -07:00
|
|
|
let shape_tables =
|
|
|
|
llvm::LLVMConstPointerCast(ccx.shape_cx.llshapetables,
|
|
|
|
T_ptr(T_i8()));
|
|
|
|
|
|
|
|
let tydesc =
|
2011-07-14 15:19:17 -04:00
|
|
|
C_named_struct(ccx.tydesc_type,
|
2011-08-19 15:16:48 -07:00
|
|
|
[C_null(T_ptr(T_ptr(ccx.tydesc_type))),
|
|
|
|
ti.size, // size
|
|
|
|
ti.align, // align
|
2011-08-19 10:24:13 +02:00
|
|
|
take_glue, // take_glue
|
2011-08-19 15:16:48 -07:00
|
|
|
drop_glue, // drop_glue
|
|
|
|
free_glue, // free_glue
|
2011-08-24 17:05:53 +02:00
|
|
|
C_null(T_ptr(T_i8())), // unused
|
2011-08-19 15:16:48 -07:00
|
|
|
C_null(glue_fn_ty), // sever_glue
|
|
|
|
C_null(glue_fn_ty), // mark_glue
|
2011-09-22 22:15:25 -07:00
|
|
|
C_null(glue_fn_ty), // unused
|
2011-08-19 15:16:48 -07:00
|
|
|
cmp_glue, // cmp_glue
|
|
|
|
C_shape(ccx, shape), // shape
|
|
|
|
shape_tables, // shape_tables
|
2011-10-14 16:45:25 -07:00
|
|
|
C_int(ccx, 0), // n_params
|
|
|
|
C_int(ccx, 0)]); // n_obj_params
|
2011-07-27 14:19:39 +02:00
|
|
|
|
|
|
|
let gvar = ti.tydesc;
|
2011-05-12 15:42:12 -07:00
|
|
|
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-10-21 12:21:27 +02:00
|
|
|
};
|
2011-05-12 15:42:12 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn make_take_glue(cx: @block_ctxt, v: ValueRef, t: ty::t) {
|
2011-12-14 07:31:12 -08:00
|
|
|
|
2011-08-25 10:18:02 +02:00
|
|
|
let bcx = cx;
|
2011-12-13 21:44:57 -08:00
|
|
|
let tcx = bcx_tcx(cx);
|
2011-04-12 12:06:20 -07:00
|
|
|
// NB: v is an *alias* of type t here, not a direct value.
|
2011-12-14 07:31:12 -08:00
|
|
|
bcx = alt ty::struct(tcx, t) {
|
2012-01-09 17:44:55 +01:00
|
|
|
ty::ty_box(_) | ty::ty_iface(_, _) {
|
2011-12-14 07:31:12 -08:00
|
|
|
incr_refcnt_of_boxed(bcx, Load(bcx, v))
|
2011-12-13 21:44:57 -08:00
|
|
|
}
|
|
|
|
ty::ty_uniq(_) {
|
2011-09-22 18:05:36 -07:00
|
|
|
check trans_uniq::type_is_unique_box(bcx, t);
|
2011-12-14 07:31:12 -08:00
|
|
|
let r = trans_uniq::duplicate(bcx, Load(bcx, v), t);
|
|
|
|
Store(r.bcx, r.val, v);
|
|
|
|
r.bcx
|
2011-12-13 21:44:57 -08:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ty::ty_vec(_) | ty::ty_str {
|
2011-12-14 07:31:12 -08:00
|
|
|
let r = tvec::duplicate(bcx, Load(bcx, v), t);
|
|
|
|
Store(r.bcx, r.val, v);
|
|
|
|
r.bcx
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ty::ty_send_type {
|
2011-12-15 11:06:48 -08:00
|
|
|
// sendable type descriptors are basically unique pointers,
|
|
|
|
// they must be cloned when copied:
|
|
|
|
let r = Load(bcx, v);
|
|
|
|
let s = Call(bcx, bcx_ccx(bcx).upcalls.create_shared_type_desc, [r]);
|
|
|
|
Store(bcx, s, v);
|
2011-12-14 07:31:12 -08:00
|
|
|
bcx
|
|
|
|
}
|
2011-12-23 16:09:52 +01:00
|
|
|
ty::ty_native_fn(_, _) | ty::ty_fn(_) {
|
2011-12-15 11:06:48 -08:00
|
|
|
trans_closure::make_fn_glue(bcx, v, t, take_ty)
|
2011-12-14 07:31:12 -08:00
|
|
|
}
|
2012-01-05 16:19:12 -08:00
|
|
|
ty::ty_opaque_closure_ptr(ck) {
|
|
|
|
trans_closure::make_opaque_cbox_take_glue(bcx, ck, v)
|
2011-12-13 21:44:57 -08:00
|
|
|
}
|
2012-01-09 19:15:17 -06:00
|
|
|
_ if ty::type_is_structural(bcx_tcx(bcx), t) {
|
2011-12-14 07:31:12 -08:00
|
|
|
iter_structural_ty(bcx, v, t, take_ty)
|
2011-12-13 21:44:57 -08:00
|
|
|
}
|
2011-12-14 07:31:12 -08:00
|
|
|
_ { bcx }
|
|
|
|
};
|
2011-08-17 13:58:49 -07:00
|
|
|
|
2011-08-17 17:49:54 -07:00
|
|
|
build_return(bcx);
|
2010-12-10 16:13:52 -08:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn incr_refcnt_of_boxed(cx: @block_ctxt, box_ptr: ValueRef) -> @block_ctxt {
|
2011-10-14 16:45:25 -07:00
|
|
|
let ccx = bcx_ccx(cx);
|
2011-07-27 14:19:39 +02:00
|
|
|
let rc_ptr =
|
2011-10-25 22:23:28 -07:00
|
|
|
GEPi(cx, box_ptr, [0, abi::box_rc_field_refcnt]);
|
2011-08-30 09:59:30 +02:00
|
|
|
let rc = Load(cx, rc_ptr);
|
2011-10-14 16:45:25 -07:00
|
|
|
rc = Add(cx, rc, C_int(ccx, 1));
|
2011-09-02 12:21:01 -07:00
|
|
|
Store(cx, rc, rc_ptr);
|
|
|
|
ret cx;
|
2010-12-10 16:13:52 -08:00
|
|
|
}
|
|
|
|
|
2011-12-15 11:06:48 -08:00
|
|
|
fn free_box(bcx: @block_ctxt, v: ValueRef, t: ty::t) -> @block_ctxt {
|
|
|
|
ret alt ty::struct(bcx_tcx(bcx), t) {
|
|
|
|
ty::ty_box(body_mt) {
|
|
|
|
let v = PointerCast(bcx, v, type_of_1(bcx, t));
|
|
|
|
let body = GEPi(bcx, v, [0, abi::box_rc_field_body]);
|
|
|
|
let bcx = drop_ty(bcx, body, body_mt.ty);
|
|
|
|
trans_free_if_not_gc(bcx, v)
|
|
|
|
}
|
|
|
|
|
|
|
|
_ { fail "free_box invoked with non-box type"; }
|
|
|
|
};
|
2011-12-13 21:44:57 -08:00
|
|
|
}
|
|
|
|
|
2011-10-10 09:51:09 +02:00
|
|
|
fn make_free_glue(bcx: @block_ctxt, v: ValueRef, t: ty::t) {
|
|
|
|
// v is a pointer to the actual box component of the type here. The
|
|
|
|
// ValueRef will have the wrong type here (make_generic_glue is casting
|
|
|
|
// everything to a pointer to the type that the glue acts on).
|
|
|
|
let bcx = alt ty::struct(bcx_tcx(bcx), t) {
|
|
|
|
ty::ty_box(body_mt) {
|
2011-12-15 11:06:48 -08:00
|
|
|
free_box(bcx, v, t)
|
2011-10-10 09:51:09 +02:00
|
|
|
}
|
|
|
|
ty::ty_uniq(content_mt) {
|
|
|
|
check trans_uniq::type_is_unique_box(bcx, t);
|
2011-11-03 10:57:54 +01:00
|
|
|
let v = PointerCast(bcx, v, type_of_1(bcx, t));
|
2011-10-10 09:51:09 +02:00
|
|
|
trans_uniq::make_free_glue(bcx, v, t)
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ty::ty_vec(_) | ty::ty_str {
|
2011-10-10 13:32:50 +02:00
|
|
|
tvec::make_free_glue(bcx, PointerCast(bcx, v, type_of_1(bcx, t)), t)
|
|
|
|
}
|
2012-01-13 10:58:31 +01:00
|
|
|
ty::ty_iface(_, _) {
|
|
|
|
// Call through the box's own fields-drop glue first.
|
2011-10-10 09:51:09 +02:00
|
|
|
// Then free the body.
|
|
|
|
let ccx = bcx_ccx(bcx);
|
2012-01-13 10:58:31 +01:00
|
|
|
let llbox_ty = T_opaque_iface_ptr(ccx);
|
2011-10-10 09:51:09 +02:00
|
|
|
let b = PointerCast(bcx, v, llbox_ty);
|
2011-10-25 22:23:28 -07:00
|
|
|
let body = GEPi(bcx, b, [0, abi::box_rc_field_body]);
|
2012-01-13 10:58:31 +01:00
|
|
|
let tydescptr = GEPi(bcx, body, [0, 0]);
|
2011-10-10 09:51:09 +02:00
|
|
|
let tydesc = Load(bcx, tydescptr);
|
|
|
|
let ti = none;
|
|
|
|
call_tydesc_glue_full(bcx, body, tydesc,
|
|
|
|
abi::tydesc_field_drop_glue, ti);
|
2011-12-14 07:31:12 -08:00
|
|
|
trans_free_if_not_gc(bcx, b)
|
2011-10-10 09:51:09 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ty::ty_send_type {
|
2011-12-15 11:06:48 -08:00
|
|
|
// sendable type descriptors are basically unique pointers,
|
|
|
|
// they must be freed.
|
2012-01-06 17:46:33 -08:00
|
|
|
let ccx = bcx_ccx(bcx);
|
|
|
|
let v = PointerCast(bcx, v, T_ptr(ccx.tydesc_type));
|
|
|
|
Call(bcx, ccx.upcalls.free_shared_type_desc, [v]);
|
|
|
|
bcx
|
2011-12-13 21:44:57 -08:00
|
|
|
}
|
2011-12-23 16:09:52 +01:00
|
|
|
ty::ty_native_fn(_, _) | ty::ty_fn(_) {
|
2011-12-15 11:06:48 -08:00
|
|
|
trans_closure::make_fn_glue(bcx, v, t, free_ty)
|
|
|
|
}
|
2012-01-05 16:19:12 -08:00
|
|
|
ty::ty_opaque_closure_ptr(ck) {
|
|
|
|
trans_closure::make_opaque_cbox_free_glue(bcx, ck, v)
|
2011-10-10 09:51:09 +02:00
|
|
|
}
|
|
|
|
_ { bcx }
|
|
|
|
};
|
2011-08-30 13:50:58 +02:00
|
|
|
build_return(bcx);
|
2011-05-18 17:28:08 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn make_drop_glue(bcx: @block_ctxt, v0: ValueRef, t: ty::t) {
|
2011-05-18 17:28:08 -07:00
|
|
|
// NB: v0 is an *alias* of type t here, not a direct value.
|
2011-08-30 13:50:58 +02:00
|
|
|
let ccx = bcx_ccx(bcx);
|
2011-09-12 11:27:30 +02:00
|
|
|
let bcx =
|
|
|
|
alt ty::struct(ccx.tcx, t) {
|
2012-01-07 22:44:14 +01:00
|
|
|
ty::ty_box(_) | ty::ty_iface(_, _) {
|
|
|
|
decr_refcnt_maybe_free(bcx, Load(bcx, v0), t)
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ty::ty_uniq(_) | ty::ty_vec(_) | ty::ty_str | ty::ty_send_type {
|
2011-10-10 13:32:50 +02:00
|
|
|
free_ty(bcx, Load(bcx, v0), t)
|
|
|
|
}
|
2011-09-12 11:27:30 +02:00
|
|
|
ty::ty_res(did, inner, tps) {
|
|
|
|
trans_res_drop(bcx, v0, did, inner, tps)
|
|
|
|
}
|
2011-12-23 16:09:52 +01:00
|
|
|
ty::ty_native_fn(_, _) | ty::ty_fn(_) {
|
2011-12-15 11:06:48 -08:00
|
|
|
trans_closure::make_fn_glue(bcx, v0, t, drop_ty)
|
2011-12-13 21:44:57 -08:00
|
|
|
}
|
2012-01-05 16:19:12 -08:00
|
|
|
ty::ty_opaque_closure_ptr(ck) {
|
|
|
|
trans_closure::make_opaque_cbox_drop_glue(bcx, ck, v0)
|
2011-09-12 11:27:30 +02:00
|
|
|
}
|
|
|
|
_ {
|
2011-11-22 13:16:23 +01:00
|
|
|
if ty::type_needs_drop(ccx.tcx, t) &&
|
|
|
|
ty::type_is_structural(ccx.tcx, t) {
|
2011-09-12 11:27:30 +02:00
|
|
|
iter_structural_ty(bcx, v0, t, drop_ty)
|
|
|
|
} else { bcx }
|
|
|
|
}
|
|
|
|
};
|
2011-08-30 13:50:58 +02:00
|
|
|
build_return(bcx);
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trans_res_drop(cx: @block_ctxt, rs: ValueRef, did: ast::def_id,
|
|
|
|
inner_t: ty::t, tps: [ty::t]) -> @block_ctxt {
|
2011-07-27 14:19:39 +02:00
|
|
|
let ccx = bcx_ccx(cx);
|
|
|
|
let inner_t_s = ty::substitute_type_params(ccx.tcx, tps, inner_t);
|
2011-08-19 15:16:48 -07:00
|
|
|
let tup_ty = ty::mk_tup(ccx.tcx, [ty::mk_int(ccx.tcx), inner_t_s]);
|
2011-09-02 15:34:58 -07:00
|
|
|
let drop_cx = new_sub_block_ctxt(cx, "drop res");
|
|
|
|
let next_cx = new_sub_block_ctxt(cx, "next");
|
2011-06-28 16:14:01 +02:00
|
|
|
|
2011-09-17 10:18:30 -07:00
|
|
|
// Silly check
|
|
|
|
check type_is_tup_like(cx, tup_ty);
|
2011-08-19 15:16:48 -07:00
|
|
|
let drop_flag = GEP_tup_like(cx, tup_ty, rs, [0, 0]);
|
2011-11-03 10:57:54 +01:00
|
|
|
let cx = drop_flag.bcx;
|
2011-08-30 09:59:30 +02:00
|
|
|
let null_test = IsNull(cx, Load(cx, drop_flag.val));
|
|
|
|
CondBr(cx, null_test, next_cx.llbb, drop_cx.llbb);
|
2011-06-28 16:14:01 +02:00
|
|
|
cx = drop_cx;
|
2011-06-30 12:35:19 +02:00
|
|
|
|
2011-09-17 10:18:30 -07:00
|
|
|
check type_is_tup_like(cx, tup_ty);
|
2011-08-19 15:16:48 -07:00
|
|
|
let val = GEP_tup_like(cx, tup_ty, rs, [0, 1]);
|
2011-06-30 14:46:17 +02:00
|
|
|
cx = val.bcx;
|
2011-06-30 12:35:19 +02:00
|
|
|
// Find and call the actual destructor.
|
2011-09-18 22:05:58 +02:00
|
|
|
let dtor_addr = trans_common::get_res_dtor(ccx, cx.sp, did, inner_t);
|
2011-10-20 11:56:45 +02:00
|
|
|
let args = [cx.fcx.llretptr, null_env_ptr(cx)];
|
2011-08-19 15:16:48 -07:00
|
|
|
for tp: ty::t in tps {
|
2011-08-12 07:15:18 -07:00
|
|
|
let ti: option::t<@tydesc_info> = none;
|
2012-01-13 10:58:31 +01:00
|
|
|
let td = get_tydesc(cx, tp, false, ti).result;
|
2011-08-19 15:16:48 -07:00
|
|
|
args += [td.val];
|
2011-06-30 14:46:17 +02:00
|
|
|
cx = td.bcx;
|
|
|
|
}
|
|
|
|
// Kludge to work around the fact that we know the precise type of the
|
|
|
|
// value here, but the dtor expects a type that still has opaque pointers
|
|
|
|
// for type variables.
|
2011-09-12 12:39:38 +02:00
|
|
|
let val_llty = lib::llvm::fn_ty_param_tys
|
2011-09-12 11:27:30 +02:00
|
|
|
(llvm::LLVMGetElementType
|
2011-12-13 16:25:51 -08:00
|
|
|
(llvm::LLVMTypeOf(dtor_addr)))[vec::len(args)];
|
2011-08-30 09:59:30 +02:00
|
|
|
let val_cast = BitCast(cx, val.val, val_llty);
|
2011-09-27 18:42:06 -07:00
|
|
|
Call(cx, dtor_addr, args + [val_cast]);
|
2011-06-30 14:46:17 +02:00
|
|
|
|
2011-08-30 13:50:58 +02:00
|
|
|
cx = drop_ty(cx, val.val, inner_t_s);
|
2011-11-17 13:43:34 -08:00
|
|
|
// FIXME #1184: Resource flag is larger than necessary
|
2011-11-17 13:36:09 -08:00
|
|
|
Store(cx, C_int(ccx, 0), drop_flag.val);
|
2011-08-30 09:59:30 +02:00
|
|
|
Br(cx, next_cx.llbb);
|
2011-08-30 13:50:58 +02:00
|
|
|
ret next_cx;
|
2011-06-28 16:14:01 +02:00
|
|
|
}
|
|
|
|
|
2011-10-10 09:51:09 +02:00
|
|
|
fn decr_refcnt_maybe_free(cx: @block_ctxt, box_ptr: ValueRef, t: ty::t)
|
|
|
|
-> @block_ctxt {
|
2011-07-27 14:19:39 +02:00
|
|
|
let ccx = bcx_ccx(cx);
|
2011-09-02 15:34:58 -07:00
|
|
|
let rc_adj_cx = new_sub_block_ctxt(cx, "rc--");
|
|
|
|
let free_cx = new_sub_block_ctxt(cx, "free");
|
|
|
|
let next_cx = new_sub_block_ctxt(cx, "next");
|
2012-01-13 10:58:31 +01:00
|
|
|
let llbox_ty = T_opaque_iface_ptr(ccx);
|
2011-11-03 10:57:54 +01:00
|
|
|
let box_ptr = PointerCast(cx, box_ptr, llbox_ty);
|
2011-08-30 09:59:30 +02:00
|
|
|
let null_test = IsNull(cx, box_ptr);
|
2011-09-02 12:21:01 -07:00
|
|
|
CondBr(cx, null_test, next_cx.llbb, rc_adj_cx.llbb);
|
2011-07-27 14:19:39 +02:00
|
|
|
let rc_ptr =
|
2011-10-25 22:23:28 -07:00
|
|
|
GEPi(rc_adj_cx, box_ptr, [0, abi::box_rc_field_refcnt]);
|
2011-09-02 12:21:01 -07:00
|
|
|
let rc = Load(rc_adj_cx, rc_ptr);
|
2011-10-14 16:45:25 -07:00
|
|
|
rc = Sub(rc_adj_cx, rc, C_int(ccx, 1));
|
2011-08-30 09:59:30 +02:00
|
|
|
Store(rc_adj_cx, rc, rc_ptr);
|
2011-10-14 16:45:25 -07:00
|
|
|
let zero_test = ICmp(rc_adj_cx, lib::llvm::LLVMIntEQ, C_int(ccx, 0), rc);
|
2011-08-30 09:59:30 +02:00
|
|
|
CondBr(rc_adj_cx, zero_test, free_cx.llbb, next_cx.llbb);
|
2011-10-10 09:51:09 +02:00
|
|
|
let free_cx = free_ty(free_cx, box_ptr, t);
|
2011-08-30 13:50:58 +02:00
|
|
|
Br(free_cx, next_cx.llbb);
|
|
|
|
ret next_cx;
|
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-09-12 11:27:30 +02:00
|
|
|
fn maybe_name_value(cx: @crate_ctxt, v: ValueRef, s: str) {
|
2012-01-12 17:59:49 +01:00
|
|
|
if cx.sess.opts.save_temps {
|
2011-09-02 15:34:58 -07:00
|
|
|
let _: () = str::as_buf(s, {|buf| llvm::LLVMSetValueName(v, buf) });
|
2011-05-10 16:43:34 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-08-02 12:26:52 -07:00
|
|
|
// Used only for creating scalar comparison glue.
|
2012-01-19 17:56:05 -08:00
|
|
|
enum scalar_type { nil_type, signed_int, unsigned_int, floating_point, }
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-02 16:23:52 -07:00
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
fn compare_scalar_types(cx: @block_ctxt, lhs: ValueRef, rhs: ValueRef,
|
2011-10-27 22:01:30 -07:00
|
|
|
t: ty::t, op: ast::binop) -> result {
|
|
|
|
let f = bind compare_scalar_values(cx, lhs, rhs, _, op);
|
2011-07-27 14:19:39 +02:00
|
|
|
|
|
|
|
alt ty::struct(bcx_tcx(cx), t) {
|
2012-01-18 22:37:22 -08:00
|
|
|
ty::ty_nil { ret rslt(cx, f(nil_type)); }
|
|
|
|
ty::ty_bool | ty::ty_ptr(_) { ret rslt(cx, f(unsigned_int)); }
|
2011-12-07 21:06:12 +01:00
|
|
|
ty::ty_int(_) { ret rslt(cx, f(signed_int)); }
|
|
|
|
ty::ty_uint(_) { ret rslt(cx, f(unsigned_int)); }
|
|
|
|
ty::ty_float(_) { ret rslt(cx, f(floating_point)); }
|
2012-01-18 22:37:22 -08:00
|
|
|
ty::ty_type {
|
2011-09-26 13:21:47 +02:00
|
|
|
ret rslt(trans_fail(cx, none,
|
|
|
|
"attempt to compare values of type type"),
|
|
|
|
C_nil());
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
ty::ty_native(_) {
|
2011-09-26 13:21:47 +02:00
|
|
|
let cx = trans_fail(cx, none::<span>,
|
|
|
|
"attempt to compare values of type native");
|
|
|
|
ret rslt(cx, C_nil());
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ {
|
|
|
|
// Should never get here, because t is scalar.
|
2011-09-02 15:34:58 -07:00
|
|
|
bcx_ccx(cx).sess.bug("non-scalar type passed to \
|
2011-07-22 23:56:02 -07:00
|
|
|
compare_scalar_types");
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-04-19 15:22:57 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-07-11 16:37:21 -05:00
|
|
|
// A helper function to do the actual comparison of scalar values.
|
2011-09-12 11:27:30 +02:00
|
|
|
fn compare_scalar_values(cx: @block_ctxt, lhs: ValueRef, rhs: ValueRef,
|
2011-10-27 22:01:30 -07:00
|
|
|
nt: scalar_type, op: ast::binop) -> ValueRef {
|
2011-10-28 14:20:10 -07:00
|
|
|
alt nt {
|
2012-01-18 22:37:22 -08:00
|
|
|
nil_type {
|
2011-07-27 14:19:39 +02:00
|
|
|
// We don't need to do actual comparisons for nil.
|
|
|
|
// () == () holds but () < () does not.
|
2011-10-27 22:01:30 -07:00
|
|
|
alt op {
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::eq | ast::le | ast::ge { ret C_bool(true); }
|
|
|
|
ast::ne | ast::lt | ast::gt { ret C_bool(false); }
|
2011-10-27 22:01:30 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
floating_point {
|
2011-10-28 14:20:10 -07:00
|
|
|
let cmp = alt op {
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::eq { lib::llvm::LLVMRealOEQ }
|
|
|
|
ast::ne { lib::llvm::LLVMRealUNE }
|
|
|
|
ast::lt { lib::llvm::LLVMRealOLT }
|
|
|
|
ast::le { lib::llvm::LLVMRealOLE }
|
|
|
|
ast::gt { lib::llvm::LLVMRealOGT }
|
|
|
|
ast::ge { lib::llvm::LLVMRealOGE }
|
2011-10-28 14:20:10 -07:00
|
|
|
};
|
|
|
|
ret FCmp(cx, cmp, lhs, rhs);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
signed_int {
|
2011-10-28 14:20:10 -07:00
|
|
|
let cmp = alt op {
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::eq { lib::llvm::LLVMIntEQ }
|
|
|
|
ast::ne { lib::llvm::LLVMIntNE }
|
|
|
|
ast::lt { lib::llvm::LLVMIntSLT }
|
|
|
|
ast::le { lib::llvm::LLVMIntSLE }
|
|
|
|
ast::gt { lib::llvm::LLVMIntSGT }
|
|
|
|
ast::ge { lib::llvm::LLVMIntSGE }
|
2011-10-28 14:20:10 -07:00
|
|
|
};
|
|
|
|
ret ICmp(cx, cmp, lhs, rhs);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
unsigned_int {
|
2011-10-28 14:20:10 -07:00
|
|
|
let cmp = alt op {
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::eq { lib::llvm::LLVMIntEQ }
|
|
|
|
ast::ne { lib::llvm::LLVMIntNE }
|
|
|
|
ast::lt { lib::llvm::LLVMIntULT }
|
|
|
|
ast::le { lib::llvm::LLVMIntULE }
|
|
|
|
ast::gt { lib::llvm::LLVMIntUGT }
|
|
|
|
ast::ge { lib::llvm::LLVMIntUGE }
|
2011-10-28 14:20:10 -07:00
|
|
|
};
|
|
|
|
ret ICmp(cx, cmp, lhs, rhs);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-04-19 15:22:57 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-11 09:58:05 -08:00
|
|
|
type val_pair_fn = fn@(@block_ctxt, ValueRef, ValueRef) -> @block_ctxt;
|
|
|
|
type val_and_ty_fn = fn@(@block_ctxt, ValueRef, ty::t) -> @block_ctxt;
|
2011-02-28 17:49:26 -08:00
|
|
|
|
2011-11-10 09:14:53 -08:00
|
|
|
fn load_inbounds(cx: @block_ctxt, p: ValueRef, idxs: [int]) -> ValueRef {
|
|
|
|
ret Load(cx, GEPi(cx, p, idxs));
|
2011-07-05 14:19:19 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn store_inbounds(cx: @block_ctxt, v: ValueRef, p: ValueRef,
|
2011-10-26 17:09:07 -07:00
|
|
|
idxs: [int]) {
|
|
|
|
Store(cx, v, GEPi(cx, p, idxs));
|
2011-07-05 14:19:19 -07:00
|
|
|
}
|
|
|
|
|
2011-08-30 13:10:10 +02:00
|
|
|
// Iterates through the elements of a structural type.
|
2011-08-30 13:50:58 +02:00
|
|
|
fn iter_structural_ty(cx: @block_ctxt, av: ValueRef, t: ty::t,
|
2011-09-12 11:27:30 +02:00
|
|
|
f: val_and_ty_fn) -> @block_ctxt {
|
|
|
|
fn iter_boxpp(cx: @block_ctxt, box_cell: ValueRef, f: val_and_ty_fn) ->
|
2011-09-02 15:34:58 -07:00
|
|
|
@block_ctxt {
|
2011-08-30 09:59:30 +02:00
|
|
|
let box_ptr = Load(cx, box_cell);
|
2011-07-27 14:19:39 +02:00
|
|
|
let tnil = ty::mk_nil(bcx_tcx(cx));
|
|
|
|
let tbox = ty::mk_imm_box(bcx_tcx(cx), tnil);
|
2011-09-02 15:34:58 -07:00
|
|
|
let inner_cx = new_sub_block_ctxt(cx, "iter box");
|
|
|
|
let next_cx = new_sub_block_ctxt(cx, "next");
|
2011-08-30 09:59:30 +02:00
|
|
|
let null_test = IsNull(cx, box_ptr);
|
|
|
|
CondBr(cx, null_test, next_cx.llbb, inner_cx.llbb);
|
2011-08-30 13:50:58 +02:00
|
|
|
let inner_cx = f(inner_cx, box_cell, tbox);
|
|
|
|
Br(inner_cx, next_cx.llbb);
|
|
|
|
ret next_cx;
|
2010-12-20 17:28:07 -08:00
|
|
|
}
|
2011-07-01 12:36:49 +02:00
|
|
|
|
2011-08-09 18:28:46 -07:00
|
|
|
fn iter_variant(cx: @block_ctxt, a_tup: ValueRef,
|
2011-09-12 11:27:30 +02:00
|
|
|
variant: ty::variant_info, tps: [ty::t], tid: ast::def_id,
|
|
|
|
f: val_and_ty_fn) -> @block_ctxt {
|
2011-12-13 16:25:51 -08:00
|
|
|
if vec::len::<ty::t>(variant.args) == 0u { ret cx; }
|
2011-07-27 14:19:39 +02:00
|
|
|
let fn_ty = variant.ctor_ty;
|
|
|
|
let ccx = bcx_ccx(cx);
|
2011-11-03 10:57:54 +01:00
|
|
|
let cx = cx;
|
2011-07-27 14:19:39 +02:00
|
|
|
alt ty::struct(ccx.tcx, fn_ty) {
|
2011-12-23 16:09:52 +01:00
|
|
|
ty::ty_fn({inputs: args, _}) {
|
2011-09-01 16:31:18 -07:00
|
|
|
let j = 0u;
|
2011-09-01 17:25:06 -07:00
|
|
|
let v_id = variant.id;
|
2011-08-15 21:54:52 -07:00
|
|
|
for a: ty::arg in args {
|
2011-09-02 15:34:58 -07:00
|
|
|
check (valid_variant_index(j, cx, tid, v_id));
|
2011-09-01 17:25:06 -07:00
|
|
|
let rslt = GEP_tag(cx, a_tup, tid, v_id, tps, j);
|
2011-07-27 14:19:39 +02:00
|
|
|
let llfldp_a = rslt.val;
|
|
|
|
cx = rslt.bcx;
|
|
|
|
let ty_subst = ty::substitute_type_params(ccx.tcx, tps, a.ty);
|
2011-08-30 13:50:58 +02:00
|
|
|
cx = f(cx, llfldp_a, ty_subst);
|
2011-09-01 16:31:18 -07:00
|
|
|
j += 1u;
|
2011-07-01 12:36:49 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-07-01 12:36:49 +02:00
|
|
|
}
|
2011-08-30 13:50:58 +02:00
|
|
|
ret cx;
|
2011-07-01 12:36:49 +02:00
|
|
|
}
|
2011-07-13 15:44:09 -07:00
|
|
|
|
2011-09-17 10:18:30 -07:00
|
|
|
/*
|
|
|
|
Typestate constraint that shows the unimpl case doesn't happen?
|
|
|
|
*/
|
2011-11-03 10:57:54 +01:00
|
|
|
let cx = cx;
|
2011-07-27 14:19:39 +02:00
|
|
|
alt ty::struct(bcx_tcx(cx), t) {
|
|
|
|
ty::ty_rec(fields) {
|
|
|
|
let i: int = 0;
|
2011-08-15 11:40:26 +02:00
|
|
|
for fld: ty::field in fields {
|
2011-09-17 10:18:30 -07:00
|
|
|
// Silly check
|
|
|
|
check type_is_tup_like(cx, t);
|
2011-09-02 15:34:58 -07:00
|
|
|
let {bcx: bcx, val: llfld_a} = GEP_tup_like(cx, t, av, [0, i]);
|
2011-08-30 13:50:58 +02:00
|
|
|
cx = f(bcx, llfld_a, fld.mt.ty);
|
2011-07-27 14:19:39 +02:00
|
|
|
i += 1;
|
2011-06-10 19:35:59 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-08-15 11:40:26 +02:00
|
|
|
ty::ty_tup(args) {
|
|
|
|
let i = 0;
|
|
|
|
for arg in args {
|
2011-09-17 10:18:30 -07:00
|
|
|
// Silly check
|
|
|
|
check type_is_tup_like(cx, t);
|
2011-09-02 15:34:58 -07:00
|
|
|
let {bcx: bcx, val: llfld_a} = GEP_tup_like(cx, t, av, [0, i]);
|
2011-08-30 13:50:58 +02:00
|
|
|
cx = f(bcx, llfld_a, arg);
|
2011-08-15 11:40:26 +02:00
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
ty::ty_res(_, inner, tps) {
|
2011-07-29 11:44:29 +02:00
|
|
|
let tcx = bcx_tcx(cx);
|
|
|
|
let inner1 = ty::substitute_type_params(tcx, tps, inner);
|
|
|
|
let inner_t_s = ty::substitute_type_params(tcx, tps, inner);
|
2011-08-19 15:16:48 -07:00
|
|
|
let tup_t = ty::mk_tup(tcx, [ty::mk_int(tcx), inner_t_s]);
|
2011-09-17 10:18:30 -07:00
|
|
|
// Silly check
|
|
|
|
check type_is_tup_like(cx, tup_t);
|
2011-09-02 15:34:58 -07:00
|
|
|
let {bcx: bcx, val: llfld_a} = GEP_tup_like(cx, tup_t, av, [0, 1]);
|
2011-08-30 13:50:58 +02:00
|
|
|
ret f(bcx, llfld_a, inner1);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
ty::ty_tag(tid, tps) {
|
|
|
|
let variants = ty::tag_variants(bcx_tcx(cx), tid);
|
2011-12-15 17:14:58 -08:00
|
|
|
let n_variants = vec::len(*variants);
|
2011-07-27 14:19:39 +02:00
|
|
|
|
|
|
|
// Cast the tags to types we can GEP into.
|
|
|
|
if n_variants == 1u {
|
2011-08-19 15:16:48 -07:00
|
|
|
ret iter_variant(cx, av, variants[0], tps, tid, f);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
|
2011-10-14 16:45:25 -07:00
|
|
|
let ccx = bcx_ccx(cx);
|
|
|
|
let lltagty = T_opaque_tag_ptr(ccx);
|
2011-08-30 09:59:30 +02:00
|
|
|
let av_tag = PointerCast(cx, av, lltagty);
|
2011-10-25 22:23:28 -07:00
|
|
|
let lldiscrim_a_ptr = GEPi(cx, av_tag, [0, 0]);
|
|
|
|
let llunion_a_ptr = GEPi(cx, av_tag, [0, 1]);
|
2011-08-30 09:59:30 +02:00
|
|
|
let lldiscrim_a = Load(cx, lldiscrim_a_ptr);
|
2011-07-27 14:19:39 +02:00
|
|
|
|
|
|
|
// NB: we must hit the discriminant first so that structural
|
|
|
|
// comparison know not to proceed when the discriminants differ.
|
2011-08-30 13:50:58 +02:00
|
|
|
cx = f(cx, lldiscrim_a_ptr, ty::mk_int(bcx_tcx(cx)));
|
2012-01-19 14:24:03 -08:00
|
|
|
let unr_cx = new_sub_block_ctxt(cx, "enum-iter-unr");
|
2011-08-30 09:59:30 +02:00
|
|
|
Unreachable(unr_cx);
|
2011-08-30 13:50:58 +02:00
|
|
|
let llswitch = Switch(cx, lldiscrim_a, unr_cx.llbb, n_variants);
|
2012-01-19 14:24:03 -08:00
|
|
|
let next_cx = new_sub_block_ctxt(cx, "enum-iter-next");
|
2011-12-15 17:14:58 -08:00
|
|
|
for variant: ty::variant_info in *variants {
|
2011-07-27 14:19:39 +02:00
|
|
|
let variant_cx =
|
2011-09-02 15:34:58 -07:00
|
|
|
new_sub_block_ctxt(cx,
|
2012-01-19 14:24:03 -08:00
|
|
|
"enum-iter-variant-" +
|
2012-01-10 14:50:40 -07:00
|
|
|
int::to_str(variant.disr_val, 10u));
|
|
|
|
AddCase(llswitch, C_int(ccx, variant.disr_val), variant_cx.llbb);
|
2011-09-02 15:34:58 -07:00
|
|
|
variant_cx =
|
|
|
|
iter_variant(variant_cx, llunion_a_ptr, variant, tps, tid, f);
|
2011-08-30 09:59:30 +02:00
|
|
|
Br(variant_cx, next_cx.llbb);
|
2010-12-01 17:08:46 -08:00
|
|
|
}
|
2011-08-30 13:50:58 +02:00
|
|
|
ret next_cx;
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-09-02 15:34:58 -07:00
|
|
|
_ { bcx_ccx(cx).sess.unimpl("type in iter_structural_ty"); }
|
2010-11-09 17:49:20 -08:00
|
|
|
}
|
2011-08-30 13:50:58 +02:00
|
|
|
ret cx;
|
2010-11-09 17:49:20 -08:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn lazily_emit_all_tydesc_glue(cx: @block_ctxt,
|
|
|
|
static_ti: option::t<@tydesc_info>) {
|
2011-08-19 10:24:13 +02:00
|
|
|
lazily_emit_tydesc_glue(cx, abi::tydesc_field_take_glue, static_ti);
|
2011-05-12 15:42:12 -07:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn lazily_emit_all_generic_info_tydesc_glues(cx: @block_ctxt,
|
|
|
|
gi: generic_info) {
|
2011-08-12 07:15:18 -07:00
|
|
|
for ti: option::t<@tydesc_info> in gi.static_tis {
|
2011-05-12 15:42:12 -07:00
|
|
|
lazily_emit_all_tydesc_glue(cx, ti);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn lazily_emit_tydesc_glue(cx: @block_ctxt, field: int,
|
|
|
|
static_ti: option::t<@tydesc_info>) {
|
2011-07-27 14:19:39 +02:00
|
|
|
alt static_ti {
|
2012-01-18 22:37:22 -08:00
|
|
|
none { }
|
2011-07-27 14:19:39 +02:00
|
|
|
some(ti) {
|
2011-08-19 10:24:13 +02:00
|
|
|
if field == abi::tydesc_field_take_glue {
|
2011-09-20 17:29:09 +02:00
|
|
|
alt ti.take_glue {
|
2011-07-27 14:19:39 +02:00
|
|
|
some(_) { }
|
2012-01-18 22:37:22 -08:00
|
|
|
none {
|
2011-12-22 16:13:40 -08:00
|
|
|
#debug("+++ lazily_emit_tydesc_glue TAKE %s",
|
|
|
|
ty_to_str(bcx_tcx(cx), ti.ty));
|
2011-07-27 14:19:39 +02:00
|
|
|
let lcx = cx.fcx.lcx;
|
|
|
|
let glue_fn =
|
2011-10-14 16:45:25 -07:00
|
|
|
declare_generic_glue(lcx, ti.ty, T_glue_fn(lcx.ccx),
|
2011-09-02 15:34:58 -07:00
|
|
|
"take");
|
2011-08-19 10:24:13 +02:00
|
|
|
ti.take_glue = some::<ValueRef>(glue_fn);
|
2011-08-22 11:41:49 +02:00
|
|
|
make_generic_glue(lcx, cx.sp, ti.ty, glue_fn,
|
2011-12-12 09:39:41 -08:00
|
|
|
make_take_glue,
|
2011-09-02 15:34:58 -07:00
|
|
|
ti.ty_params, "take");
|
2011-12-22 16:13:40 -08:00
|
|
|
#debug("--- lazily_emit_tydesc_glue TAKE %s",
|
|
|
|
ty_to_str(bcx_tcx(cx), ti.ty));
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
}
|
2011-08-19 15:16:48 -07:00
|
|
|
} else if field == abi::tydesc_field_drop_glue {
|
2011-09-20 17:29:09 +02:00
|
|
|
alt ti.drop_glue {
|
2011-07-27 14:19:39 +02:00
|
|
|
some(_) { }
|
2012-01-18 22:37:22 -08:00
|
|
|
none {
|
2011-12-22 16:13:40 -08:00
|
|
|
#debug("+++ lazily_emit_tydesc_glue DROP %s",
|
|
|
|
ty_to_str(bcx_tcx(cx), ti.ty));
|
2011-07-27 14:19:39 +02:00
|
|
|
let lcx = cx.fcx.lcx;
|
|
|
|
let glue_fn =
|
2011-10-14 16:45:25 -07:00
|
|
|
declare_generic_glue(lcx, ti.ty, T_glue_fn(lcx.ccx),
|
2011-09-02 15:34:58 -07:00
|
|
|
"drop");
|
2011-08-13 00:09:25 -07:00
|
|
|
ti.drop_glue = some::<ValueRef>(glue_fn);
|
2011-08-22 11:41:49 +02:00
|
|
|
make_generic_glue(lcx, cx.sp, ti.ty, glue_fn,
|
2011-12-12 09:39:41 -08:00
|
|
|
make_drop_glue,
|
2011-09-02 15:34:58 -07:00
|
|
|
ti.ty_params, "drop");
|
2011-12-22 16:13:40 -08:00
|
|
|
#debug("--- lazily_emit_tydesc_glue DROP %s",
|
|
|
|
ty_to_str(bcx_tcx(cx), ti.ty));
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
}
|
2011-09-02 15:34:58 -07:00
|
|
|
} else if field == abi::tydesc_field_free_glue {
|
2011-09-20 17:29:09 +02:00
|
|
|
alt ti.free_glue {
|
2011-07-27 14:19:39 +02:00
|
|
|
some(_) { }
|
2012-01-18 22:37:22 -08:00
|
|
|
none {
|
2011-12-22 16:13:40 -08:00
|
|
|
#debug("+++ lazily_emit_tydesc_glue FREE %s",
|
|
|
|
ty_to_str(bcx_tcx(cx), ti.ty));
|
2011-07-27 14:19:39 +02:00
|
|
|
let lcx = cx.fcx.lcx;
|
|
|
|
let glue_fn =
|
2011-10-14 16:45:25 -07:00
|
|
|
declare_generic_glue(lcx, ti.ty, T_glue_fn(lcx.ccx),
|
2011-09-02 15:34:58 -07:00
|
|
|
"free");
|
2011-08-13 00:09:25 -07:00
|
|
|
ti.free_glue = some::<ValueRef>(glue_fn);
|
2011-08-22 11:41:49 +02:00
|
|
|
make_generic_glue(lcx, cx.sp, ti.ty, glue_fn,
|
2011-12-12 09:39:41 -08:00
|
|
|
make_free_glue,
|
2011-09-02 15:34:58 -07:00
|
|
|
ti.ty_params, "free");
|
2011-12-22 16:13:40 -08:00
|
|
|
#debug("--- lazily_emit_tydesc_glue FREE %s",
|
|
|
|
ty_to_str(bcx_tcx(cx), ti.ty));
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
}
|
2011-08-19 15:16:48 -07:00
|
|
|
} else if field == abi::tydesc_field_cmp_glue {
|
2011-09-20 17:29:09 +02:00
|
|
|
alt ti.cmp_glue {
|
2011-07-27 14:19:39 +02:00
|
|
|
some(_) { }
|
2012-01-18 22:37:22 -08:00
|
|
|
none {
|
2011-12-22 16:13:40 -08:00
|
|
|
#debug("+++ lazily_emit_tydesc_glue CMP %s",
|
|
|
|
ty_to_str(bcx_tcx(cx), ti.ty));
|
2011-08-09 17:01:38 -07:00
|
|
|
ti.cmp_glue = some(bcx_ccx(cx).upcalls.cmp_type);
|
2011-12-22 16:13:40 -08:00
|
|
|
#debug("--- lazily_emit_tydesc_glue CMP %s",
|
|
|
|
ty_to_str(bcx_tcx(cx), ti.ty));
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-05-12 15:42:12 -07:00
|
|
|
}
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-05-12 15:42:12 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn call_tydesc_glue_full(cx: @block_ctxt, v: ValueRef, tydesc: ValueRef,
|
|
|
|
field: int, static_ti: option::t<@tydesc_info>) {
|
2011-05-12 15:42:12 -07:00
|
|
|
lazily_emit_tydesc_glue(cx, field, static_ti);
|
2011-06-27 15:38:04 -07:00
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
let static_glue_fn = none;
|
|
|
|
alt static_ti {
|
2012-01-18 22:37:22 -08:00
|
|
|
none {/* no-op */ }
|
2011-07-27 14:19:39 +02:00
|
|
|
some(sti) {
|
2011-08-19 10:24:13 +02:00
|
|
|
if field == abi::tydesc_field_take_glue {
|
|
|
|
static_glue_fn = sti.take_glue;
|
2011-08-19 15:16:48 -07:00
|
|
|
} else if field == abi::tydesc_field_drop_glue {
|
2011-06-27 15:38:04 -07:00
|
|
|
static_glue_fn = sti.drop_glue;
|
2011-08-19 15:16:48 -07:00
|
|
|
} else if field == abi::tydesc_field_free_glue {
|
2011-06-27 15:38:04 -07:00
|
|
|
static_glue_fn = sti.free_glue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-30 09:59:30 +02:00
|
|
|
let llrawptr = PointerCast(cx, v, T_ptr(T_i8()));
|
2011-07-27 14:19:39 +02:00
|
|
|
let lltydescs =
|
2011-10-25 22:23:28 -07:00
|
|
|
GEPi(cx, tydesc, [0, abi::tydesc_field_first_param]);
|
2011-08-30 09:59:30 +02:00
|
|
|
lltydescs = Load(cx, lltydescs);
|
2011-06-27 15:38:04 -07:00
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
let llfn;
|
|
|
|
alt static_glue_fn {
|
2012-01-18 22:37:22 -08:00
|
|
|
none {
|
2011-10-25 22:23:28 -07:00
|
|
|
let llfnptr = GEPi(cx, tydesc, [0, field]);
|
2011-08-30 09:59:30 +02:00
|
|
|
llfn = Load(cx, llfnptr);
|
2011-06-27 15:38:04 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
some(sgf) { llfn = sgf; }
|
2011-06-27 15:38:04 -07:00
|
|
|
}
|
|
|
|
|
2011-10-20 11:56:45 +02:00
|
|
|
Call(cx, llfn, [C_null(T_ptr(T_nil())), C_null(T_ptr(T_nil())),
|
|
|
|
lltydescs, llrawptr]);
|
2011-01-28 14:34:25 -08:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn call_tydesc_glue(cx: @block_ctxt, v: ValueRef, t: ty::t, field: int) ->
|
2011-09-02 15:34:58 -07:00
|
|
|
@block_ctxt {
|
2011-08-13 00:09:25 -07:00
|
|
|
let ti: option::t<@tydesc_info> = none::<@tydesc_info>;
|
2012-01-13 10:58:31 +01:00
|
|
|
let {bcx: bcx, val: td} = get_tydesc(cx, t, false, ti).result;
|
2011-08-30 13:50:58 +02:00
|
|
|
call_tydesc_glue_full(bcx, v, td, field, ti);
|
|
|
|
ret bcx;
|
2011-01-28 14:34:25 -08:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn call_cmp_glue(cx: @block_ctxt, lhs: ValueRef, rhs: ValueRef, t: ty::t,
|
2011-07-27 14:19:39 +02:00
|
|
|
llop: ValueRef) -> result {
|
2011-04-19 15:22:57 -07:00
|
|
|
// We can't use call_tydesc_glue_full() and friends here because compare
|
|
|
|
// glue has a special signature.
|
|
|
|
|
2011-09-02 15:12:27 -07:00
|
|
|
let bcx = cx;
|
|
|
|
|
|
|
|
let r = spill_if_immediate(bcx, lhs, t);
|
2011-09-02 15:34:58 -07:00
|
|
|
let lllhs = r.val;
|
|
|
|
bcx = r.bcx;
|
2011-09-02 15:12:27 -07:00
|
|
|
r = spill_if_immediate(bcx, rhs, t);
|
2011-09-02 15:34:58 -07:00
|
|
|
let llrhs = r.val;
|
|
|
|
bcx = r.bcx;
|
2011-09-02 15:12:27 -07:00
|
|
|
|
|
|
|
let llrawlhsptr = BitCast(bcx, lllhs, T_ptr(T_i8()));
|
|
|
|
let llrawrhsptr = BitCast(bcx, llrhs, T_ptr(T_i8()));
|
2011-08-13 00:09:25 -07:00
|
|
|
let ti = none::<@tydesc_info>;
|
2012-01-13 10:58:31 +01:00
|
|
|
r = get_tydesc(bcx, t, false, ti).result;
|
2011-09-02 15:34:58 -07:00
|
|
|
let lltydesc = r.val;
|
|
|
|
bcx = r.bcx;
|
2011-09-02 15:12:27 -07:00
|
|
|
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_cmp_glue, ti);
|
2011-09-02 15:34:58 -07:00
|
|
|
let lltydescs =
|
2011-10-25 22:23:28 -07:00
|
|
|
GEPi(bcx, lltydesc, [0, abi::tydesc_field_first_param]);
|
2011-09-02 15:12:27 -07:00
|
|
|
lltydescs = Load(bcx, lltydescs);
|
2011-06-27 18:35:01 -07:00
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
let llfn;
|
|
|
|
alt ti {
|
2012-01-18 22:37:22 -08:00
|
|
|
none {
|
2011-09-02 15:34:58 -07:00
|
|
|
let llfnptr =
|
2011-10-25 22:23:28 -07:00
|
|
|
GEPi(bcx, lltydesc, [0, abi::tydesc_field_cmp_glue]);
|
2011-09-02 15:12:27 -07:00
|
|
|
llfn = Load(bcx, llfnptr);
|
2011-06-27 18:35:01 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
some(sti) { llfn = option::get(sti.cmp_glue); }
|
2011-06-27 18:35:01 -07:00
|
|
|
}
|
|
|
|
|
2011-09-02 15:12:27 -07:00
|
|
|
let llcmpresultptr = alloca(bcx, T_i1());
|
2011-10-20 11:56:45 +02:00
|
|
|
Call(bcx, llfn, [llcmpresultptr, lltydesc, lltydescs,
|
2011-10-20 11:42:40 +02:00
|
|
|
llrawlhsptr, llrawrhsptr, llop]);
|
2011-09-02 15:12:27 -07:00
|
|
|
ret rslt(bcx, Load(bcx, llcmpresultptr));
|
2011-04-19 15:22:57 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn take_ty(cx: @block_ctxt, v: ValueRef, t: ty::t) -> @block_ctxt {
|
2011-11-22 13:16:23 +01:00
|
|
|
if ty::type_needs_drop(bcx_tcx(cx), t) {
|
2011-08-19 10:24:13 +02:00
|
|
|
ret call_tydesc_glue(cx, v, t, abi::tydesc_field_take_glue);
|
2010-12-17 18:20:10 -08:00
|
|
|
}
|
2011-08-30 13:50:58 +02:00
|
|
|
ret cx;
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn drop_ty(cx: @block_ctxt, v: ValueRef, t: ty::t) -> @block_ctxt {
|
2011-07-29 12:53:58 +02:00
|
|
|
if ty::type_needs_drop(bcx_tcx(cx), 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
|
|
|
}
|
2011-08-30 13:50:58 +02:00
|
|
|
ret cx;
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
|
|
|
|
2011-10-10 10:58:53 +02:00
|
|
|
fn drop_ty_immediate(bcx: @block_ctxt, v: ValueRef, t: ty::t) -> @block_ctxt {
|
|
|
|
alt ty::struct(bcx_tcx(bcx), t) {
|
2012-01-18 22:37:22 -08:00
|
|
|
ty::ty_uniq(_) | ty::ty_vec(_) | ty::ty_str { free_ty(bcx, v, t) }
|
2012-01-07 22:44:14 +01:00
|
|
|
ty::ty_box(_) | ty::ty_iface(_, _) { decr_refcnt_maybe_free(bcx, v, t) }
|
2011-10-10 10:58:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn take_ty_immediate(bcx: @block_ctxt, v: ValueRef, t: ty::t) -> result {
|
|
|
|
alt ty::struct(bcx_tcx(bcx), t) {
|
2012-01-07 22:44:14 +01:00
|
|
|
ty::ty_box(_) | ty::ty_iface(_, _) {
|
|
|
|
rslt(incr_refcnt_of_boxed(bcx, v), v)
|
|
|
|
}
|
2011-10-10 10:58:53 +02:00
|
|
|
ty::ty_uniq(_) {
|
|
|
|
check trans_uniq::type_is_unique_box(bcx, t);
|
2012-01-07 22:44:14 +01:00
|
|
|
trans_uniq::duplicate(bcx, v, t)
|
2011-10-10 10:58:53 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ty::ty_str | ty::ty_vec(_) { tvec::duplicate(bcx, v, t) }
|
2012-01-07 22:44:14 +01:00
|
|
|
_ { rslt(bcx, v) }
|
2011-10-10 10:58:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn free_ty(cx: @block_ctxt, v: ValueRef, t: ty::t) -> @block_ctxt {
|
2011-11-22 13:16:23 +01:00
|
|
|
if ty::type_needs_drop(bcx_tcx(cx), 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
|
|
|
}
|
2011-08-30 13:50:58 +02:00
|
|
|
ret cx;
|
2011-05-18 17:28:08 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn call_memmove(cx: @block_ctxt, dst: ValueRef, src: ValueRef,
|
2011-07-27 14:19:39 +02:00
|
|
|
n_bytes: ValueRef) -> result {
|
2011-06-18 16:59:44 -07:00
|
|
|
// TODO: Provide LLVM with better alignment information when the alignment
|
|
|
|
// is statically known (it must be nothing more than a constant int, or
|
|
|
|
// LLVM complains -- not even a constant element of a tydesc works).
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-10-14 16:45:25 -07:00
|
|
|
let ccx = bcx_ccx(cx);
|
2012-01-12 17:59:49 +01:00
|
|
|
let key = alt ccx.sess.targ_cfg.arch {
|
2012-01-19 01:03:57 -08:00
|
|
|
session::arch_x86 | session::arch_arm { "llvm.memmove.p0i8.p0i8.i32" }
|
|
|
|
session::arch_x86_64 { "llvm.memmove.p0i8.p0i8.i64" }
|
2011-10-26 17:09:07 -07:00
|
|
|
};
|
2011-10-14 16:45:25 -07:00
|
|
|
let i = ccx.intrinsics;
|
2011-10-26 17:09:07 -07:00
|
|
|
assert (i.contains_key(key));
|
|
|
|
let memmove = i.get(key);
|
2011-08-30 09:59:30 +02:00
|
|
|
let src_ptr = PointerCast(cx, src, T_ptr(T_i8()));
|
|
|
|
let dst_ptr = PointerCast(cx, dst, T_ptr(T_i8()));
|
2011-11-17 13:43:34 -08:00
|
|
|
// FIXME #1184: Resource flag is larger than necessary
|
2011-10-26 17:09:07 -07:00
|
|
|
let size = IntCast(cx, n_bytes, ccx.int_type);
|
|
|
|
let align = C_i32(1i32);
|
2011-07-27 14:19:39 +02:00
|
|
|
let volatile = C_bool(false);
|
2011-10-31 14:43:31 -07:00
|
|
|
let ret_val = Call(cx, memmove, [dst_ptr, src_ptr, size,
|
|
|
|
align, volatile]);
|
2011-10-26 17:09:07 -07:00
|
|
|
ret rslt(cx, ret_val);
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
|
|
|
|
2012-01-05 12:05:22 -08:00
|
|
|
fn memmove_ty(bcx: @block_ctxt, dst: ValueRef, src: ValueRef, t: ty::t) ->
|
2011-09-21 12:40:27 +02:00
|
|
|
@block_ctxt {
|
2012-01-05 12:05:22 -08:00
|
|
|
let ccx = bcx_ccx(bcx);
|
2011-09-02 18:59:22 -07:00
|
|
|
if check type_has_static_size(ccx, t) {
|
2012-01-05 12:05:22 -08:00
|
|
|
if ty::type_is_structural(bcx_tcx(bcx), t) {
|
|
|
|
let sp = bcx.sp;
|
2011-10-14 16:45:25 -07:00
|
|
|
let llsz = llsize_of(ccx, type_of(ccx, sp, t));
|
2012-01-05 12:05:22 -08:00
|
|
|
ret call_memmove(bcx, dst, src, llsz).bcx;
|
2011-09-07 12:10:37 -07:00
|
|
|
}
|
2012-01-05 12:05:22 -08:00
|
|
|
Store(bcx, Load(bcx, src), dst);
|
|
|
|
ret bcx;
|
2011-09-02 18:59:22 -07:00
|
|
|
}
|
2011-09-07 12:10:37 -07:00
|
|
|
|
2012-01-06 19:39:18 -08:00
|
|
|
let {bcx, val: llsz} = size_of(bcx, t);
|
2012-01-05 12:05:22 -08:00
|
|
|
ret call_memmove(bcx, dst, src, llsz).bcx;
|
2011-01-17 13:30:29 -08:00
|
|
|
}
|
|
|
|
|
2012-01-19 17:56:05 -08:00
|
|
|
enum copy_action { INIT, DROP_EXISTING, }
|
2011-06-10 13:39:13 -07:00
|
|
|
|
2011-08-22 12:38:58 +02:00
|
|
|
// These are the types that are passed by pointer.
|
2011-09-12 11:27:30 +02:00
|
|
|
fn type_is_structural_or_param(tcx: ty::ctxt, t: ty::t) -> bool {
|
2011-08-22 12:38:58 +02:00
|
|
|
if ty::type_is_structural(tcx, t) { ret true; }
|
|
|
|
alt ty::struct(tcx, t) {
|
|
|
|
ty::ty_param(_, _) { ret true; }
|
|
|
|
_ { ret false; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn copy_val(cx: @block_ctxt, action: copy_action, dst: ValueRef,
|
2011-08-22 12:45:18 +02:00
|
|
|
src: ValueRef, t: ty::t) -> @block_ctxt {
|
2011-09-27 20:20:51 +02:00
|
|
|
if action == DROP_EXISTING &&
|
|
|
|
(type_is_structural_or_param(bcx_tcx(cx), t) ||
|
|
|
|
ty::type_is_unique(bcx_tcx(cx), t)) {
|
2011-09-02 15:34:58 -07:00
|
|
|
let do_copy_cx = new_sub_block_ctxt(cx, "do_copy");
|
|
|
|
let next_cx = new_sub_block_ctxt(cx, "next");
|
2011-09-27 20:20:51 +02:00
|
|
|
let dstcmp = load_if_immediate(cx, dst, t);
|
2011-08-22 12:38:58 +02:00
|
|
|
let self_assigning =
|
2011-09-27 20:20:51 +02:00
|
|
|
ICmp(cx, lib::llvm::LLVMIntNE,
|
|
|
|
PointerCast(cx, dstcmp, val_ty(src)), src);
|
2011-08-30 09:59:30 +02:00
|
|
|
CondBr(cx, self_assigning, do_copy_cx.llbb, next_cx.llbb);
|
2011-08-22 12:38:58 +02:00
|
|
|
do_copy_cx = copy_val_no_check(do_copy_cx, action, dst, src, t);
|
2011-08-30 09:59:30 +02:00
|
|
|
Br(do_copy_cx, next_cx.llbb);
|
2011-08-22 12:38:58 +02:00
|
|
|
ret next_cx;
|
|
|
|
}
|
|
|
|
ret copy_val_no_check(cx, action, dst, src, t);
|
|
|
|
}
|
|
|
|
|
2011-10-10 13:32:50 +02:00
|
|
|
fn copy_val_no_check(bcx: @block_ctxt, action: copy_action, dst: ValueRef,
|
2011-08-22 12:45:18 +02:00
|
|
|
src: ValueRef, t: ty::t) -> @block_ctxt {
|
2011-11-03 10:57:54 +01:00
|
|
|
let ccx = bcx_ccx(bcx), bcx = bcx;
|
2011-07-27 14:19:39 +02:00
|
|
|
if ty::type_is_scalar(ccx.tcx, t) || ty::type_is_native(ccx.tcx, t) {
|
2011-10-10 13:32:50 +02:00
|
|
|
Store(bcx, src, dst);
|
|
|
|
ret bcx;
|
2011-09-07 12:10:37 -07:00
|
|
|
}
|
2011-10-10 13:32:50 +02:00
|
|
|
if ty::type_is_nil(ccx.tcx, t) || ty::type_is_bot(ccx.tcx, t) { ret bcx; }
|
2011-10-12 10:14:21 +02:00
|
|
|
if ty::type_is_boxed(ccx.tcx, t) || ty::type_is_vec(ccx.tcx, t) ||
|
|
|
|
ty::type_is_unique_box(ccx.tcx, t) {
|
2011-10-10 13:32:50 +02:00
|
|
|
if action == DROP_EXISTING { bcx = drop_ty(bcx, dst, t); }
|
2011-08-30 09:59:30 +02:00
|
|
|
Store(bcx, src, dst);
|
2011-09-07 12:10:37 -07:00
|
|
|
ret take_ty(bcx, dst, t);
|
|
|
|
}
|
2011-10-10 13:32:50 +02:00
|
|
|
if type_is_structural_or_param(ccx.tcx, t) {
|
|
|
|
if action == DROP_EXISTING { bcx = drop_ty(bcx, dst, t); }
|
2011-09-21 12:40:27 +02:00
|
|
|
bcx = memmove_ty(bcx, dst, src, t);
|
2011-08-30 13:50:58 +02:00
|
|
|
ret take_ty(bcx, dst, t);
|
2011-08-22 12:38:58 +02:00
|
|
|
}
|
2011-09-02 15:34:58 -07:00
|
|
|
ccx.sess.bug("unexpected type in trans::copy_val_no_check: " +
|
|
|
|
ty_to_str(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-07-27 14:19:39 +02:00
|
|
|
fn move_val(cx: @block_ctxt, action: copy_action, dst: ValueRef,
|
2011-09-12 11:27:30 +02:00
|
|
|
src: lval_result, t: ty::t) -> @block_ctxt {
|
2011-09-16 16:27:34 +02:00
|
|
|
let src_val = src.val;
|
2011-11-03 10:57:54 +01:00
|
|
|
let tcx = bcx_tcx(cx), cx = cx;
|
2011-09-02 15:34:58 -07:00
|
|
|
if ty::type_is_scalar(tcx, t) || ty::type_is_native(tcx, t) {
|
2011-10-07 11:20:51 +02:00
|
|
|
if src.kind == owned { src_val = Load(cx, src_val); }
|
2011-08-30 09:59:30 +02:00
|
|
|
Store(cx, src_val, dst);
|
2011-08-22 12:38:58 +02:00
|
|
|
ret cx;
|
2011-08-22 14:00:41 +02:00
|
|
|
} else if ty::type_is_nil(tcx, t) || ty::type_is_bot(tcx, t) {
|
2011-08-22 12:38:58 +02:00
|
|
|
ret cx;
|
2011-10-10 13:32:50 +02:00
|
|
|
} else if ty::type_is_boxed(tcx, t) || ty::type_is_unique(tcx, t) {
|
2011-10-07 11:20:51 +02:00
|
|
|
if src.kind == owned { src_val = Load(cx, src_val); }
|
2011-09-02 15:34:58 -07:00
|
|
|
if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); }
|
2011-08-30 09:59:30 +02:00
|
|
|
Store(cx, src_val, dst);
|
2011-10-07 11:20:51 +02:00
|
|
|
if src.kind == owned { ret zero_alloca(cx, src.val, t); }
|
2011-08-16 12:38:42 -07:00
|
|
|
// If we're here, it must be a temporary.
|
2011-11-18 15:10:14 +01:00
|
|
|
revoke_clean(cx, src_val);
|
|
|
|
ret cx;
|
2011-10-10 13:32:50 +02:00
|
|
|
} else if type_is_structural_or_param(tcx, t) {
|
2011-08-30 13:50:58 +02:00
|
|
|
if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); }
|
2011-09-21 12:40:27 +02:00
|
|
|
cx = memmove_ty(cx, dst, src_val, t);
|
2011-10-07 11:20:51 +02:00
|
|
|
if src.kind == owned { ret zero_alloca(cx, src_val, t); }
|
2011-09-07 18:16:08 -07:00
|
|
|
// If we're here, it must be a temporary.
|
2011-11-18 15:10:14 +01:00
|
|
|
revoke_clean(cx, src_val);
|
|
|
|
ret cx;
|
2011-05-31 14:36:08 -07:00
|
|
|
}
|
2011-09-16 10:49:05 -07:00
|
|
|
/* FIXME: suggests a type constraint */
|
2011-09-02 15:34:58 -07:00
|
|
|
bcx_ccx(cx).sess.bug("unexpected type in trans::move_val: " +
|
|
|
|
ty_to_str(tcx, t));
|
Make moving of temporaries do the right thing, use it to optimize
This adds support for dropping cleanups for temporary values when they
are moved somewhere else. It then adds wraps most copy operations
(return, put in data structure, box, etc) in a way that will fall back
to a move when it is safe.
This saves a lot of taking/dropping, shaving over a megabyte off the
stage2/rustc binary size.
In some cases, most notably function returns, we could detect that the
returned value is a local variable, and can thus be safely moved even
though it is not a temporary. This will require putting some more
information in lvals.
I did not yet handle function arguments, since the logic for passing
them looked too convoluted to touch. I'll probably try that in the
near future, since it's bound to be a big win.
2011-07-07 13:36:12 +02:00
|
|
|
}
|
|
|
|
|
2011-10-05 12:23:18 +02:00
|
|
|
fn store_temp_expr(cx: @block_ctxt, action: copy_action, dst: ValueRef,
|
2011-11-18 15:10:14 +01:00
|
|
|
src: lval_result, t: ty::t, last_use: bool)
|
|
|
|
-> @block_ctxt {
|
Make moving of temporaries do the right thing, use it to optimize
This adds support for dropping cleanups for temporary values when they
are moved somewhere else. It then adds wraps most copy operations
(return, put in data structure, box, etc) in a way that will fall back
to a move when it is safe.
This saves a lot of taking/dropping, shaving over a megabyte off the
stage2/rustc binary size.
In some cases, most notably function returns, we could detect that the
returned value is a local variable, and can thus be safely moved even
though it is not a temporary. This will require putting some more
information in lvals.
I did not yet handle function arguments, since the logic for passing
them looked too convoluted to touch. I'll probably try that in the
near future, since it's bound to be a big win.
2011-07-07 13:36:12 +02:00
|
|
|
// Lvals in memory are not temporaries. Copy them.
|
2011-11-18 15:10:14 +01:00
|
|
|
if src.kind != temporary && !last_use {
|
2011-10-07 11:20:51 +02:00
|
|
|
let v = src.kind == owned ? load_if_immediate(cx, src.val, t)
|
|
|
|
: src.val;
|
|
|
|
ret copy_val(cx, action, dst, v, t);
|
2011-08-16 12:38:42 -07:00
|
|
|
}
|
|
|
|
ret move_val(cx, action, dst, src, t);
|
2011-05-31 14:36:08 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trans_crate_lit(cx: @crate_ctxt, lit: ast::lit) -> ValueRef {
|
2011-07-27 14:19:39 +02:00
|
|
|
alt lit.node {
|
2011-12-07 21:06:12 +01:00
|
|
|
ast::lit_int(i, t) { C_integral(T_int_ty(cx, t), i as u64, True) }
|
|
|
|
ast::lit_uint(u, t) { C_integral(T_uint_ty(cx, t), u, False) }
|
|
|
|
ast::lit_float(fs, t) { C_floating(fs, T_float_ty(cx, t)) }
|
|
|
|
ast::lit_bool(b) { C_bool(b) }
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::lit_nil { C_nil() }
|
2011-09-01 22:08:59 -07:00
|
|
|
ast::lit_str(s) {
|
2011-09-02 15:34:58 -07:00
|
|
|
cx.sess.span_unimpl(lit.span, "unique string in this context");
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-07-14 11:47:20 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-27 08:42:27 +02:00
|
|
|
fn trans_lit(cx: @block_ctxt, lit: ast::lit, dest: dest) -> @block_ctxt {
|
|
|
|
if dest == ignore { ret cx; }
|
2011-07-27 14:19:39 +02:00
|
|
|
alt lit.node {
|
2011-09-27 08:42:27 +02:00
|
|
|
ast::lit_str(s) { ret tvec::trans_str(cx, s, dest); }
|
|
|
|
_ {
|
2011-09-27 10:50:18 +02:00
|
|
|
ret store_in_dest(cx, trans_crate_lit(bcx_ccx(cx), lit), dest);
|
2011-09-27 08:42:27 +02:00
|
|
|
}
|
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-09-12 11:27:30 +02:00
|
|
|
fn node_id_type(cx: @crate_ctxt, id: ast::node_id) -> ty::t {
|
2011-06-19 22:41:21 +02:00
|
|
|
ret ty::node_id_to_monotype(cx.tcx, id);
|
2010-11-05 18:31:02 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn node_type(cx: @crate_ctxt, sp: span, id: ast::node_id) -> TypeRef {
|
2011-09-02 18:59:22 -07:00
|
|
|
let ty = node_id_type(cx, id);
|
|
|
|
// How to make this a precondition?
|
|
|
|
// FIXME (again, would require a predicate that implies
|
|
|
|
// another predicate)
|
2011-09-12 11:27:30 +02:00
|
|
|
check (type_has_static_size(cx, ty));
|
2011-09-02 18:59:22 -07:00
|
|
|
type_of(cx, sp, ty)
|
2010-11-22 16:27:00 -08:00
|
|
|
}
|
|
|
|
|
2011-09-27 13:19:55 +02:00
|
|
|
fn trans_unary(bcx: @block_ctxt, op: ast::unop, e: @ast::expr,
|
|
|
|
id: ast::node_id, dest: dest) -> @block_ctxt {
|
2011-10-05 11:26:27 +02:00
|
|
|
if dest == ignore { ret trans_expr(bcx, e, ignore); }
|
2011-09-27 13:19:55 +02:00
|
|
|
let e_ty = ty::expr_ty(bcx_tcx(bcx), e);
|
2011-07-27 14:19:39 +02:00
|
|
|
alt op {
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::not {
|
2011-10-05 11:26:27 +02:00
|
|
|
let {bcx, val} = trans_temp_expr(bcx, e);
|
2011-09-27 13:19:55 +02:00
|
|
|
ret store_in_dest(bcx, Not(bcx, val), dest);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::neg {
|
2011-10-05 11:26:27 +02:00
|
|
|
let {bcx, val} = trans_temp_expr(bcx, e);
|
2011-10-09 10:07:10 +02:00
|
|
|
let neg = if ty::type_is_fp(bcx_tcx(bcx), e_ty) {
|
2011-09-27 13:19:55 +02:00
|
|
|
FNeg(bcx, val)
|
|
|
|
} else { Neg(bcx, val) };
|
|
|
|
ret store_in_dest(bcx, neg, dest);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
ast::box(_) {
|
2011-09-27 13:19:55 +02:00
|
|
|
let {bcx, box, body} = trans_malloc_boxed(bcx, e_ty);
|
|
|
|
add_clean_free(bcx, box, false);
|
2011-07-27 14:19:39 +02: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
|
2012-01-18 22:37:22 -08:00
|
|
|
// on whether they're boxed or not
|
2011-09-27 13:19:55 +02:00
|
|
|
let ccx = bcx_ccx(bcx);
|
|
|
|
if check type_has_static_size(ccx, e_ty) {
|
2011-09-02 18:59:22 -07:00
|
|
|
let e_sp = e.span;
|
2011-09-27 13:19:55 +02:00
|
|
|
let llety = T_ptr(type_of(ccx, e_sp, e_ty));
|
|
|
|
body = PointerCast(bcx, body, llety);
|
|
|
|
}
|
2011-10-05 10:21:48 +02:00
|
|
|
bcx = trans_expr_save_in(bcx, e, body);
|
2011-09-27 13:19:55 +02:00
|
|
|
revoke_clean(bcx, box);
|
|
|
|
ret store_in_dest(bcx, box, dest);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-09-20 18:06:47 -07:00
|
|
|
ast::uniq(_) {
|
2011-09-27 13:19:55 +02:00
|
|
|
ret trans_uniq::trans_uniq(bcx, e, id, dest);
|
2011-09-20 18:06:47 -07:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::deref {
|
2011-09-27 13:19:55 +02:00
|
|
|
bcx_ccx(bcx).sess.bug("deref expressions should have been \
|
|
|
|
translated using trans_lval(), not \
|
|
|
|
trans_unary()");
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trans_compare(cx: @block_ctxt, op: ast::binop, lhs: ValueRef,
|
2011-08-19 15:16:48 -07:00
|
|
|
_lhs_t: ty::t, rhs: ValueRef, rhs_t: ty::t) -> result {
|
2011-10-27 22:01:30 -07:00
|
|
|
if ty::type_is_scalar(bcx_tcx(cx), rhs_t) {
|
|
|
|
let rs = compare_scalar_types(cx, lhs, rhs, rhs_t, op);
|
|
|
|
ret rslt(rs.bcx, rs.val);
|
|
|
|
}
|
|
|
|
|
2011-04-19 15:22:57 -07:00
|
|
|
// Determine the operation we need.
|
2011-07-27 14:19:39 +02:00
|
|
|
let llop;
|
|
|
|
alt op {
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::eq | ast::ne { llop = C_u8(abi::cmp_glue_op_eq); }
|
|
|
|
ast::lt | ast::ge { llop = C_u8(abi::cmp_glue_op_lt); }
|
|
|
|
ast::le | ast::gt { llop = C_u8(abi::cmp_glue_op_le); }
|
2011-02-28 16:36:08 -08:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
|
2011-10-27 22:01:30 -07:00
|
|
|
let rs = call_cmp_glue(cx, lhs, rhs, rhs_t, llop);
|
2011-02-28 16:36:08 -08:00
|
|
|
|
2011-08-02 18:04:24 -07:00
|
|
|
// Invert the result if necessary.
|
|
|
|
alt op {
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::eq | ast::lt | ast::le { ret rslt(rs.bcx, rs.val); }
|
|
|
|
ast::ne | ast::ge | ast::gt {
|
2011-08-30 09:59:30 +02:00
|
|
|
ret rslt(rs.bcx, Not(rs.bcx, rs.val));
|
2011-08-02 18:04:24 -07:00
|
|
|
}
|
2011-02-10 19:40:02 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-02 17:21:28 -07:00
|
|
|
// Important to get types for both lhs and rhs, because one might be _|_
|
|
|
|
// and the other not.
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trans_eager_binop(cx: @block_ctxt, op: ast::binop, lhs: ValueRef,
|
2011-09-27 10:50:18 +02:00
|
|
|
lhs_t: ty::t, rhs: ValueRef, rhs_t: ty::t, dest: dest)
|
|
|
|
-> @block_ctxt {
|
|
|
|
if dest == ignore { ret cx; }
|
2011-08-02 17:21:28 -07:00
|
|
|
let intype = lhs_t;
|
2011-08-19 15:16:48 -07:00
|
|
|
if ty::type_is_bot(bcx_tcx(cx), intype) { intype = rhs_t; }
|
2011-10-09 10:07:10 +02:00
|
|
|
let is_float = ty::type_is_fp(bcx_tcx(cx), intype);
|
2011-08-02 17:21:28 -07:00
|
|
|
|
2011-09-27 10:50:18 +02:00
|
|
|
if op == ast::add && ty::type_is_sequence(bcx_tcx(cx), intype) {
|
|
|
|
ret tvec::trans_add(cx, intype, lhs, rhs, dest);
|
|
|
|
}
|
2011-11-03 10:57:54 +01:00
|
|
|
let cx = cx, val = alt op {
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::add {
|
2011-09-27 10:50:18 +02:00
|
|
|
if is_float { FAdd(cx, lhs, rhs) }
|
|
|
|
else { Add(cx, lhs, rhs) }
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::subtract {
|
2011-09-27 10:50:18 +02:00
|
|
|
if is_float { FSub(cx, lhs, rhs) }
|
|
|
|
else { Sub(cx, lhs, rhs) }
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::mul {
|
2011-09-27 10:50:18 +02:00
|
|
|
if is_float { FMul(cx, lhs, rhs) }
|
|
|
|
else { Mul(cx, lhs, rhs) }
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::div {
|
2011-09-27 10:50:18 +02:00
|
|
|
if is_float { FDiv(cx, lhs, rhs) }
|
|
|
|
else if ty::type_is_signed(bcx_tcx(cx), intype) {
|
|
|
|
SDiv(cx, lhs, rhs)
|
|
|
|
} else { UDiv(cx, lhs, rhs) }
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::rem {
|
2011-09-27 10:50:18 +02:00
|
|
|
if is_float { FRem(cx, lhs, rhs) }
|
|
|
|
else if ty::type_is_signed(bcx_tcx(cx), intype) {
|
|
|
|
SRem(cx, lhs, rhs)
|
|
|
|
} else { URem(cx, lhs, rhs) }
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::bitor { Or(cx, lhs, rhs) }
|
|
|
|
ast::bitand { And(cx, lhs, rhs) }
|
|
|
|
ast::bitxor { Xor(cx, lhs, rhs) }
|
|
|
|
ast::lsl { Shl(cx, lhs, rhs) }
|
|
|
|
ast::lsr { LShr(cx, lhs, rhs) }
|
|
|
|
ast::asr { AShr(cx, lhs, rhs) }
|
2011-09-27 10:50:18 +02:00
|
|
|
_ {
|
|
|
|
let cmpr = trans_compare(cx, op, lhs, lhs_t, rhs, rhs_t);
|
|
|
|
cx = cmpr.bcx;
|
|
|
|
cmpr.val
|
|
|
|
}
|
|
|
|
};
|
|
|
|
ret store_in_dest(cx, val, dest);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
|
2011-09-27 08:03:06 +02:00
|
|
|
fn trans_assign_op(bcx: @block_ctxt, op: ast::binop, dst: @ast::expr,
|
|
|
|
src: @ast::expr) -> @block_ctxt {
|
|
|
|
let tcx = bcx_tcx(bcx);
|
|
|
|
let t = ty::expr_ty(tcx, src);
|
|
|
|
let lhs_res = trans_lval(bcx, dst);
|
2011-10-07 11:20:51 +02:00
|
|
|
assert (lhs_res.kind == owned);
|
2011-09-27 08:03:06 +02:00
|
|
|
// Special case for `+= [x]`
|
|
|
|
alt ty::struct(tcx, t) {
|
|
|
|
ty::ty_vec(_) {
|
|
|
|
alt src.node {
|
|
|
|
ast::expr_vec(args, _) {
|
|
|
|
ret tvec::trans_append_literal(lhs_res.bcx,
|
|
|
|
lhs_res.val, t, args);
|
|
|
|
}
|
|
|
|
_ { }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ { }
|
|
|
|
}
|
2011-10-05 11:26:27 +02:00
|
|
|
let {bcx, val: rhs_val} = trans_temp_expr(lhs_res.bcx, src);
|
2011-09-27 08:03:06 +02:00
|
|
|
if ty::type_is_sequence(tcx, t) {
|
|
|
|
alt op {
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::add {
|
2011-10-05 10:21:48 +02:00
|
|
|
ret tvec::trans_append(bcx, t, lhs_res.val, rhs_val);
|
2011-09-27 08:03:06 +02:00
|
|
|
}
|
|
|
|
_ { }
|
|
|
|
}
|
|
|
|
}
|
2011-10-05 10:21:48 +02:00
|
|
|
ret trans_eager_binop(bcx, op, Load(bcx, lhs_res.val), t, rhs_val, t,
|
|
|
|
save_in(lhs_res.val));
|
2011-09-27 08:03:06 +02:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn autoderef(cx: @block_ctxt, v: ValueRef, t: ty::t) -> result_t {
|
2011-07-27 14:19:39 +02:00
|
|
|
let v1: ValueRef = v;
|
|
|
|
let t1: ty::t = t;
|
|
|
|
let ccx = bcx_ccx(cx);
|
2011-09-02 18:59:22 -07:00
|
|
|
let sp = cx.sp;
|
2011-07-27 14:19:39 +02:00
|
|
|
while true {
|
|
|
|
alt ty::struct(ccx.tcx, t1) {
|
|
|
|
ty::ty_box(mt) {
|
2011-10-25 22:23:28 -07:00
|
|
|
let body = GEPi(cx, v1, [0, abi::box_rc_field_body]);
|
2011-07-27 14:19:39 +02:00
|
|
|
t1 = mt.ty;
|
|
|
|
|
|
|
|
// Since we're changing levels of box indirection, we may have
|
2012-01-19 14:24:03 -08:00
|
|
|
// to cast this pointer, since statically-sized enum types have
|
2011-07-27 14:19:39 +02:00
|
|
|
// different types depending on whether they're behind a box
|
|
|
|
// or not.
|
2011-09-02 18:59:22 -07:00
|
|
|
if check type_has_static_size(ccx, t1) {
|
|
|
|
let llty = type_of(ccx, sp, t1);
|
2011-08-30 09:59:30 +02:00
|
|
|
v1 = PointerCast(cx, body, T_ptr(llty));
|
2011-07-27 14:19:39 +02:00
|
|
|
} else { v1 = body; }
|
|
|
|
}
|
2011-09-22 16:04:27 -07:00
|
|
|
ty::ty_uniq(_) {
|
|
|
|
check trans_uniq::type_is_unique_box(cx, t1);
|
|
|
|
let derefed = trans_uniq::autoderef(cx, v1, t1);
|
|
|
|
t1 = derefed.t;
|
|
|
|
v1 = derefed.v;
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
ty::ty_res(did, inner, tps) {
|
|
|
|
t1 = ty::substitute_type_params(ccx.tcx, tps, inner);
|
2011-10-25 22:23:28 -07:00
|
|
|
v1 = GEPi(cx, v1, [0, 1]);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
ty::ty_tag(did, tps) {
|
|
|
|
let variants = ty::tag_variants(ccx.tcx, did);
|
2011-12-15 17:14:58 -08:00
|
|
|
if vec::len(*variants) != 1u ||
|
2011-12-13 16:25:51 -08:00
|
|
|
vec::len(variants[0].args) != 1u {
|
2011-07-27 14:19:39 +02:00
|
|
|
break;
|
2011-07-01 13:57:03 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
t1 =
|
2011-08-19 15:16:48 -07:00
|
|
|
ty::substitute_type_params(ccx.tcx, tps, variants[0].args[0]);
|
2011-09-02 18:59:22 -07:00
|
|
|
if check type_has_static_size(ccx, t1) {
|
|
|
|
v1 = PointerCast(cx, v1, T_ptr(type_of(ccx, sp, t1)));
|
2011-09-12 11:27:30 +02:00
|
|
|
} else { } // FIXME: typestate hack
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ { break; }
|
2011-01-24 18:03:31 -08:00
|
|
|
}
|
2011-07-11 13:12:44 -05:00
|
|
|
v1 = load_if_immediate(cx, v1, t1);
|
2011-01-24 18:03:31 -08:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
ret {bcx: cx, val: v1, ty: t1};
|
2011-01-24 18:03:31 -08:00
|
|
|
}
|
|
|
|
|
2011-09-27 10:50:18 +02:00
|
|
|
fn trans_lazy_binop(bcx: @block_ctxt, op: ast::binop, a: @ast::expr,
|
|
|
|
b: @ast::expr, dest: dest) -> @block_ctxt {
|
2012-01-18 22:37:22 -08:00
|
|
|
let is_and = alt op { ast::and { true } ast::or { false } };
|
2011-10-05 11:26:27 +02:00
|
|
|
let lhs_res = trans_temp_expr(bcx, a);
|
2011-09-27 10:50:18 +02:00
|
|
|
if lhs_res.bcx.unreachable { ret lhs_res.bcx; }
|
|
|
|
let rhs_cx = new_scope_block_ctxt(lhs_res.bcx, "rhs");
|
2011-10-05 11:26:27 +02:00
|
|
|
let rhs_res = trans_temp_expr(rhs_cx, b);
|
2011-09-27 10:50:18 +02:00
|
|
|
|
|
|
|
let lhs_past_cx = new_scope_block_ctxt(lhs_res.bcx, "lhs");
|
|
|
|
// The following line ensures that any cleanups for rhs
|
|
|
|
// are done within the block for rhs. This is necessary
|
|
|
|
// because and/or are lazy. So the rhs may never execute,
|
|
|
|
// and the cleanups can't be pushed into later code.
|
|
|
|
let rhs_bcx = trans_block_cleanups(rhs_res.bcx, rhs_cx);
|
|
|
|
if is_and {
|
|
|
|
CondBr(lhs_res.bcx, lhs_res.val, rhs_cx.llbb, lhs_past_cx.llbb);
|
|
|
|
} else {
|
|
|
|
CondBr(lhs_res.bcx, lhs_res.val, lhs_past_cx.llbb, rhs_cx.llbb);
|
|
|
|
}
|
|
|
|
|
|
|
|
let join_cx = new_sub_block_ctxt(bcx, "join");
|
|
|
|
Br(lhs_past_cx, join_cx.llbb);
|
|
|
|
if rhs_bcx.unreachable {
|
|
|
|
ret store_in_dest(join_cx, C_bool(!is_and), dest);
|
|
|
|
}
|
|
|
|
Br(rhs_bcx, join_cx.llbb);
|
|
|
|
let phi = Phi(join_cx, T_bool(), [C_bool(!is_and), rhs_res.val],
|
|
|
|
[lhs_past_cx.llbb, rhs_bcx.llbb]);
|
|
|
|
ret store_in_dest(join_cx, phi, dest);
|
|
|
|
}
|
2011-08-19 15:16:48 -07:00
|
|
|
|
2011-09-27 10:50:18 +02:00
|
|
|
fn trans_binary(cx: @block_ctxt, op: ast::binop, a: @ast::expr, b: @ast::expr,
|
|
|
|
dest: dest) -> @block_ctxt {
|
2010-10-19 17:24:15 -07:00
|
|
|
// First couple cases are lazy:
|
2011-07-27 14:19:39 +02:00
|
|
|
alt op {
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::and | ast::or {
|
2011-09-27 10:50:18 +02:00
|
|
|
ret trans_lazy_binop(cx, op, a, b, dest);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ {
|
|
|
|
// Remaining cases are eager:
|
2011-10-05 11:26:27 +02:00
|
|
|
let lhs = trans_temp_expr(cx, a);
|
|
|
|
let rhs = trans_temp_expr(lhs.bcx, b);
|
2011-08-19 15:16:48 -07:00
|
|
|
ret trans_eager_binop(rhs.bcx, op, lhs.val,
|
|
|
|
ty::expr_ty(bcx_tcx(cx), a), rhs.val,
|
2011-09-27 10:50:18 +02:00
|
|
|
ty::expr_ty(bcx_tcx(cx), b), dest);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-19 14:24:03 -08:00
|
|
|
enum dest {
|
2012-01-19 17:56:05 -08:00
|
|
|
by_val(@mutable ValueRef),
|
|
|
|
save_in(ValueRef),
|
|
|
|
ignore,
|
2011-09-23 21:13:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn empty_dest_cell() -> @mutable ValueRef {
|
|
|
|
ret @mutable llvm::LLVMGetUndef(T_nil());
|
|
|
|
}
|
|
|
|
|
|
|
|
fn dup_for_join(dest: dest) -> dest {
|
|
|
|
alt dest {
|
|
|
|
by_val(_) { by_val(empty_dest_cell()) }
|
|
|
|
_ { dest }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn join_returns(parent_cx: @block_ctxt, in_cxs: [@block_ctxt],
|
|
|
|
in_ds: [dest], out_dest: dest) -> @block_ctxt {
|
|
|
|
let out = new_sub_block_ctxt(parent_cx, "join");
|
|
|
|
let reachable = false, i = 0u, phi = none;
|
|
|
|
for cx in in_cxs {
|
|
|
|
if !cx.unreachable {
|
|
|
|
Br(cx, out.llbb);
|
|
|
|
reachable = true;
|
|
|
|
alt in_ds[i] {
|
2011-10-05 10:41:30 +02:00
|
|
|
by_val(cell) {
|
2011-09-23 21:13:50 +02:00
|
|
|
if option::is_none(phi) {
|
|
|
|
phi = some(EmptyPhi(out, val_ty(*cell)));
|
|
|
|
}
|
2011-09-23 23:20:19 +02:00
|
|
|
AddIncomingToPhi(option::get(phi), *cell, cx.llbb);
|
2011-09-23 21:13:50 +02:00
|
|
|
}
|
|
|
|
_ {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
if !reachable {
|
|
|
|
Unreachable(out);
|
|
|
|
} else {
|
|
|
|
alt out_dest {
|
2011-10-05 10:41:30 +02:00
|
|
|
by_val(cell) { *cell = option::get(phi); }
|
2011-09-23 21:13:50 +02:00
|
|
|
_ {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret out;
|
|
|
|
}
|
|
|
|
|
2011-09-27 13:19:55 +02:00
|
|
|
// Used to put an immediate value in a dest.
|
2011-09-27 10:50:18 +02:00
|
|
|
fn store_in_dest(bcx: @block_ctxt, val: ValueRef, dest: dest) -> @block_ctxt {
|
|
|
|
alt dest {
|
2012-01-18 22:37:22 -08:00
|
|
|
ignore {}
|
2011-09-27 10:50:18 +02:00
|
|
|
by_val(cell) { *cell = val; }
|
|
|
|
save_in(addr) { Store(bcx, val, addr); }
|
|
|
|
}
|
|
|
|
ret bcx;
|
|
|
|
}
|
|
|
|
|
2011-10-05 10:21:48 +02:00
|
|
|
fn get_dest_addr(dest: dest) -> ValueRef {
|
|
|
|
alt dest { save_in(a) { a } }
|
2011-09-29 11:18:40 +02:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trans_if(cx: @block_ctxt, cond: @ast::expr, thn: ast::blk,
|
2011-09-23 21:13:50 +02:00
|
|
|
els: option::t<@ast::expr>, dest: dest)
|
|
|
|
-> @block_ctxt {
|
2011-10-05 11:26:27 +02:00
|
|
|
let {bcx, val: cond_val} = trans_temp_expr(cx, cond);
|
2011-08-03 13:05:46 -07:00
|
|
|
|
2011-09-23 21:13:50 +02:00
|
|
|
let then_dest = dup_for_join(dest);
|
|
|
|
let else_dest = dup_for_join(dest);
|
2011-09-21 12:40:27 +02:00
|
|
|
let then_cx = new_scope_block_ctxt(bcx, "then");
|
|
|
|
let else_cx = new_scope_block_ctxt(bcx, "else");
|
2011-09-23 21:13:50 +02:00
|
|
|
CondBr(bcx, cond_val, then_cx.llbb, else_cx.llbb);
|
|
|
|
then_cx = trans_block_dps(then_cx, thn, then_dest);
|
2011-07-27 14:48:34 +02: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-09-23 21:13:50 +02:00
|
|
|
alt els {
|
|
|
|
some(elexpr) {
|
|
|
|
alt elexpr.node {
|
|
|
|
ast::expr_if(_, _, _) {
|
|
|
|
let elseif_blk = ast_util::block_from_expr(elexpr);
|
|
|
|
else_cx = trans_block_dps(else_cx, elseif_blk, else_dest);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-09-23 21:13:50 +02:00
|
|
|
ast::expr_block(blk) {
|
|
|
|
else_cx = trans_block_dps(else_cx, blk, else_dest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ {}
|
|
|
|
}
|
|
|
|
ret join_returns(cx, [then_cx, else_cx], [then_dest, else_dest], dest);
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trans_for(cx: @block_ctxt, local: @ast::local, seq: @ast::expr,
|
2011-09-27 08:03:06 +02:00
|
|
|
body: ast::blk) -> @block_ctxt {
|
2011-09-13 12:31:16 +02:00
|
|
|
fn inner(bcx: @block_ctxt, local: @ast::local, curr: ValueRef, t: ty::t,
|
2011-09-12 11:27:30 +02:00
|
|
|
body: ast::blk, outer_next_cx: @block_ctxt) -> @block_ctxt {
|
2011-09-13 12:31:16 +02:00
|
|
|
let next_cx = new_sub_block_ctxt(bcx, "next");
|
2011-09-09 16:26:53 +02:00
|
|
|
let scope_cx =
|
2011-09-13 12:31:16 +02:00
|
|
|
new_loop_scope_block_ctxt(bcx, option::some(next_cx),
|
2011-09-09 16:26:53 +02:00
|
|
|
outer_next_cx, "for loop scope");
|
2011-09-13 12:31:16 +02:00
|
|
|
Br(bcx, scope_cx.llbb);
|
2011-11-03 10:57:54 +01:00
|
|
|
let curr = PointerCast(bcx, curr, T_ptr(type_of_or_i8(bcx, t)));
|
|
|
|
let bcx = trans_alt::bind_irrefutable_pat(scope_cx, local.node.pat,
|
|
|
|
curr, false);
|
2011-09-23 21:13:50 +02:00
|
|
|
bcx = trans_block_dps(bcx, body, ignore);
|
2011-09-21 12:40:27 +02:00
|
|
|
Br(bcx, next_cx.llbb);
|
2011-08-30 13:50:58 +02:00
|
|
|
ret next_cx;
|
2011-01-21 07:59:06 -08:00
|
|
|
}
|
2011-10-14 16:45:25 -07:00
|
|
|
let ccx = bcx_ccx(cx);
|
2011-09-02 15:34:58 -07:00
|
|
|
let next_cx = new_sub_block_ctxt(cx, "next");
|
2011-07-27 14:19:39 +02:00
|
|
|
let seq_ty = ty::expr_ty(bcx_tcx(cx), seq);
|
2011-10-05 11:26:27 +02:00
|
|
|
let {bcx: bcx, val: seq} = trans_temp_expr(cx, seq);
|
2011-10-14 20:38:24 -07:00
|
|
|
let seq = PointerCast(bcx, seq, T_ptr(ccx.opaque_vec_type));
|
2011-09-09 15:06:06 +02:00
|
|
|
let fill = tvec::get_fill(bcx, seq);
|
|
|
|
if ty::type_is_str(bcx_tcx(bcx), seq_ty) {
|
2011-10-14 16:45:25 -07:00
|
|
|
fill = Sub(bcx, fill, C_int(ccx, 1));
|
2011-09-09 15:06:06 +02:00
|
|
|
}
|
2011-10-10 13:32:50 +02:00
|
|
|
let bcx = tvec::iter_vec_raw(bcx, seq, seq_ty, fill,
|
|
|
|
bind inner(_, local, _, _, body, next_cx));
|
2011-08-30 13:50:58 +02:00
|
|
|
Br(bcx, next_cx.llbb);
|
2011-09-27 08:03:06 +02:00
|
|
|
ret next_cx;
|
2011-01-21 07:59:06 -08:00
|
|
|
}
|
|
|
|
|
2011-09-27 08:03:06 +02:00
|
|
|
fn trans_while(cx: @block_ctxt, cond: @ast::expr, body: ast::blk)
|
|
|
|
-> @block_ctxt {
|
2011-09-02 15:34:58 -07:00
|
|
|
let next_cx = new_sub_block_ctxt(cx, "while next");
|
|
|
|
let cond_cx =
|
|
|
|
new_loop_scope_block_ctxt(cx, option::none::<@block_ctxt>, next_cx,
|
|
|
|
"while cond");
|
|
|
|
let body_cx = new_scope_block_ctxt(cond_cx, "while loop body");
|
2011-10-05 11:26:27 +02:00
|
|
|
let body_end = trans_block(body_cx, body);
|
|
|
|
let cond_res = trans_temp_expr(cond_cx, cond);
|
|
|
|
Br(body_end, cond_cx.llbb);
|
2011-07-27 14:19:39 +02:00
|
|
|
let cond_bcx = trans_block_cleanups(cond_res.bcx, cond_cx);
|
2011-08-30 09:59:30 +02:00
|
|
|
CondBr(cond_bcx, cond_res.val, body_cx.llbb, next_cx.llbb);
|
|
|
|
Br(cx, cond_cx.llbb);
|
2011-09-27 08:03:06 +02:00
|
|
|
ret next_cx;
|
2010-11-03 11:05:15 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trans_do_while(cx: @block_ctxt, body: ast::blk, cond: @ast::expr) ->
|
2011-09-27 08:03:06 +02:00
|
|
|
@block_ctxt {
|
2011-09-02 15:34:58 -07:00
|
|
|
let next_cx = new_sub_block_ctxt(cx, "next");
|
2011-07-27 14:19:39 +02:00
|
|
|
let body_cx =
|
2011-08-13 00:09:25 -07:00
|
|
|
new_loop_scope_block_ctxt(cx, option::none::<@block_ctxt>, next_cx,
|
2011-09-02 15:34:58 -07:00
|
|
|
"do-while loop body");
|
2011-10-05 11:26:27 +02:00
|
|
|
let body_end = trans_block(body_cx, body);
|
2011-12-05 00:33:25 +08:00
|
|
|
let cond_cx = new_scope_block_ctxt(body_cx, "do-while cond");
|
|
|
|
Br(body_end, cond_cx.llbb);
|
|
|
|
let cond_res = trans_temp_expr(cond_cx, cond);
|
|
|
|
let cond_bcx = trans_block_cleanups(cond_res.bcx, cond_cx);
|
|
|
|
CondBr(cond_bcx, cond_res.val, body_cx.llbb, next_cx.llbb);
|
2011-08-30 09:59:30 +02:00
|
|
|
Br(cx, body_cx.llbb);
|
2011-09-27 08:03:06 +02:00
|
|
|
ret next_cx;
|
2010-11-03 11:05:15 -07:00
|
|
|
}
|
|
|
|
|
2012-01-02 16:50:51 +01:00
|
|
|
type generic_info = {
|
|
|
|
item_type: ty::t,
|
|
|
|
static_tis: [option::t<@tydesc_info>],
|
|
|
|
tydescs: [ValueRef],
|
|
|
|
param_bounds: @[ty::param_bounds],
|
|
|
|
origins: option::t<typeck::dict_res>
|
|
|
|
};
|
2011-01-14 14:17:57 -08:00
|
|
|
|
2012-01-19 14:24:03 -08:00
|
|
|
enum lval_kind {
|
2012-01-19 17:56:05 -08:00
|
|
|
temporary, //< Temporary value passed by value if of immediate type
|
|
|
|
owned, //< Non-temporary value passed by pointer
|
|
|
|
owned_imm, //< Non-temporary value passed by value
|
2011-12-19 12:50:31 -08:00
|
|
|
}
|
2011-12-10 08:38:40 -08:00
|
|
|
type local_var_result = {val: ValueRef, kind: lval_kind};
|
2011-10-07 11:20:51 +02:00
|
|
|
type lval_result = {bcx: @block_ctxt, val: ValueRef, kind: lval_kind};
|
2012-01-19 14:24:03 -08:00
|
|
|
enum callee_env {
|
2012-01-19 17:56:05 -08:00
|
|
|
null_env,
|
|
|
|
is_closure,
|
|
|
|
self_env(ValueRef),
|
|
|
|
dict_env(ValueRef, ValueRef),
|
2012-01-02 16:50:51 +01:00
|
|
|
}
|
2011-09-16 16:27:34 +02:00
|
|
|
type lval_maybe_callee = {bcx: @block_ctxt,
|
|
|
|
val: ValueRef,
|
2011-10-07 11:20:51 +02:00
|
|
|
kind: lval_kind,
|
2011-09-16 16:27:34 +02:00
|
|
|
env: callee_env,
|
|
|
|
generic: option::t<generic_info>};
|
2011-07-27 14:19:39 +02:00
|
|
|
|
2011-09-18 22:05:58 +02:00
|
|
|
fn null_env_ptr(bcx: @block_ctxt) -> ValueRef {
|
2012-01-05 16:19:12 -08:00
|
|
|
C_null(T_opaque_cbox_ptr(bcx_ccx(bcx)))
|
2011-09-18 22:05:58 +02:00
|
|
|
}
|
|
|
|
|
2011-12-10 08:38:40 -08:00
|
|
|
fn lval_from_local_var(bcx: @block_ctxt, r: local_var_result) -> lval_result {
|
|
|
|
ret { bcx: bcx, val: r.val, kind: r.kind };
|
|
|
|
}
|
|
|
|
|
2011-10-07 11:20:51 +02:00
|
|
|
fn lval_owned(bcx: @block_ctxt, val: ValueRef) -> lval_result {
|
|
|
|
ret {bcx: bcx, val: val, kind: owned};
|
2011-09-16 16:27:34 +02:00
|
|
|
}
|
2011-10-07 11:20:51 +02:00
|
|
|
fn lval_temp(bcx: @block_ctxt, val: ValueRef) -> lval_result {
|
|
|
|
ret {bcx: bcx, val: val, kind: temporary};
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
|
2011-10-07 11:20:51 +02:00
|
|
|
fn lval_no_env(bcx: @block_ctxt, val: ValueRef, kind: lval_kind)
|
2011-09-16 16:27:34 +02:00
|
|
|
-> lval_maybe_callee {
|
2011-10-07 11:20:51 +02:00
|
|
|
ret {bcx: bcx, val: val, kind: kind, env: is_closure, generic: none};
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trans_external_path(cx: @block_ctxt, did: ast::def_id,
|
2011-12-28 17:50:12 +01:00
|
|
|
tpt: ty::ty_param_bounds_and_ty) -> ValueRef {
|
2011-07-27 14:19:39 +02:00
|
|
|
let lcx = cx.fcx.lcx;
|
2012-01-12 17:59:49 +01:00
|
|
|
let name = csearch::get_symbol(lcx.ccx.sess.cstore, did);
|
2011-09-02 15:34:58 -07:00
|
|
|
ret get_extern_const(lcx.ccx.externs, lcx.ccx.llmod, name,
|
2011-12-28 17:50:12 +01:00
|
|
|
type_of_ty_param_bounds_and_ty(lcx, cx.sp, tpt));
|
2011-03-30 18:15:29 -07:00
|
|
|
}
|
|
|
|
|
2011-12-14 14:38:25 +01:00
|
|
|
fn lval_static_fn(bcx: @block_ctxt, fn_id: ast::def_id, id: ast::node_id)
|
|
|
|
-> lval_maybe_callee {
|
2012-01-02 12:00:40 +01:00
|
|
|
let ccx = bcx_ccx(bcx);
|
|
|
|
let tpt = ty::lookup_item_type(ccx.tcx, fn_id);
|
2011-09-16 16:27:34 +02:00
|
|
|
let val = if fn_id.crate == ast::local_crate {
|
2011-03-30 18:15:29 -07:00
|
|
|
// Internal reference.
|
2012-01-02 12:00:40 +01:00
|
|
|
assert (ccx.item_ids.contains_key(fn_id.node));
|
|
|
|
ccx.item_ids.get(fn_id.node)
|
2011-03-30 18:15:29 -07:00
|
|
|
} else {
|
|
|
|
// External reference.
|
2011-09-16 16:27:34 +02:00
|
|
|
trans_external_path(bcx, fn_id, tpt)
|
|
|
|
};
|
2012-01-02 12:00:40 +01:00
|
|
|
let tys = ty::node_id_to_type_params(ccx.tcx, id);
|
2011-11-03 10:57:54 +01:00
|
|
|
let gen = none, bcx = bcx;
|
2012-01-02 12:00:40 +01:00
|
|
|
if vec::len(tys) != 0u {
|
2011-09-16 16:27:34 +02:00
|
|
|
let tydescs = [], tis = [];
|
|
|
|
for t in tys {
|
2011-04-29 14:59:52 -07:00
|
|
|
// TODO: Doesn't always escape.
|
2011-09-16 16:27:34 +02:00
|
|
|
let ti = none;
|
2012-01-13 10:58:31 +01:00
|
|
|
let td = get_tydesc(bcx, t, true, ti).result;
|
2011-08-19 15:16:48 -07:00
|
|
|
tis += [ti];
|
2011-01-31 18:06:35 -08:00
|
|
|
bcx = td.bcx;
|
2011-08-19 15:16:48 -07:00
|
|
|
tydescs += [td.val];
|
2011-01-31 18:06:35 -08:00
|
|
|
}
|
2012-01-02 12:00:40 +01:00
|
|
|
gen = some({item_type: tpt.ty,
|
|
|
|
static_tis: tis,
|
|
|
|
tydescs: tydescs,
|
2012-01-02 16:50:51 +01:00
|
|
|
param_bounds: tpt.bounds,
|
|
|
|
origins: ccx.dict_map.find(id)});
|
2011-01-31 18:06:35 -08:00
|
|
|
}
|
2011-10-07 11:20:51 +02:00
|
|
|
ret {bcx: bcx, val: val, kind: owned, env: null_env, generic: gen};
|
2011-01-31 18:06:35 -08:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn lookup_discriminant(lcx: @local_ctxt, vid: ast::def_id) -> ValueRef {
|
2011-10-14 16:45:25 -07:00
|
|
|
let ccx = lcx.ccx;
|
|
|
|
alt ccx.discrims.find(vid) {
|
2012-01-18 22:37:22 -08:00
|
|
|
none {
|
2011-07-27 14:19:39 +02:00
|
|
|
// It's an external discriminant that we haven't seen yet.
|
|
|
|
assert (vid.crate != ast::local_crate);
|
2012-01-12 17:59:49 +01:00
|
|
|
let sym = csearch::get_symbol(lcx.ccx.sess.cstore, vid);
|
2011-09-02 15:34:58 -07:00
|
|
|
let gvar =
|
|
|
|
str::as_buf(sym,
|
|
|
|
{|buf|
|
2011-10-14 17:00:17 -07:00
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type, buf)
|
2011-09-02 15:34:58 -07:00
|
|
|
});
|
2011-07-27 14:19:39 +02:00
|
|
|
llvm::LLVMSetLinkage(gvar,
|
|
|
|
lib::llvm::LLVMExternalLinkage as llvm::Linkage);
|
|
|
|
llvm::LLVMSetGlobalConstant(gvar, True);
|
2011-10-20 15:26:26 -07:00
|
|
|
lcx.ccx.discrims.insert(vid, gvar);
|
2011-07-27 14:19:39 +02:00
|
|
|
ret gvar;
|
|
|
|
}
|
|
|
|
some(llval) { ret llval; }
|
2011-04-07 11:42:40 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-10 08:38:40 -08:00
|
|
|
fn trans_local_var(cx: @block_ctxt, def: ast::def) -> local_var_result {
|
|
|
|
fn take_local(table: hashmap<ast::node_id, local_val>,
|
|
|
|
id: ast::node_id) -> local_var_result {
|
2011-10-07 11:20:51 +02:00
|
|
|
alt table.find(id) {
|
2011-12-10 08:38:40 -08:00
|
|
|
some(local_mem(v)) { {val: v, kind: owned} }
|
|
|
|
some(local_imm(v)) { {val: v, kind: owned_imm} }
|
2012-01-14 16:05:07 -08:00
|
|
|
r { fail("take_local: internal error"); }
|
2011-10-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
}
|
2011-09-01 14:35:00 +02:00
|
|
|
alt def {
|
|
|
|
ast::def_upvar(did, _, _) {
|
2011-08-02 15:13:08 -07:00
|
|
|
assert (cx.fcx.llupvars.contains_key(did.node));
|
2011-12-10 08:38:40 -08:00
|
|
|
ret { val: cx.fcx.llupvars.get(did.node), kind: owned };
|
2011-08-02 15:13:08 -07:00
|
|
|
}
|
2011-09-01 14:35:00 +02:00
|
|
|
ast::def_arg(did, _) {
|
2012-01-14 16:05:07 -08:00
|
|
|
assert (cx.fcx.llargs.contains_key(did.node));
|
2011-12-10 08:38:40 -08:00
|
|
|
ret take_local(cx.fcx.llargs, did.node);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-10-07 11:20:51 +02:00
|
|
|
ast::def_local(did, _) | ast::def_binding(did) {
|
2012-01-14 16:05:07 -08:00
|
|
|
assert (cx.fcx.lllocals.contains_key(did.node));
|
2011-12-10 08:38:40 -08:00
|
|
|
ret take_local(cx.fcx.lllocals, did.node);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-12-13 13:19:56 +01:00
|
|
|
ast::def_self(did) {
|
2011-12-14 15:23:11 +01:00
|
|
|
let slf = option::get(cx.fcx.llself);
|
|
|
|
let ptr = PointerCast(cx, slf.v, T_ptr(type_of_or_i8(cx, slf.t)));
|
|
|
|
ret {val: ptr, kind: owned};
|
2011-12-13 13:19:56 +01:00
|
|
|
}
|
2011-09-01 14:35:00 +02:00
|
|
|
_ {
|
2011-09-12 11:27:30 +02:00
|
|
|
bcx_ccx(cx).sess.span_unimpl
|
|
|
|
(cx.sp, "unsupported def type in trans_local_def");
|
2011-09-01 14:35:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-30 13:38:38 +01:00
|
|
|
fn trans_path(cx: @block_ctxt, p: @ast::path, id: ast::node_id)
|
2011-09-16 16:27:34 +02:00
|
|
|
-> lval_maybe_callee {
|
|
|
|
ret trans_var(cx, p.span, bcx_tcx(cx).def_map.get(id), id);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trans_var(cx: @block_ctxt, sp: span, def: ast::def, id: ast::node_id)
|
|
|
|
-> lval_maybe_callee {
|
2011-09-01 14:35:00 +02:00
|
|
|
let ccx = bcx_ccx(cx);
|
|
|
|
alt def {
|
2011-10-11 14:52:38 -07:00
|
|
|
ast::def_fn(did, _) | ast::def_native_fn(did, _) {
|
2011-12-14 14:38:25 +01:00
|
|
|
ret lval_static_fn(cx, did, id);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-09-01 14:35:00 +02:00
|
|
|
ast::def_variant(tid, vid) {
|
2011-12-14 14:38:25 +01:00
|
|
|
if vec::len(ty::tag_variant_with_id(ccx.tcx, tid, vid).args) > 0u {
|
2011-07-27 14:19:39 +02:00
|
|
|
// N-ary variant.
|
2011-12-14 14:38:25 +01:00
|
|
|
ret lval_static_fn(cx, vid, id);
|
|
|
|
} else {
|
2011-07-27 14:19:39 +02:00
|
|
|
// Nullary variant.
|
|
|
|
let tag_ty = node_id_type(ccx, id);
|
|
|
|
let alloc_result = alloc_ty(cx, tag_ty);
|
|
|
|
let lltagblob = alloc_result.val;
|
2011-07-28 18:38:27 -07:00
|
|
|
let lltagty = type_of_tag(ccx, sp, tid, tag_ty);
|
2011-07-27 14:19:39 +02:00
|
|
|
let bcx = alloc_result.bcx;
|
2011-08-30 09:59:30 +02:00
|
|
|
let lltagptr = PointerCast(bcx, lltagblob, T_ptr(lltagty));
|
2011-10-25 22:23:28 -07:00
|
|
|
let lldiscrimptr = GEPi(bcx, lltagptr, [0, 0]);
|
2012-01-10 14:50:40 -07:00
|
|
|
let lldiscrim_gv = lookup_discriminant(bcx.fcx.lcx, vid);
|
|
|
|
let lldiscrim = Load(bcx, lldiscrim_gv);
|
|
|
|
Store(bcx, lldiscrim, lldiscrimptr);
|
2011-10-07 11:20:51 +02:00
|
|
|
ret lval_no_env(bcx, lltagptr, temporary);
|
2011-05-12 13:25:18 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-09-01 14:35:00 +02:00
|
|
|
ast::def_const(did) {
|
2011-07-27 14:19:39 +02:00
|
|
|
if did.crate == ast::local_crate {
|
|
|
|
assert (ccx.consts.contains_key(did.node));
|
2011-10-07 11:20:51 +02:00
|
|
|
ret lval_no_env(cx, ccx.consts.get(did.node), owned);
|
2011-07-27 14:19:39 +02:00
|
|
|
} else {
|
|
|
|
let tp = ty::node_id_to_monotype(ccx.tcx, id);
|
2012-01-02 12:09:26 +01:00
|
|
|
let val = trans_external_path(cx, did, {bounds: @[], ty: tp});
|
2011-10-07 11:20:51 +02:00
|
|
|
ret lval_no_env(cx, load_if_immediate(cx, val, tp), owned_imm);
|
2010-11-26 15:54:04 -08:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-09-16 16:27:34 +02:00
|
|
|
_ {
|
|
|
|
let loc = trans_local_var(cx, def);
|
2011-12-10 08:38:40 -08:00
|
|
|
ret lval_no_env(cx, loc.val, loc.kind);
|
2011-09-16 16:27:34 +02:00
|
|
|
}
|
2010-11-26 15:54:04 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-05 10:21:57 +02:00
|
|
|
fn trans_rec_field(bcx: @block_ctxt, base: @ast::expr,
|
|
|
|
field: ast::ident) -> lval_result {
|
2011-10-05 11:26:27 +02:00
|
|
|
let {bcx, val} = trans_temp_expr(bcx, base);
|
2011-10-05 10:21:57 +02:00
|
|
|
let {bcx, val, ty} = autoderef(bcx, val, ty::expr_ty(bcx_tcx(bcx), base));
|
|
|
|
let fields = alt ty::struct(bcx_tcx(bcx), ty) { ty::ty_rec(fs) { fs } };
|
2011-12-18 19:30:40 +01:00
|
|
|
let ix = option::get(ty::field_idx(field, fields));
|
2011-10-05 10:21:57 +02:00
|
|
|
// Silly check
|
|
|
|
check type_is_tup_like(bcx, ty);
|
|
|
|
let {bcx, val} = GEP_tup_like(bcx, ty, val, [0, ix as int]);
|
2011-10-07 11:20:51 +02:00
|
|
|
ret {bcx: bcx, val: val, kind: owned};
|
2010-11-26 15:54:04 -08:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trans_index(cx: @block_ctxt, sp: span, base: @ast::expr, idx: @ast::expr,
|
|
|
|
id: ast::node_id) -> lval_result {
|
2011-06-11 23:15:16 -07:00
|
|
|
// Is this an interior vector?
|
2011-07-27 14:19:39 +02:00
|
|
|
let base_ty = ty::expr_ty(bcx_tcx(cx), base);
|
2011-10-05 11:26:27 +02:00
|
|
|
let exp = trans_temp_expr(cx, base);
|
2011-07-27 14:19:39 +02:00
|
|
|
let lv = autoderef(exp.bcx, exp.val, base_ty);
|
2011-10-05 11:26:27 +02:00
|
|
|
let ix = trans_temp_expr(lv.bcx, idx);
|
2011-07-27 14:19:39 +02:00
|
|
|
let v = lv.val;
|
|
|
|
let bcx = ix.bcx;
|
2011-10-14 16:45:25 -07:00
|
|
|
let ccx = bcx_ccx(cx);
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-10-10 13:32:50 +02:00
|
|
|
// Cast to an LLVM integer. Rust is less strict than LLVM in this regard.
|
2011-07-27 14:19:39 +02:00
|
|
|
let ix_val;
|
|
|
|
let ix_size = llsize_of_real(bcx_ccx(cx), val_ty(ix.val));
|
2011-10-14 17:00:17 -07:00
|
|
|
let int_size = llsize_of_real(bcx_ccx(cx), ccx.int_type);
|
2011-07-27 14:19:39 +02:00
|
|
|
if ix_size < int_size {
|
2011-10-14 17:00:17 -07:00
|
|
|
ix_val = ZExt(bcx, ix.val, ccx.int_type);
|
2011-08-19 15:16:48 -07:00
|
|
|
} else if ix_size > int_size {
|
2011-10-14 17:00:17 -07:00
|
|
|
ix_val = Trunc(bcx, ix.val, ccx.int_type);
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { ix_val = ix.val; }
|
2011-10-10 13:32:50 +02:00
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
let unit_ty = node_id_type(bcx_ccx(cx), id);
|
|
|
|
let unit_sz = size_of(bcx, unit_ty);
|
2011-01-31 15:03:05 -08:00
|
|
|
bcx = unit_sz.bcx;
|
2011-09-02 15:34:58 -07:00
|
|
|
maybe_name_value(bcx_ccx(cx), unit_sz.val, "unit_sz");
|
2011-08-30 09:59:30 +02:00
|
|
|
let scaled_ix = Mul(bcx, ix_val, unit_sz.val);
|
2011-09-02 15:34:58 -07:00
|
|
|
maybe_name_value(bcx_ccx(cx), scaled_ix, "scaled_ix");
|
2011-09-02 16:09:41 +02:00
|
|
|
let lim = tvec::get_fill(bcx, v);
|
|
|
|
let body = tvec::get_dataptr(bcx, v, type_of_or_i8(bcx, unit_ty));
|
2011-08-30 09:59:30 +02:00
|
|
|
let bounds_check = ICmp(bcx, lib::llvm::LLVMIntULT, scaled_ix, lim);
|
2011-09-02 15:34:58 -07:00
|
|
|
let fail_cx = new_sub_block_ctxt(bcx, "fail");
|
|
|
|
let next_cx = new_sub_block_ctxt(bcx, "next");
|
2011-09-02 18:59:22 -07:00
|
|
|
let ncx = bcx_ccx(next_cx);
|
2011-08-30 09:59:30 +02:00
|
|
|
CondBr(bcx, bounds_check, next_cx.llbb, fail_cx.llbb);
|
2010-12-10 16:10:35 -08:00
|
|
|
// fail: bad bounds check.
|
|
|
|
|
2011-09-02 15:34:58 -07:00
|
|
|
trans_fail(fail_cx, some::<span>(sp), "bounds check");
|
2011-09-12 11:27:30 +02:00
|
|
|
let elt =
|
|
|
|
if check type_has_static_size(ncx, unit_ty) {
|
|
|
|
let elt_1 = GEP(next_cx, body, [ix_val]);
|
|
|
|
let llunitty = type_of(ncx, sp, unit_ty);
|
|
|
|
PointerCast(next_cx, elt_1, T_ptr(llunitty))
|
|
|
|
} else {
|
|
|
|
body = PointerCast(next_cx, body, T_ptr(T_i8()));
|
|
|
|
GEP(next_cx, body, [scaled_ix])
|
|
|
|
};
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-10-07 11:20:51 +02:00
|
|
|
ret lval_owned(next_cx, elt);
|
2010-12-10 16:10:35 -08:00
|
|
|
}
|
|
|
|
|
2011-12-14 15:23:11 +01:00
|
|
|
fn expr_is_lval(bcx: @block_ctxt, e: @ast::expr) -> bool {
|
|
|
|
let ccx = bcx_ccx(bcx);
|
2012-01-13 10:58:31 +01:00
|
|
|
ty::expr_is_lval(ccx.method_map, e)
|
2011-12-14 15:23:11 +01:00
|
|
|
}
|
|
|
|
|
2011-10-05 10:21:57 +02:00
|
|
|
fn trans_callee(bcx: @block_ctxt, e: @ast::expr) -> lval_maybe_callee {
|
2011-09-16 16:27:34 +02:00
|
|
|
alt e.node {
|
2011-10-05 10:21:57 +02:00
|
|
|
ast::expr_path(p) { ret trans_path(bcx, p, e.id); }
|
2011-12-19 10:21:31 +01:00
|
|
|
ast::expr_field(base, ident, _) {
|
2011-10-05 11:51:41 +02:00
|
|
|
// Lval means this is a record field, so not a method
|
2011-12-14 15:23:11 +01:00
|
|
|
if !expr_is_lval(bcx, e) {
|
|
|
|
alt bcx_ccx(bcx).method_map.find(e.id) {
|
2011-12-29 13:12:52 +01:00
|
|
|
some(typeck::method_static(did)) { // An impl method
|
2012-01-02 16:50:51 +01:00
|
|
|
ret trans_impl::trans_static_callee(bcx, e, base, did);
|
2011-12-14 14:38:25 +01:00
|
|
|
}
|
2012-01-02 16:50:51 +01:00
|
|
|
some(typeck::method_param(iid, off, p, b)) {
|
2012-01-07 22:44:14 +01:00
|
|
|
ret trans_impl::trans_param_callee(
|
2012-01-02 16:50:51 +01:00
|
|
|
bcx, e, base, iid, off, p, b);
|
2011-12-29 13:12:52 +01:00
|
|
|
}
|
2012-01-07 22:44:14 +01:00
|
|
|
some(typeck::method_iface(off)) {
|
|
|
|
ret trans_impl::trans_iface_callee(bcx, e, base, off);
|
|
|
|
}
|
2011-12-14 14:38:25 +01:00
|
|
|
}
|
2011-10-05 10:21:57 +02:00
|
|
|
}
|
2011-09-16 16:27:34 +02:00
|
|
|
}
|
2011-10-05 10:21:57 +02:00
|
|
|
_ {}
|
2011-09-16 16:27:34 +02:00
|
|
|
}
|
2011-10-05 11:51:41 +02:00
|
|
|
let lv = trans_temp_lval(bcx, e);
|
2011-10-07 11:20:51 +02:00
|
|
|
ret lval_no_env(lv.bcx, lv.val, lv.kind);
|
2011-09-16 16:27:34 +02:00
|
|
|
}
|
|
|
|
|
2011-10-05 12:23:18 +02:00
|
|
|
// Use this when you know you are compiling an lval.
|
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-09-16 16:27:34 +02:00
|
|
|
fn trans_lval(cx: @block_ctxt, e: @ast::expr) -> lval_result {
|
2011-07-27 14:19:39 +02:00
|
|
|
alt e.node {
|
2011-09-16 16:27:34 +02:00
|
|
|
ast::expr_path(p) {
|
|
|
|
let v = trans_path(cx, p, e.id);
|
|
|
|
ret lval_maybe_callee_to_lval(v, ty::expr_ty(bcx_tcx(cx), e));
|
|
|
|
}
|
2011-12-19 10:21:31 +01:00
|
|
|
ast::expr_field(base, ident, _) {
|
2011-10-05 10:21:57 +02:00
|
|
|
ret trans_rec_field(cx, base, ident);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
ast::expr_index(base, idx) {
|
|
|
|
ret trans_index(cx, e.span, base, idx, e.id);
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::expr_unary(ast::deref, base) {
|
2011-07-27 14:19:39 +02:00
|
|
|
let ccx = bcx_ccx(cx);
|
2011-10-05 11:26:27 +02:00
|
|
|
let sub = trans_temp_expr(cx, base);
|
2011-07-27 14:19:39 +02:00
|
|
|
let t = ty::expr_ty(ccx.tcx, base);
|
|
|
|
let val =
|
|
|
|
alt ty::struct(ccx.tcx, t) {
|
|
|
|
ty::ty_box(_) {
|
2011-10-25 22:23:28 -07:00
|
|
|
GEPi(sub.bcx, sub.val, [0, abi::box_rc_field_body])
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
ty::ty_res(_, _, _) {
|
2011-10-25 22:23:28 -07:00
|
|
|
GEPi(sub.bcx, sub.val, [0, 1])
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
ty::ty_tag(_, _) {
|
|
|
|
let ety = ty::expr_ty(ccx.tcx, e);
|
2011-09-02 18:59:22 -07:00
|
|
|
let sp = e.span;
|
2011-09-12 11:27:30 +02:00
|
|
|
let ellty =
|
|
|
|
if check type_has_static_size(ccx, ety) {
|
|
|
|
T_ptr(type_of(ccx, sp, ety))
|
|
|
|
} else { T_typaram_ptr(ccx.tn) };
|
2011-08-30 09:59:30 +02:00
|
|
|
PointerCast(sub.bcx, sub.val, ellty)
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-09-21 14:00:11 -07:00
|
|
|
ty::ty_ptr(_) | ty::ty_uniq(_) { sub.val }
|
2011-06-28 16:38:14 +02:00
|
|
|
};
|
2011-10-07 11:20:51 +02:00
|
|
|
ret lval_owned(sub.bcx, val);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-10-05 11:51:41 +02:00
|
|
|
// This is a by-ref returning call. Regular calls are not lval
|
2011-10-21 14:11:24 +02:00
|
|
|
ast::expr_call(f, args, _) {
|
2011-10-05 11:51:41 +02:00
|
|
|
let cell = empty_dest_cell();
|
2011-10-21 13:42:26 +02:00
|
|
|
let bcx = trans_call(cx, f, args, e.id, by_val(cell));
|
2011-10-07 11:20:51 +02:00
|
|
|
ret lval_owned(bcx, *cell);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-10-05 11:51:41 +02:00
|
|
|
_ { bcx_ccx(cx).sess.span_bug(e.span, "non-lval in trans_lval"); }
|
2011-07-08 14:28:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-16 16:27:34 +02:00
|
|
|
fn maybe_add_env(bcx: @block_ctxt, c: lval_maybe_callee)
|
2011-10-07 11:20:51 +02:00
|
|
|
-> (lval_kind, ValueRef) {
|
2011-09-29 11:50:03 +02:00
|
|
|
alt c.env {
|
2012-01-18 22:37:22 -08:00
|
|
|
is_closure { (c.kind, c.val) }
|
2012-01-13 10:58:31 +01:00
|
|
|
self_env(_) | dict_env(_, _) {
|
2011-09-29 11:50:03 +02:00
|
|
|
fail "Taking the value of a method does not work yet (issue #435)";
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
null_env {
|
2011-09-16 16:27:34 +02:00
|
|
|
let llfnty = llvm::LLVMGetElementType(val_ty(c.val));
|
2011-10-07 11:20:51 +02:00
|
|
|
(temporary, create_real_fn_pair(bcx, llfnty, c.val,
|
|
|
|
null_env_ptr(bcx)))
|
2011-09-29 11:50:03 +02:00
|
|
|
}
|
2011-09-16 16:27:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn lval_maybe_callee_to_lval(c: lval_maybe_callee, ty: ty::t) -> lval_result {
|
|
|
|
alt c.generic {
|
2011-07-27 14:19:39 +02:00
|
|
|
some(gi) {
|
2011-12-13 16:25:51 -08:00
|
|
|
let n_args = vec::len(ty::ty_fn_args(bcx_tcx(c.bcx), ty));
|
2012-01-18 16:02:29 -05:00
|
|
|
let args = vec::init_elt(n_args, none::<@ast::expr>);
|
2011-09-28 15:57:38 +02:00
|
|
|
let space = alloc_ty(c.bcx, ty);
|
2011-12-14 13:57:10 -08:00
|
|
|
let bcx = trans_closure::trans_bind_1(space.bcx, ty, c, args, ty,
|
|
|
|
save_in(space.val));
|
2011-09-28 15:57:38 +02:00
|
|
|
add_clean_temp(bcx, space.val, ty);
|
2011-10-07 11:20:51 +02:00
|
|
|
ret {bcx: bcx, val: space.val, kind: temporary};
|
2011-09-16 16:27:34 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
none {
|
2011-10-07 11:20:51 +02:00
|
|
|
let (kind, val) = maybe_add_env(c.bcx, c);
|
|
|
|
ret {bcx: c.bcx, val: val, kind: kind};
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn int_cast(bcx: @block_ctxt, lldsttype: TypeRef, llsrctype: TypeRef,
|
2011-07-27 14:19:39 +02:00
|
|
|
llsrc: ValueRef, signed: bool) -> ValueRef {
|
|
|
|
let srcsz = llvm::LLVMGetIntTypeWidth(llsrctype);
|
|
|
|
let dstsz = llvm::LLVMGetIntTypeWidth(lldsttype);
|
|
|
|
ret if dstsz == srcsz {
|
2011-08-30 09:59:30 +02:00
|
|
|
BitCast(bcx, llsrc, lldsttype)
|
2011-08-19 15:16:48 -07:00
|
|
|
} else if srcsz > dstsz {
|
2011-08-30 09:59:30 +02:00
|
|
|
TruncOrBitCast(bcx, llsrc, lldsttype)
|
2011-08-19 15:16:48 -07:00
|
|
|
} else if signed {
|
2011-08-30 09:59:30 +02:00
|
|
|
SExtOrBitCast(bcx, llsrc, lldsttype)
|
|
|
|
} else { ZExtOrBitCast(bcx, llsrc, lldsttype) };
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn float_cast(bcx: @block_ctxt, lldsttype: TypeRef, llsrctype: TypeRef,
|
2011-07-27 14:19:39 +02:00
|
|
|
llsrc: ValueRef) -> ValueRef {
|
|
|
|
let srcsz = lib::llvm::float_width(llsrctype);
|
|
|
|
let dstsz = lib::llvm::float_width(lldsttype);
|
|
|
|
ret if dstsz > srcsz {
|
2011-08-30 09:59:30 +02:00
|
|
|
FPExt(bcx, llsrc, lldsttype)
|
2011-08-19 15:16:48 -07:00
|
|
|
} else if srcsz > dstsz {
|
2011-08-30 09:59:30 +02:00
|
|
|
FPTrunc(bcx, llsrc, lldsttype)
|
2011-07-27 14:19:39 +02:00
|
|
|
} else { llsrc };
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:46:49 +02:00
|
|
|
fn trans_cast(cx: @block_ctxt, e: @ast::expr, id: ast::node_id,
|
|
|
|
dest: dest) -> @block_ctxt {
|
2011-07-27 14:19:39 +02:00
|
|
|
let ccx = bcx_ccx(cx);
|
2012-01-07 22:44:14 +01:00
|
|
|
let t_out = node_id_type(ccx, id);
|
|
|
|
alt ty::struct(ccx.tcx, t_out) {
|
|
|
|
ty::ty_iface(_, _) { ret trans_impl::trans_cast(cx, e, id, dest); }
|
|
|
|
_ {}
|
|
|
|
}
|
2011-10-05 11:26:27 +02:00
|
|
|
let e_res = trans_temp_expr(cx, e);
|
2011-07-27 14:19:39 +02:00
|
|
|
let ll_t_in = val_ty(e_res.val);
|
|
|
|
let t_in = ty::expr_ty(ccx.tcx, e);
|
2011-09-02 18:59:22 -07:00
|
|
|
// Check should be avoidable because it's a cast.
|
|
|
|
// FIXME: Constrain types so as to avoid this check.
|
2011-09-12 11:27:30 +02:00
|
|
|
check (type_has_static_size(ccx, t_out));
|
2011-07-27 14:19:39 +02:00
|
|
|
let ll_t_out = type_of(ccx, e.span, t_out);
|
2011-07-22 13:10:59 +02:00
|
|
|
|
2012-01-19 17:56:05 -08:00
|
|
|
enum kind { pointer, integral, float, tag_, other, }
|
2011-09-12 11:27:30 +02:00
|
|
|
fn t_kind(tcx: ty::ctxt, t: ty::t) -> kind {
|
2011-07-27 14:19:39 +02:00
|
|
|
ret if ty::type_is_fp(tcx, t) {
|
|
|
|
float
|
2011-11-02 12:15:50 +01:00
|
|
|
} else if ty::type_is_native(tcx, t) ||
|
|
|
|
ty::type_is_unsafe_ptr(tcx, t) {
|
|
|
|
pointer
|
2011-08-19 15:16:48 -07:00
|
|
|
} else if ty::type_is_integral(tcx, t) {
|
2011-07-27 14:19:39 +02:00
|
|
|
integral
|
2012-01-10 14:55:54 -07:00
|
|
|
} else if ty::type_is_tag(tcx, t) {
|
|
|
|
tag_
|
2011-07-27 14:19:39 +02:00
|
|
|
} else { other };
|
|
|
|
}
|
|
|
|
let k_in = t_kind(ccx.tcx, t_in);
|
|
|
|
let k_out = t_kind(ccx.tcx, t_out);
|
|
|
|
let s_in = k_in == integral && ty::type_is_signed(ccx.tcx, t_in);
|
|
|
|
|
|
|
|
let newval =
|
|
|
|
alt {in: k_in, out: k_out} {
|
2012-01-19 01:03:57 -08:00
|
|
|
{in: integral, out: integral} {
|
2011-07-27 14:19:39 +02:00
|
|
|
int_cast(e_res.bcx, ll_t_out, ll_t_in, e_res.val, s_in)
|
|
|
|
}
|
2012-01-19 01:03:57 -08:00
|
|
|
{in: float, out: float} {
|
2011-07-27 14:19:39 +02:00
|
|
|
float_cast(e_res.bcx, ll_t_out, ll_t_in, e_res.val)
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
{in: integral, out: float} {
|
2011-07-27 14:19:39 +02:00
|
|
|
if s_in {
|
2011-08-30 09:59:30 +02:00
|
|
|
SIToFP(e_res.bcx, e_res.val, ll_t_out)
|
|
|
|
} else { UIToFP(e_res.bcx, e_res.val, ll_t_out) }
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
{in: float, out: integral} {
|
2011-07-27 14:19:39 +02:00
|
|
|
if ty::type_is_signed(ccx.tcx, t_out) {
|
2011-08-30 09:59:30 +02:00
|
|
|
FPToSI(e_res.bcx, e_res.val, ll_t_out)
|
|
|
|
} else { FPToUI(e_res.bcx, e_res.val, ll_t_out) }
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
{in: integral, out: pointer} {
|
2011-08-30 09:59:30 +02:00
|
|
|
IntToPtr(e_res.bcx, e_res.val, ll_t_out)
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
{in: pointer, out: integral} {
|
2011-08-30 09:59:30 +02:00
|
|
|
PtrToInt(e_res.bcx, e_res.val, ll_t_out)
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-19 01:03:57 -08:00
|
|
|
{in: pointer, out: pointer} {
|
2011-08-30 09:59:30 +02:00
|
|
|
PointerCast(e_res.bcx, e_res.val, ll_t_out)
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-19 01:03:57 -08:00
|
|
|
{in: tag_, out: integral} | {in: tag_, out: float} {
|
2012-01-10 14:55:54 -07:00
|
|
|
let cx = e_res.bcx;
|
|
|
|
let lltagty = T_opaque_tag_ptr(ccx);
|
|
|
|
let av_tag = PointerCast(cx, e_res.val, lltagty);
|
|
|
|
let lldiscrim_a_ptr = GEPi(cx, av_tag, [0, 0]);
|
|
|
|
let lldiscrim_a = Load(cx, lldiscrim_a_ptr);
|
|
|
|
alt k_out {
|
2012-01-18 22:37:22 -08:00
|
|
|
integral {int_cast(e_res.bcx, ll_t_out,
|
2012-01-10 14:55:54 -07:00
|
|
|
val_ty(lldiscrim_a), lldiscrim_a, true)}
|
2012-01-18 22:37:22 -08:00
|
|
|
float {SIToFP(e_res.bcx, lldiscrim_a, ll_t_out)}
|
2012-01-10 14:55:54 -07:00
|
|
|
}
|
|
|
|
}
|
2011-09-02 15:34:58 -07:00
|
|
|
_ { ccx.sess.bug("Translating unsupported cast.") }
|
2011-07-27 14:19:39 +02:00
|
|
|
};
|
2011-09-29 10:46:49 +02:00
|
|
|
ret store_in_dest(e_res.bcx, newval, dest);
|
2010-11-24 10:32:14 -08:00
|
|
|
}
|
|
|
|
|
2012-01-09 17:44:55 +01:00
|
|
|
fn trans_arg_expr(cx: @block_ctxt, arg: ty::arg, lldestty: TypeRef,
|
2011-09-12 12:39:38 +02:00
|
|
|
&to_zero: [{v: ValueRef, t: ty::t}],
|
|
|
|
&to_revoke: [{v: ValueRef, t: ty::t}], e: @ast::expr) ->
|
|
|
|
result {
|
2011-07-27 14:19:39 +02:00
|
|
|
let ccx = bcx_ccx(cx);
|
|
|
|
let e_ty = ty::expr_ty(ccx.tcx, e);
|
|
|
|
let is_bot = ty::type_is_bot(ccx.tcx, e_ty);
|
2011-10-05 11:51:41 +02:00
|
|
|
let lv = trans_temp_lval(cx, e);
|
2011-09-16 16:27:34 +02:00
|
|
|
let bcx = lv.bcx;
|
|
|
|
let val = lv.val;
|
2011-07-27 14:19:39 +02:00
|
|
|
if is_bot {
|
2011-06-02 17:50:37 -07:00
|
|
|
// For values of type _|_, we generate an
|
|
|
|
// "undef" value, as such a value should never
|
|
|
|
// be inspected. It's important for the value
|
2012-01-09 17:44:55 +01:00
|
|
|
// to have type lldestty (the callee's expected type).
|
|
|
|
val = llvm::LLVMGetUndef(lldestty);
|
2011-10-06 12:26:12 +02:00
|
|
|
} else if arg.mode == ast::by_ref || arg.mode == ast::by_val {
|
2011-10-10 12:23:58 +02:00
|
|
|
let copied = false, imm = ty::type_is_immediate(ccx.tcx, e_ty);
|
2011-10-07 11:20:51 +02:00
|
|
|
if arg.mode == ast::by_ref && lv.kind != owned && imm {
|
2011-09-07 15:13:19 +02:00
|
|
|
val = do_spill_noroot(bcx, val);
|
|
|
|
copied = true;
|
|
|
|
}
|
2011-10-07 11:20:51 +02:00
|
|
|
if ccx.copy_map.contains_key(e.id) && lv.kind != temporary {
|
2011-09-07 15:13:19 +02:00
|
|
|
if !copied {
|
|
|
|
let alloc = alloc_ty(bcx, e_ty);
|
2011-10-06 14:17:56 +02:00
|
|
|
bcx = copy_val(alloc.bcx, INIT, alloc.val,
|
|
|
|
load_if_immediate(alloc.bcx, val, e_ty), e_ty);
|
2011-09-07 15:13:19 +02:00
|
|
|
val = alloc.val;
|
2011-09-12 11:27:30 +02:00
|
|
|
} else { bcx = take_ty(bcx, val, e_ty); }
|
2011-09-07 15:13:19 +02:00
|
|
|
add_clean(bcx, val, e_ty);
|
2011-07-07 16:14:00 +02:00
|
|
|
}
|
2011-10-07 11:20:51 +02:00
|
|
|
if arg.mode == ast::by_val && (lv.kind == owned || !imm) {
|
2011-10-06 14:17:56 +02:00
|
|
|
val = Load(bcx, val);
|
|
|
|
}
|
2011-11-16 12:32:38 +01:00
|
|
|
} else if arg.mode == ast::by_copy {
|
|
|
|
let {bcx: cx, val: alloc} = alloc_ty(bcx, e_ty);
|
2011-11-18 16:43:30 +01:00
|
|
|
let last_use = ccx.last_uses.contains_key(e.id);
|
2011-11-16 12:32:38 +01:00
|
|
|
bcx = cx;
|
|
|
|
if lv.kind == temporary { revoke_clean(bcx, val); }
|
|
|
|
if lv.kind == owned || !ty::type_is_immediate(ccx.tcx, e_ty) {
|
|
|
|
bcx = memmove_ty(bcx, alloc, val, e_ty);
|
2011-11-18 16:43:30 +01:00
|
|
|
if last_use && ty::type_needs_drop(ccx.tcx, e_ty) {
|
|
|
|
bcx = zero_alloca(bcx, val, e_ty);
|
|
|
|
}
|
2011-11-16 12:32:38 +01:00
|
|
|
} else { Store(bcx, val, alloc); }
|
|
|
|
val = alloc;
|
2011-11-18 16:43:30 +01:00
|
|
|
if lv.kind != temporary && !last_use {
|
|
|
|
bcx = take_ty(bcx, val, e_ty);
|
|
|
|
}
|
2011-10-10 12:23:58 +02:00
|
|
|
} else if ty::type_is_immediate(ccx.tcx, e_ty) && lv.kind != owned {
|
2011-09-02 15:12:27 -07:00
|
|
|
let r = do_spill(bcx, val, e_ty);
|
2011-09-02 15:34:58 -07:00
|
|
|
val = r.val;
|
|
|
|
bcx = r.bcx;
|
2011-07-07 16:14:00 +02:00
|
|
|
}
|
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
if !is_bot && ty::type_contains_params(ccx.tcx, arg.ty) {
|
2011-08-30 09:59:30 +02:00
|
|
|
val = PointerCast(bcx, val, lldestty);
|
2011-04-23 14:17:44 -07:00
|
|
|
}
|
2011-08-09 17:56:26 -07:00
|
|
|
|
|
|
|
// Collect arg for later if it happens to be one we've moving out.
|
2011-09-12 10:05:40 +02:00
|
|
|
if arg.mode == ast::by_move {
|
2011-10-07 11:20:51 +02:00
|
|
|
if lv.kind == owned {
|
2011-08-19 15:16:48 -07:00
|
|
|
// Use actual ty, not declared ty -- anything else doesn't make
|
|
|
|
// sense if declared ty is a ty param
|
2011-09-16 16:27:34 +02:00
|
|
|
to_zero += [{v: lv.val, t: e_ty}];
|
|
|
|
} else { to_revoke += [{v: lv.val, t: e_ty}]; }
|
2011-08-09 17:56:26 -07:00
|
|
|
}
|
2011-06-24 19:04:08 +02:00
|
|
|
ret rslt(bcx, val);
|
2011-04-23 14:17:44 -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:
|
|
|
|
//
|
2011-09-14 14:34:50 +02:00
|
|
|
// - type_of_fn
|
2011-02-08 11:47:53 -08:00
|
|
|
// - create_llargs_for_fn_args.
|
|
|
|
// - new_fn_ctxt
|
|
|
|
// - trans_args
|
2011-11-23 10:56:10 +01:00
|
|
|
fn trans_args(cx: @block_ctxt, llenv: ValueRef,
|
2011-10-21 13:42:26 +02:00
|
|
|
gen: option::t<generic_info>, es: [@ast::expr], fn_ty: ty::t,
|
2011-10-05 10:21:40 +02:00
|
|
|
dest: dest)
|
2011-09-14 14:34:50 +02:00
|
|
|
-> {bcx: @block_ctxt,
|
|
|
|
args: [ValueRef],
|
|
|
|
retslot: ValueRef,
|
|
|
|
to_zero: [{v: ValueRef, t: ty::t}],
|
2011-11-23 10:56:10 +01:00
|
|
|
to_revoke: [{v: ValueRef, t: ty::t}]} {
|
2011-08-09 17:56:26 -07:00
|
|
|
|
2011-08-04 16:20:09 -07:00
|
|
|
let args: [ty::arg] = ty::ty_fn_args(bcx_tcx(cx), fn_ty);
|
2011-08-19 15:16:48 -07:00
|
|
|
let llargs: [ValueRef] = [];
|
|
|
|
let lltydescs: [ValueRef] = [];
|
|
|
|
let to_zero = [];
|
|
|
|
let to_revoke = [];
|
2011-08-09 17:56:26 -07:00
|
|
|
|
2011-09-14 16:19:15 +02:00
|
|
|
let ccx = bcx_ccx(cx);
|
|
|
|
let tcx = ccx.tcx;
|
2011-10-05 10:21:40 +02:00
|
|
|
let bcx = cx;
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-09-21 11:39:06 +02:00
|
|
|
let retty = ty::ty_fn_ret(tcx, fn_ty), full_retty = retty;
|
2011-07-27 14:19:39 +02:00
|
|
|
alt gen {
|
|
|
|
some(g) {
|
|
|
|
lazily_emit_all_generic_info_tydesc_glues(cx, g);
|
2012-01-02 16:50:51 +01:00
|
|
|
let i = 0u, n_orig = 0u;
|
|
|
|
for param in *g.param_bounds {
|
|
|
|
lltydescs += [g.tydescs[i]];
|
|
|
|
for bound in *param {
|
|
|
|
alt bound {
|
|
|
|
ty::bound_iface(_) {
|
|
|
|
let res = trans_impl::get_dict(
|
|
|
|
bcx, option::get(g.origins)[n_orig]);
|
|
|
|
lltydescs += [res.val];
|
|
|
|
bcx = res.bcx;
|
|
|
|
n_orig += 1u;
|
|
|
|
}
|
|
|
|
_ {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
i += 1u;
|
|
|
|
}
|
2011-09-14 14:34:50 +02:00
|
|
|
args = ty::ty_fn_args(tcx, g.item_type);
|
|
|
|
retty = ty::ty_fn_ret(tcx, g.item_type);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ { }
|
2011-02-08 11:47:53 -08:00
|
|
|
}
|
2011-09-21 12:40:27 +02:00
|
|
|
// Arg 0: Output pointer.
|
2011-11-23 10:56:10 +01:00
|
|
|
let llretslot = alt dest {
|
2012-01-18 22:37:22 -08:00
|
|
|
ignore {
|
2011-11-23 10:56:10 +01:00
|
|
|
if ty::type_is_nil(tcx, retty) {
|
2012-01-05 22:45:02 +01:00
|
|
|
llvm::LLVMGetUndef(T_ptr(T_nil()))
|
|
|
|
} else {
|
|
|
|
let {bcx: cx, val} = alloc_ty(bcx, full_retty);
|
|
|
|
bcx = cx;
|
|
|
|
val
|
|
|
|
}
|
2011-11-23 10:56:10 +01:00
|
|
|
}
|
|
|
|
save_in(dst) { dst }
|
2012-01-05 22:45:02 +01:00
|
|
|
by_val(_) {
|
|
|
|
let {bcx: cx, val} = alloc_ty(bcx, full_retty);
|
|
|
|
bcx = cx;
|
|
|
|
val
|
|
|
|
}
|
2011-10-05 10:21:40 +02:00
|
|
|
};
|
|
|
|
|
2011-09-14 14:34:50 +02:00
|
|
|
if ty::type_contains_params(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-09-15 20:47:38 -07:00
|
|
|
check non_ty_var(ccx, retty);
|
2011-09-14 16:19:15 +02:00
|
|
|
let llretty = T_ptr(type_of_inner(ccx, bcx.sp, retty));
|
2011-08-30 09:59:30 +02:00
|
|
|
llargs += [PointerCast(cx, llretslot, llretty)];
|
2011-08-19 15:16:48 -07:00
|
|
|
} else { llargs += [llretslot]; }
|
2011-02-08 11:47:53 -08:00
|
|
|
|
2012-01-13 10:58:31 +01:00
|
|
|
// Arg 1: Env (closure-bindings / self value)
|
2011-10-14 15:16:44 -07:00
|
|
|
llargs += [llenv];
|
2011-02-08 11:47:53 -08:00
|
|
|
|
2011-10-20 11:56:45 +02:00
|
|
|
// Args >2: ty_params ...
|
2011-06-15 11:19:50 -07:00
|
|
|
llargs += lltydescs;
|
|
|
|
|
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-09-14 16:19:15 +02:00
|
|
|
let arg_tys = type_of_explicit_args(ccx, cx.sp, args);
|
2011-11-23 10:56:10 +01:00
|
|
|
let i = 0u;
|
2011-08-15 21:54:52 -07:00
|
|
|
for e: @ast::expr in es {
|
2011-11-23 10:56:10 +01:00
|
|
|
let r = trans_arg_expr(bcx, args[i], arg_tys[i], to_zero, to_revoke,
|
|
|
|
e);
|
|
|
|
bcx = r.bcx;
|
2011-08-19 15:16:48 -07:00
|
|
|
llargs += [r.val];
|
2011-02-08 11:47:53 -08:00
|
|
|
i += 1u;
|
|
|
|
}
|
2011-08-19 15:16:48 -07:00
|
|
|
ret {bcx: bcx,
|
|
|
|
args: llargs,
|
|
|
|
retslot: llretslot,
|
|
|
|
to_zero: to_zero,
|
2011-11-23 10:56:10 +01:00
|
|
|
to_revoke: to_revoke};
|
2011-02-08 11:47:53 -08:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
|
2011-10-21 13:42:26 +02:00
|
|
|
args: [@ast::expr], id: ast::node_id, dest: dest)
|
|
|
|
-> @block_ctxt {
|
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.
|
2011-09-21 12:40:27 +02:00
|
|
|
let tcx = bcx_tcx(in_cx);
|
|
|
|
let fn_expr_ty = ty::expr_ty(tcx, f);
|
2011-09-29 17:33:41 -07:00
|
|
|
|
2011-09-16 12:42:18 +02:00
|
|
|
let cx = new_scope_block_ctxt(in_cx, "call");
|
2011-11-23 10:56:10 +01:00
|
|
|
Br(in_cx, cx.llbb);
|
2011-09-16 16:27:34 +02:00
|
|
|
let f_res = trans_callee(cx, f);
|
|
|
|
let bcx = f_res.bcx;
|
|
|
|
|
|
|
|
let faddr = f_res.val;
|
2012-01-02 16:50:51 +01:00
|
|
|
let llenv, dict_param = none;
|
2011-09-16 21:28:47 +02:00
|
|
|
alt f_res.env {
|
2012-01-18 22:37:22 -08:00
|
|
|
null_env {
|
2012-01-05 16:19:12 -08:00
|
|
|
llenv = llvm::LLVMGetUndef(T_opaque_cbox_ptr(bcx_ccx(cx)));
|
2011-09-21 11:39:06 +02:00
|
|
|
}
|
2012-01-13 10:58:31 +01:00
|
|
|
self_env(e) { llenv = e; }
|
2012-01-02 16:50:51 +01:00
|
|
|
dict_env(dict, e) { llenv = e; dict_param = some(dict); }
|
2012-01-18 22:37:22 -08:00
|
|
|
is_closure {
|
2011-09-16 16:27:34 +02:00
|
|
|
// It's a closure. Have to fetch the elements
|
2011-10-07 11:20:51 +02:00
|
|
|
if f_res.kind == owned {
|
|
|
|
faddr = load_if_immediate(bcx, faddr, fn_expr_ty);
|
|
|
|
}
|
2011-09-16 14:35:39 +02:00
|
|
|
let pair = faddr;
|
2011-10-25 22:23:28 -07:00
|
|
|
faddr = GEPi(bcx, pair, [0, abi::fn_field_code]);
|
2011-08-30 09:59:30 +02:00
|
|
|
faddr = Load(bcx, faddr);
|
2011-10-25 22:23:28 -07:00
|
|
|
let llclosure = GEPi(bcx, pair, [0, abi::fn_field_box]);
|
2011-09-16 21:28:47 +02:00
|
|
|
llenv = Load(bcx, llclosure);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-09-16 21:28:47 +02:00
|
|
|
}
|
2011-07-01 02:52:05 -07:00
|
|
|
|
2011-09-21 12:40:27 +02:00
|
|
|
let ret_ty = ty::node_id_to_type(tcx, id);
|
2011-07-27 14:19:39 +02:00
|
|
|
let args_res =
|
2011-11-23 10:56:10 +01:00
|
|
|
trans_args(bcx, llenv, f_res.generic, args, fn_expr_ty, dest);
|
2011-07-26 14:06:02 +02:00
|
|
|
bcx = args_res.bcx;
|
2011-07-27 14:19:39 +02:00
|
|
|
let llargs = args_res.args;
|
2012-01-02 16:50:51 +01:00
|
|
|
option::may(dict_param) {|dict| llargs = [dict] + llargs}
|
2011-07-27 14:19:39 +02:00
|
|
|
let llretslot = args_res.retslot;
|
2011-09-02 15:12:27 -07:00
|
|
|
|
2011-07-02 21:55:38 -07:00
|
|
|
/* If the block is terminated,
|
|
|
|
then one or more of the args has
|
|
|
|
type _|_. Since that means it diverges, the code
|
|
|
|
for the call itself is unreachable. */
|
2011-09-27 18:42:06 -07:00
|
|
|
bcx = invoke_full(bcx, faddr, llargs, args_res.to_zero,
|
|
|
|
args_res.to_revoke);
|
2011-10-05 10:21:40 +02:00
|
|
|
alt dest {
|
2012-01-18 22:37:22 -08:00
|
|
|
ignore {
|
2011-11-23 10:56:10 +01:00
|
|
|
if llvm::LLVMIsUndef(llretslot) != lib::llvm::True {
|
2011-10-05 10:21:40 +02:00
|
|
|
bcx = drop_ty(bcx, llretslot, ret_ty);
|
2011-04-23 14:17:44 -07:00
|
|
|
}
|
2011-09-21 12:40:27 +02:00
|
|
|
}
|
2011-10-05 10:21:40 +02:00
|
|
|
save_in(_) { } // Already saved by callee
|
2011-10-05 10:41:30 +02:00
|
|
|
by_val(cell) {
|
2011-10-05 10:21:40 +02:00
|
|
|
*cell = Load(bcx, llretslot);
|
2011-09-21 12:40:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Forget about anything we moved out.
|
|
|
|
bcx = zero_and_revoke(bcx, args_res.to_zero, args_res.to_revoke);
|
2011-08-09 17:56:26 -07:00
|
|
|
|
2011-10-05 10:21:40 +02:00
|
|
|
bcx = trans_block_cleanups(bcx, cx);
|
2011-09-21 12:40:27 +02:00
|
|
|
let next_cx = new_sub_block_ctxt(in_cx, "next");
|
|
|
|
if bcx.unreachable || ty::type_is_bot(tcx, ret_ty) {
|
|
|
|
Unreachable(next_cx);
|
2011-03-31 11:26:25 -07:00
|
|
|
}
|
2011-09-21 12:40:27 +02:00
|
|
|
Br(bcx, next_cx.llbb);
|
2011-10-05 10:21:40 +02:00
|
|
|
ret next_cx;
|
2011-03-31 11:26:25 -07:00
|
|
|
}
|
|
|
|
|
2011-09-16 14:37:58 -07:00
|
|
|
fn zero_and_revoke(bcx: @block_ctxt,
|
|
|
|
to_zero: [{v: ValueRef, t: ty::t}],
|
|
|
|
to_revoke: [{v: ValueRef, t: ty::t}]) -> @block_ctxt {
|
|
|
|
let bcx = bcx;
|
|
|
|
for {v, t} in to_zero {
|
2011-09-23 21:13:38 +02:00
|
|
|
bcx = zero_alloca(bcx, v, t);
|
2011-09-16 14:37:58 -07:00
|
|
|
}
|
2011-11-18 15:10:14 +01:00
|
|
|
for {v, _} in to_revoke { revoke_clean(bcx, v); }
|
2011-09-16 14:37:58 -07:00
|
|
|
ret bcx;
|
|
|
|
}
|
|
|
|
|
2011-09-12 09:36:51 -07:00
|
|
|
fn invoke(bcx: @block_ctxt, llfn: ValueRef,
|
2011-09-21 12:40:27 +02:00
|
|
|
llargs: [ValueRef]) -> @block_ctxt {
|
2011-09-16 14:37:58 -07:00
|
|
|
ret invoke_(bcx, llfn, llargs, [], [], Invoke);
|
2011-09-07 16:39:08 -07:00
|
|
|
}
|
|
|
|
|
2011-09-27 18:42:06 -07:00
|
|
|
fn invoke_full(bcx: @block_ctxt, llfn: ValueRef, llargs: [ValueRef],
|
|
|
|
to_zero: [{v: ValueRef, t: ty::t}],
|
|
|
|
to_revoke: [{v: ValueRef, t: ty::t}]) -> @block_ctxt {
|
|
|
|
ret invoke_(bcx, llfn, llargs, to_zero, to_revoke, Invoke);
|
2011-09-07 16:39:08 -07:00
|
|
|
}
|
2011-09-07 11:46:53 -07:00
|
|
|
|
2011-09-16 14:37:58 -07:00
|
|
|
fn invoke_(bcx: @block_ctxt, llfn: ValueRef, llargs: [ValueRef],
|
|
|
|
to_zero: [{v: ValueRef, t: ty::t}],
|
|
|
|
to_revoke: [{v: ValueRef, t: ty::t}],
|
2012-01-11 09:58:05 -08:00
|
|
|
invoker: block(@block_ctxt, ValueRef, [ValueRef],
|
|
|
|
BasicBlockRef, BasicBlockRef)) -> @block_ctxt {
|
2011-09-07 17:43:55 -07:00
|
|
|
// FIXME: May be worth turning this into a plain call when there are no
|
|
|
|
// cleanups to run
|
2011-09-21 12:40:27 +02:00
|
|
|
if bcx.unreachable { ret bcx; }
|
2011-09-07 11:46:53 -07:00
|
|
|
let normal_bcx = new_sub_block_ctxt(bcx, "normal return");
|
2012-01-02 16:50:51 +01:00
|
|
|
invoker(bcx, llfn, llargs, normal_bcx.llbb,
|
2011-09-21 12:40:27 +02:00
|
|
|
get_landing_pad(bcx, to_zero, to_revoke));
|
|
|
|
ret normal_bcx;
|
2011-09-07 11:46:53 -07:00
|
|
|
}
|
|
|
|
|
2011-09-16 14:37:58 -07:00
|
|
|
fn get_landing_pad(bcx: @block_ctxt,
|
|
|
|
to_zero: [{v: ValueRef, t: ty::t}],
|
|
|
|
to_revoke: [{v: ValueRef, t: ty::t}]
|
|
|
|
) -> BasicBlockRef {
|
|
|
|
let have_zero_or_revoke = vec::is_not_empty(to_zero)
|
|
|
|
|| vec::is_not_empty(to_revoke);
|
|
|
|
let scope_bcx = find_scope_for_lpad(bcx, have_zero_or_revoke);
|
|
|
|
if scope_bcx.lpad_dirty || have_zero_or_revoke {
|
2011-09-13 16:10:39 -07:00
|
|
|
let unwind_bcx = new_sub_block_ctxt(bcx, "unwind");
|
2011-10-10 10:58:53 +02:00
|
|
|
trans_landing_pad(unwind_bcx, to_zero, to_revoke);
|
|
|
|
scope_bcx.lpad = some(unwind_bcx.llbb);
|
2011-09-16 14:37:58 -07:00
|
|
|
scope_bcx.lpad_dirty = have_zero_or_revoke;
|
2011-09-13 16:10:39 -07:00
|
|
|
}
|
|
|
|
assert option::is_some(scope_bcx.lpad);
|
|
|
|
ret option::get(scope_bcx.lpad);
|
2011-09-13 16:40:18 -07:00
|
|
|
|
2011-09-16 14:37:58 -07:00
|
|
|
fn find_scope_for_lpad(bcx: @block_ctxt,
|
|
|
|
have_zero_or_revoke: bool) -> @block_ctxt {
|
2011-09-13 16:40:18 -07:00
|
|
|
let scope_bcx = bcx;
|
|
|
|
while true {
|
|
|
|
scope_bcx = find_scope_cx(scope_bcx);
|
2011-09-16 14:37:58 -07:00
|
|
|
if vec::is_not_empty(scope_bcx.cleanups)
|
|
|
|
|| have_zero_or_revoke {
|
2011-09-13 16:40:18 -07:00
|
|
|
ret scope_bcx;
|
|
|
|
} else {
|
|
|
|
scope_bcx = alt scope_bcx.parent {
|
|
|
|
parent_some(b) { b }
|
2012-01-18 22:37:22 -08:00
|
|
|
parent_none {
|
2011-09-13 16:40:18 -07:00
|
|
|
ret scope_bcx;
|
|
|
|
}
|
2011-09-15 09:48:39 +02:00
|
|
|
};
|
2011-09-13 16:40:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
fail;
|
|
|
|
}
|
2011-09-13 16:10:39 -07:00
|
|
|
}
|
|
|
|
|
2011-09-16 14:37:58 -07:00
|
|
|
fn trans_landing_pad(bcx: @block_ctxt,
|
|
|
|
to_zero: [{v: ValueRef, t: ty::t}],
|
2011-09-21 12:40:27 +02:00
|
|
|
to_revoke: [{v: ValueRef, t: ty::t}]) -> BasicBlockRef {
|
2011-09-07 14:28:02 -07:00
|
|
|
// The landing pad return type (the type being propagated). Not sure what
|
|
|
|
// this represents but it's determined by the personality function and
|
|
|
|
// this is what the EH proposal example uses.
|
|
|
|
let llretty = T_struct([T_ptr(T_i8()), T_i32()]);
|
|
|
|
// The exception handling personality function. This is the C++
|
|
|
|
// personality function __gxx_personality_v0, wrapped in our naming
|
|
|
|
// convention.
|
|
|
|
let personality = bcx_ccx(bcx).upcalls.rust_personality;
|
|
|
|
// The only landing pad clause will be 'cleanup'
|
|
|
|
let clauses = 1u;
|
|
|
|
let llpad = LandingPad(bcx, llretty, personality, clauses);
|
|
|
|
// The landing pad result is used both for modifying the landing pad
|
|
|
|
// in the C API and as the exception value
|
|
|
|
let llretval = llpad;
|
|
|
|
// The landing pad block is a cleanup
|
|
|
|
SetCleanup(bcx, llpad);
|
2011-09-07 15:12:37 -07:00
|
|
|
|
2011-12-06 16:26:47 -08:00
|
|
|
// Because we may have unwound across a stack boundary, we must call into
|
|
|
|
// the runtime to figure out which stack segment we are on and place the
|
|
|
|
// stack limit back into the TLS.
|
|
|
|
Call(bcx, bcx_ccx(bcx).upcalls.reset_stack_limit, []);
|
|
|
|
|
2011-09-07 17:43:55 -07:00
|
|
|
// FIXME: This seems like a very naive and redundant way to generate the
|
|
|
|
// landing pads, as we're re-generating all in-scope cleanups for each
|
|
|
|
// function call. Probably good optimization opportunities here.
|
2011-09-16 14:37:58 -07:00
|
|
|
let bcx = zero_and_revoke(bcx, to_zero, to_revoke);
|
2011-09-07 15:12:37 -07:00
|
|
|
let scope_cx = bcx;
|
|
|
|
while true {
|
|
|
|
scope_cx = find_scope_cx(scope_cx);
|
|
|
|
bcx = trans_block_cleanups(bcx, scope_cx);
|
|
|
|
scope_cx = alt scope_cx.parent {
|
|
|
|
parent_some(b) { b }
|
2012-01-18 22:37:22 -08:00
|
|
|
parent_none { break; }
|
2011-09-07 15:12:37 -07:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2011-09-07 14:28:02 -07:00
|
|
|
// Continue unwinding
|
|
|
|
Resume(bcx, llretval);
|
2011-09-13 16:10:39 -07:00
|
|
|
ret bcx.llbb;
|
2011-09-07 11:46:53 -07:00
|
|
|
}
|
|
|
|
|
2011-09-26 13:21:47 +02:00
|
|
|
fn trans_tup(bcx: @block_ctxt, elts: [@ast::expr], id: ast::node_id,
|
|
|
|
dest: dest) -> @block_ctxt {
|
2011-08-15 11:40:26 +02:00
|
|
|
let t = node_id_type(bcx.fcx.lcx.ccx, id);
|
2011-11-03 10:57:54 +01:00
|
|
|
let bcx = bcx;
|
2011-10-05 10:21:48 +02:00
|
|
|
let addr = alt dest {
|
2012-01-18 22:37:22 -08:00
|
|
|
ignore {
|
2011-10-05 11:26:27 +02:00
|
|
|
for ex in elts { bcx = trans_expr(bcx, ex, ignore); }
|
2011-09-27 12:02:01 +02:00
|
|
|
ret bcx;
|
|
|
|
}
|
2011-10-05 10:21:48 +02:00
|
|
|
save_in(pos) { pos }
|
2011-09-27 12:02:01 +02:00
|
|
|
};
|
2011-09-26 22:13:08 +02:00
|
|
|
let temp_cleanups = [], i = 0;
|
2011-08-15 11:40:26 +02:00
|
|
|
for e in elts {
|
2011-09-27 12:02:01 +02:00
|
|
|
let dst = GEP_tup_like_1(bcx, t, addr, [0, i]);
|
|
|
|
let e_ty = ty::expr_ty(bcx_tcx(bcx), e);
|
2011-10-05 10:21:48 +02:00
|
|
|
bcx = trans_expr_save_in(dst.bcx, e, dst.val);
|
2011-09-27 12:02:01 +02:00
|
|
|
add_clean_temp_mem(bcx, dst.val, e_ty);
|
|
|
|
temp_cleanups += [dst.val];
|
2011-08-15 11:40:26 +02:00
|
|
|
i += 1;
|
|
|
|
}
|
2011-09-26 22:13:08 +02:00
|
|
|
for cleanup in temp_cleanups { revoke_clean(bcx, cleanup); }
|
2011-09-26 13:21:47 +02:00
|
|
|
ret bcx;
|
2011-08-15 11:40:26 +02:00
|
|
|
}
|
|
|
|
|
2011-09-26 13:21:47 +02:00
|
|
|
fn trans_rec(bcx: @block_ctxt, fields: [ast::field],
|
|
|
|
base: option::t<@ast::expr>, id: ast::node_id,
|
|
|
|
dest: dest) -> @block_ctxt {
|
2011-07-27 14:19:39 +02:00
|
|
|
let t = node_id_type(bcx_ccx(bcx), id);
|
2011-11-03 10:57:54 +01:00
|
|
|
let bcx = bcx;
|
2011-10-05 10:21:48 +02:00
|
|
|
let addr = alt dest {
|
2012-01-18 22:37:22 -08:00
|
|
|
ignore {
|
2011-09-27 12:02:01 +02:00
|
|
|
for fld in fields {
|
2011-10-05 11:26:27 +02:00
|
|
|
bcx = trans_expr(bcx, fld.node.expr, ignore);
|
2011-09-27 12:02:01 +02:00
|
|
|
}
|
|
|
|
ret bcx;
|
|
|
|
}
|
2011-10-05 10:21:48 +02:00
|
|
|
save_in(pos) { pos }
|
2011-09-27 12:02:01 +02:00
|
|
|
};
|
2011-09-26 13:21:47 +02:00
|
|
|
|
2011-11-18 15:59:47 +01:00
|
|
|
let ty_fields = alt ty::struct(bcx_tcx(bcx), t) { ty::ty_rec(f) { f } };
|
|
|
|
let temp_cleanups = [];
|
|
|
|
for fld in fields {
|
2011-12-16 06:27:50 -08:00
|
|
|
let ix = option::get(vec::position_pred(ty_fields, {|ft|
|
2011-11-18 15:59:47 +01:00
|
|
|
str::eq(fld.node.ident, ft.ident)
|
2011-12-16 06:27:50 -08:00
|
|
|
}));
|
2011-11-18 15:59:47 +01:00
|
|
|
let dst = GEP_tup_like_1(bcx, t, addr, [0, ix as int]);
|
|
|
|
bcx = trans_expr_save_in(dst.bcx, fld.node.expr, dst.val);
|
|
|
|
add_clean_temp_mem(bcx, dst.val, ty_fields[ix].mt.ty);
|
|
|
|
temp_cleanups += [dst.val];
|
|
|
|
}
|
|
|
|
alt base {
|
2011-07-27 14:19:39 +02:00
|
|
|
some(bexp) {
|
2011-11-18 15:59:47 +01:00
|
|
|
let {bcx: cx, val: base_val} = trans_temp_expr(bcx, bexp), i = 0;
|
|
|
|
bcx = cx;
|
|
|
|
// Copy over inherited fields
|
|
|
|
for tf in ty_fields {
|
2011-12-16 06:27:50 -08:00
|
|
|
if !vec::any(fields, {|f| str::eq(f.node.ident, tf.ident)}) {
|
2011-11-18 15:59:47 +01:00
|
|
|
let dst = GEP_tup_like_1(bcx, t, addr, [0, i]);
|
|
|
|
let base = GEP_tup_like_1(bcx, t, base_val, [0, i]);
|
|
|
|
let val = load_if_immediate(base.bcx, base.val, tf.mt.ty);
|
|
|
|
bcx = copy_val(base.bcx, INIT, dst.val, val, tf.mt.ty);
|
|
|
|
}
|
|
|
|
i += 1;
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
none {}
|
2011-09-26 13:21:47 +02:00
|
|
|
};
|
2011-09-19 14:20:15 -07:00
|
|
|
|
2011-09-26 22:13:08 +02:00
|
|
|
// Now revoke the cleanups as we pass responsibility for the data
|
|
|
|
// structure on to the caller
|
|
|
|
for cleanup in temp_cleanups { revoke_clean(bcx, cleanup); }
|
2011-09-26 13:21:47 +02:00
|
|
|
ret bcx;
|
2010-11-30 10:39:35 -08:00
|
|
|
}
|
|
|
|
|
2011-10-05 12:23:18 +02:00
|
|
|
// Store the result of an expression in the given memory location, ensuring
|
|
|
|
// that nil or bot expressions get ignore rather than save_in as destination.
|
2011-10-05 10:21:48 +02:00
|
|
|
fn trans_expr_save_in(bcx: @block_ctxt, e: @ast::expr, dest: ValueRef)
|
|
|
|
-> @block_ctxt {
|
2011-09-26 13:21:47 +02:00
|
|
|
let tcx = bcx_tcx(bcx), t = ty::expr_ty(tcx, e);
|
2011-10-05 12:23:18 +02:00
|
|
|
let do_ignore = ty::type_is_bot(tcx, t) || ty::type_is_nil(tcx, t);
|
|
|
|
ret trans_expr(bcx, e, do_ignore ? ignore : save_in(dest));
|
2011-10-04 16:37:56 +02:00
|
|
|
}
|
|
|
|
|
2011-10-05 12:23:18 +02:00
|
|
|
// Call this to compile an expression that you need as an intermediate value,
|
2011-10-07 11:20:51 +02:00
|
|
|
// and you want to know whether you're dealing with an lval or not (the kind
|
2011-11-18 10:20:51 +01:00
|
|
|
// field in the returned struct). For non-intermediates, use trans_expr or
|
2011-10-05 12:23:18 +02:00
|
|
|
// trans_expr_save_in. For intermediates where you don't care about lval-ness,
|
|
|
|
// use trans_temp_expr.
|
2011-10-05 11:26:27 +02:00
|
|
|
fn trans_temp_lval(bcx: @block_ctxt, e: @ast::expr) -> lval_result {
|
2011-11-03 10:57:54 +01:00
|
|
|
let bcx = bcx;
|
2011-12-14 15:23:11 +01:00
|
|
|
if expr_is_lval(bcx, e) {
|
2011-10-05 10:21:48 +02:00
|
|
|
ret trans_lval(bcx, e);
|
|
|
|
} else {
|
|
|
|
let tcx = bcx_tcx(bcx);
|
|
|
|
let ty = ty::expr_ty(tcx, e);
|
|
|
|
if ty::type_is_nil(tcx, ty) || ty::type_is_bot(tcx, ty) {
|
2011-10-05 11:26:27 +02:00
|
|
|
bcx = trans_expr(bcx, e, ignore);
|
2011-10-07 11:20:51 +02:00
|
|
|
ret {bcx: bcx, val: C_nil(), kind: temporary};
|
2011-10-10 12:23:58 +02:00
|
|
|
} else if ty::type_is_immediate(bcx_tcx(bcx), ty) {
|
2011-10-05 10:21:48 +02:00
|
|
|
let cell = empty_dest_cell();
|
2011-10-05 11:26:27 +02:00
|
|
|
bcx = trans_expr(bcx, e, by_val(cell));
|
|
|
|
add_clean_temp(bcx, *cell, ty);
|
2011-10-07 11:20:51 +02:00
|
|
|
ret {bcx: bcx, val: *cell, kind: temporary};
|
2011-10-05 10:21:48 +02:00
|
|
|
} else {
|
|
|
|
let {bcx, val: scratch} = alloc_ty(bcx, ty);
|
2011-10-14 11:27:16 +02:00
|
|
|
bcx = trans_expr_save_in(bcx, e, scratch);
|
2011-10-05 11:26:27 +02:00
|
|
|
add_clean_temp(bcx, scratch, ty);
|
2011-10-07 11:20:51 +02:00
|
|
|
ret {bcx: bcx, val: scratch, kind: temporary};
|
2011-10-05 10:21:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-05 12:23:18 +02:00
|
|
|
// Use only for intermediate values. See trans_expr and trans_expr_save_in for
|
|
|
|
// expressions that must 'end up somewhere' (or get ignored).
|
2011-10-05 11:26:27 +02:00
|
|
|
fn trans_temp_expr(bcx: @block_ctxt, e: @ast::expr) -> result {
|
2011-10-07 11:20:51 +02:00
|
|
|
let {bcx, val, kind} = trans_temp_lval(bcx, e);
|
|
|
|
if kind == owned {
|
|
|
|
val = load_if_immediate(bcx, val, ty::expr_ty(bcx_tcx(bcx), e));
|
2011-10-05 11:26:27 +02:00
|
|
|
}
|
|
|
|
ret {bcx: bcx, val: val};
|
|
|
|
}
|
|
|
|
|
2011-10-05 12:23:18 +02:00
|
|
|
// Translate an expression, with the dest argument deciding what happens with
|
|
|
|
// the result. Invariants:
|
|
|
|
// - exprs returning nil or bot always get dest=ignore
|
|
|
|
// - exprs with non-immediate type never get dest=by_val
|
|
|
|
fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
|
2011-09-29 11:18:40 +02:00
|
|
|
let tcx = bcx_tcx(bcx);
|
2011-12-18 23:32:38 -05:00
|
|
|
debuginfo::update_source_pos(bcx, e.span);
|
2011-11-15 21:11:22 -05:00
|
|
|
|
2011-12-14 15:23:11 +01:00
|
|
|
if expr_is_lval(bcx, e) {
|
2011-12-14 14:38:25 +01:00
|
|
|
ret lval_to_dps(bcx, e, dest);
|
|
|
|
}
|
2011-09-29 11:18:40 +02:00
|
|
|
|
2011-09-23 21:13:50 +02:00
|
|
|
alt e.node {
|
|
|
|
ast::expr_if(cond, thn, els) | ast::expr_if_check(cond, thn, els) {
|
|
|
|
ret trans_if(bcx, cond, thn, els, dest);
|
|
|
|
}
|
|
|
|
ast::expr_ternary(_, _, _) {
|
2011-10-05 11:26:27 +02:00
|
|
|
ret trans_expr(bcx, ast_util::ternary_to_if(e), dest);
|
2011-09-23 21:13:50 +02:00
|
|
|
}
|
|
|
|
ast::expr_alt(expr, arms) {
|
2012-01-14 16:05:07 -08:00
|
|
|
// tcx.sess.span_note(e.span, "about to call trans_alt");
|
2011-09-23 21:13:50 +02:00
|
|
|
ret trans_alt::trans_alt(bcx, expr, arms, dest);
|
|
|
|
}
|
|
|
|
ast::expr_block(blk) {
|
|
|
|
let sub_cx = new_scope_block_ctxt(bcx, "block-expr body");
|
|
|
|
Br(bcx, sub_cx.llbb);
|
|
|
|
sub_cx = trans_block_dps(sub_cx, blk, dest);
|
|
|
|
let next_cx = new_sub_block_ctxt(bcx, "next");
|
|
|
|
Br(sub_cx, next_cx.llbb);
|
|
|
|
if sub_cx.unreachable { Unreachable(next_cx); }
|
|
|
|
ret next_cx;
|
|
|
|
}
|
2011-09-26 13:21:47 +02:00
|
|
|
ast::expr_rec(args, base) {
|
|
|
|
ret trans_rec(bcx, args, base, e.id, dest);
|
|
|
|
}
|
|
|
|
ast::expr_tup(args) { ret trans_tup(bcx, args, e.id, dest); }
|
2011-09-27 08:42:27 +02:00
|
|
|
ast::expr_lit(lit) { ret trans_lit(bcx, *lit, dest); }
|
|
|
|
ast::expr_vec(args, _) { ret tvec::trans_vec(bcx, args, e.id, dest); }
|
2011-09-27 10:50:18 +02:00
|
|
|
ast::expr_binary(op, x, y) { ret trans_binary(bcx, op, x, y, dest); }
|
2011-09-27 13:19:55 +02:00
|
|
|
ast::expr_unary(op, x) {
|
2011-09-29 11:18:40 +02:00
|
|
|
assert op != ast::deref; // lvals are handled above
|
2011-09-27 13:19:55 +02:00
|
|
|
ret trans_unary(bcx, op, x, e.id, dest);
|
|
|
|
}
|
2011-12-29 20:07:55 -08:00
|
|
|
ast::expr_fn(proto, decl, body, cap_clause) {
|
2011-12-19 12:50:31 -08:00
|
|
|
ret trans_closure::trans_expr_fn(
|
2011-12-29 20:07:55 -08:00
|
|
|
bcx, proto, decl, body, e.span, e.id, *cap_clause, dest);
|
2011-12-14 13:57:10 -08:00
|
|
|
}
|
2011-12-20 11:03:21 -08:00
|
|
|
ast::expr_fn_block(decl, body) {
|
|
|
|
alt ty::struct(tcx, ty::expr_ty(tcx, e)) {
|
2011-12-23 16:09:52 +01:00
|
|
|
ty::ty_fn({proto, _}) {
|
2011-12-29 20:07:55 -08:00
|
|
|
#debug("translating fn_block %s with type %s",
|
|
|
|
expr_to_str(e), ty_to_str(tcx, ty::expr_ty(tcx, e)));
|
2011-12-20 11:03:21 -08:00
|
|
|
let cap_clause = { copies: [], moves: [] };
|
|
|
|
ret trans_closure::trans_expr_fn(
|
2011-12-29 20:07:55 -08:00
|
|
|
bcx, proto, decl, body, e.span, e.id, cap_clause, dest);
|
2011-12-20 11:03:21 -08:00
|
|
|
}
|
|
|
|
_ {
|
|
|
|
fail "Type of fn block is not a function!";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-12-14 13:57:10 -08:00
|
|
|
ast::expr_bind(f, args) {
|
2011-12-19 12:50:31 -08:00
|
|
|
ret trans_closure::trans_bind(
|
|
|
|
bcx, f, args, e.id, dest);
|
2011-12-14 13:57:10 -08:00
|
|
|
}
|
2011-09-29 10:46:49 +02:00
|
|
|
ast::expr_copy(a) {
|
2011-12-14 15:23:11 +01:00
|
|
|
if !expr_is_lval(bcx, a) {
|
2011-12-14 14:38:25 +01:00
|
|
|
ret trans_expr(bcx, a, dest);
|
|
|
|
}
|
2011-09-29 11:18:40 +02:00
|
|
|
else { ret lval_to_dps(bcx, a, dest); }
|
2011-09-29 10:46:49 +02:00
|
|
|
}
|
2011-12-22 13:47:30 +01:00
|
|
|
ast::expr_cast(val, _) { ret trans_cast(bcx, val, e.id, dest); }
|
2011-10-21 14:11:24 +02:00
|
|
|
ast::expr_call(f, args, _) {
|
2011-10-21 13:42:26 +02:00
|
|
|
ret trans_call(bcx, f, args, e.id, dest);
|
2011-10-05 10:21:40 +02:00
|
|
|
}
|
2011-12-19 10:21:31 +01:00
|
|
|
ast::expr_field(_, _, _) {
|
2011-10-05 10:21:57 +02:00
|
|
|
fail "Taking the value of a method does not work yet (issue #435)";
|
2011-09-29 11:18:40 +02:00
|
|
|
}
|
2011-09-27 08:42:27 +02:00
|
|
|
|
2011-09-28 15:57:38 +02:00
|
|
|
// These return nothing
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::expr_break {
|
2011-09-26 13:21:47 +02:00
|
|
|
assert dest == ignore;
|
|
|
|
ret trans_break(e.span, bcx);
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::expr_cont {
|
2011-09-26 13:21:47 +02:00
|
|
|
assert dest == ignore;
|
|
|
|
ret trans_cont(e.span, bcx);
|
|
|
|
}
|
|
|
|
ast::expr_ret(ex) {
|
|
|
|
assert dest == ignore;
|
|
|
|
ret trans_ret(bcx, ex);
|
|
|
|
}
|
|
|
|
ast::expr_be(ex) {
|
2012-01-19 14:24:03 -08:00
|
|
|
// Ideally, the expr_be enum would have a precondition
|
2011-09-26 13:21:47 +02:00
|
|
|
// that is_call_expr(ex) -- but we don't support that
|
|
|
|
// yet
|
|
|
|
// FIXME
|
2011-12-22 13:47:30 +01:00
|
|
|
check (ast_util::is_call_expr(ex));
|
2011-09-26 13:21:47 +02:00
|
|
|
ret trans_be(bcx, ex);
|
|
|
|
}
|
|
|
|
ast::expr_fail(expr) {
|
|
|
|
assert dest == ignore;
|
|
|
|
ret trans_fail_expr(bcx, some(e.span), expr);
|
|
|
|
}
|
2011-12-21 14:31:31 -08:00
|
|
|
ast::expr_log(_, lvl, a) {
|
2011-09-26 13:21:47 +02:00
|
|
|
assert dest == ignore;
|
|
|
|
ret trans_log(lvl, bcx, a);
|
|
|
|
}
|
|
|
|
ast::expr_assert(a) {
|
|
|
|
assert dest == ignore;
|
|
|
|
ret trans_check_expr(bcx, a, "Assertion");
|
|
|
|
}
|
2012-01-19 01:03:57 -08:00
|
|
|
ast::expr_check(ast::checked_expr, a) {
|
2011-09-26 13:21:47 +02:00
|
|
|
assert dest == ignore;
|
|
|
|
ret trans_check_expr(bcx, a, "Predicate");
|
|
|
|
}
|
2012-01-19 01:03:57 -08:00
|
|
|
ast::expr_check(ast::claimed_expr, a) {
|
2011-09-26 13:21:47 +02:00
|
|
|
assert dest == ignore;
|
|
|
|
/* Claims are turned on and off by a global variable
|
|
|
|
that the RTS sets. This case generates code to
|
|
|
|
check the value of that variable, doing nothing
|
|
|
|
if it's set to false and acting like a check
|
|
|
|
otherwise. */
|
|
|
|
let c =
|
|
|
|
get_extern_const(bcx_ccx(bcx).externs, bcx_ccx(bcx).llmod,
|
|
|
|
"check_claims", T_bool());
|
|
|
|
let cond = Load(bcx, c);
|
|
|
|
|
|
|
|
let then_cx = new_scope_block_ctxt(bcx, "claim_then");
|
|
|
|
let check_cx = trans_check_expr(then_cx, a, "Claim");
|
2011-10-05 12:23:18 +02:00
|
|
|
let next_cx = new_sub_block_ctxt(bcx, "join");
|
2011-09-26 13:21:47 +02:00
|
|
|
|
2011-10-05 12:23:18 +02:00
|
|
|
CondBr(bcx, cond, then_cx.llbb, next_cx.llbb);
|
|
|
|
Br(check_cx, next_cx.llbb);
|
|
|
|
ret next_cx;
|
2011-09-26 13:21:47 +02:00
|
|
|
}
|
2011-09-27 08:03:06 +02:00
|
|
|
ast::expr_for(decl, seq, body) {
|
|
|
|
assert dest == ignore;
|
|
|
|
ret trans_for(bcx, decl, seq, body);
|
|
|
|
}
|
|
|
|
ast::expr_while(cond, body) {
|
|
|
|
assert dest == ignore;
|
|
|
|
ret trans_while(bcx, cond, body);
|
|
|
|
}
|
|
|
|
ast::expr_do_while(body, cond) {
|
|
|
|
assert dest == ignore;
|
|
|
|
ret trans_do_while(bcx, body, cond);
|
|
|
|
}
|
|
|
|
ast::expr_assign(dst, src) {
|
|
|
|
assert dest == ignore;
|
2011-10-05 11:26:27 +02:00
|
|
|
let src_r = trans_temp_lval(bcx, src);
|
2011-10-07 11:20:51 +02:00
|
|
|
let {bcx, val: addr, kind} = trans_lval(src_r.bcx, dst);
|
|
|
|
assert kind == owned;
|
2011-10-05 12:23:18 +02:00
|
|
|
ret store_temp_expr(bcx, DROP_EXISTING, addr, src_r,
|
2011-11-18 15:10:14 +01:00
|
|
|
ty::expr_ty(bcx_tcx(bcx), src),
|
|
|
|
bcx_ccx(bcx).last_uses.contains_key(src.id));
|
2011-09-27 08:03:06 +02:00
|
|
|
}
|
2011-09-28 15:15:29 +02:00
|
|
|
ast::expr_move(dst, src) {
|
2011-10-05 10:21:48 +02:00
|
|
|
// FIXME: calculate copy init-ness in typestate.
|
2011-09-28 15:15:29 +02:00
|
|
|
assert dest == ignore;
|
2011-10-05 11:26:27 +02:00
|
|
|
let src_r = trans_temp_lval(bcx, src);
|
2011-10-07 11:20:51 +02:00
|
|
|
let {bcx, val: addr, kind} = trans_lval(src_r.bcx, dst);
|
|
|
|
assert kind == owned;
|
2011-10-05 10:21:48 +02:00
|
|
|
ret move_val(bcx, DROP_EXISTING, addr, src_r,
|
|
|
|
ty::expr_ty(bcx_tcx(bcx), src));
|
2011-09-28 15:15:29 +02:00
|
|
|
}
|
2011-09-27 08:03:06 +02:00
|
|
|
ast::expr_swap(dst, src) {
|
|
|
|
assert dest == ignore;
|
|
|
|
let lhs_res = trans_lval(bcx, dst);
|
2011-10-07 11:20:51 +02:00
|
|
|
assert lhs_res.kind == owned;
|
2011-09-27 08:03:06 +02:00
|
|
|
let rhs_res = trans_lval(lhs_res.bcx, src);
|
2011-09-29 11:18:40 +02:00
|
|
|
let t = ty::expr_ty(tcx, src);
|
2011-09-27 08:03:06 +02:00
|
|
|
let {bcx: bcx, val: tmp_alloc} = alloc_ty(rhs_res.bcx, t);
|
|
|
|
// Swap through a temporary.
|
|
|
|
bcx = move_val(bcx, INIT, tmp_alloc, lhs_res, t);
|
|
|
|
bcx = move_val(bcx, INIT, lhs_res.val, rhs_res, t);
|
2011-10-07 11:20:51 +02:00
|
|
|
ret move_val(bcx, INIT, rhs_res.val, lval_owned(bcx, tmp_alloc), t);
|
2011-09-27 08:03:06 +02:00
|
|
|
}
|
|
|
|
ast::expr_assign_op(op, dst, src) {
|
|
|
|
assert dest == ignore;
|
|
|
|
ret trans_assign_op(bcx, op, dst, src);
|
|
|
|
}
|
2011-09-27 13:19:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-29 11:18:40 +02:00
|
|
|
fn lval_to_dps(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
|
2011-11-18 15:10:14 +01:00
|
|
|
let lv = trans_lval(bcx, e), ccx = bcx_ccx(bcx);
|
2011-10-07 11:20:51 +02:00
|
|
|
let {bcx, val, kind} = lv;
|
2011-11-18 15:10:14 +01:00
|
|
|
let last_use = kind == owned && ccx.last_uses.contains_key(e.id);
|
|
|
|
let ty = ty::expr_ty(ccx.tcx, e);
|
2011-09-27 13:19:55 +02:00
|
|
|
alt dest {
|
|
|
|
by_val(cell) {
|
2011-10-10 10:58:53 +02:00
|
|
|
if kind == temporary {
|
2011-09-27 13:19:55 +02:00
|
|
|
revoke_clean(bcx, val);
|
2011-09-23 21:13:50 +02:00
|
|
|
*cell = val;
|
2011-11-18 15:10:14 +01:00
|
|
|
} else if last_use {
|
|
|
|
*cell = Load(bcx, val);
|
|
|
|
if ty::type_needs_drop(ccx.tcx, ty) {
|
|
|
|
bcx = zero_alloca(bcx, val, ty);
|
|
|
|
}
|
|
|
|
} else {
|
2011-10-10 13:32:50 +02:00
|
|
|
if kind == owned { val = Load(bcx, val); }
|
2011-10-10 10:58:53 +02:00
|
|
|
let {bcx: cx, val} = take_ty_immediate(bcx, val, ty);
|
|
|
|
*cell = val;
|
|
|
|
bcx = cx;
|
2011-09-23 21:13:50 +02:00
|
|
|
}
|
|
|
|
}
|
2011-11-18 15:10:14 +01:00
|
|
|
save_in(loc) {
|
|
|
|
bcx = store_temp_expr(bcx, INIT, loc, lv, ty, last_use);
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ignore {}
|
2011-05-31 14:24:04 +02:00
|
|
|
}
|
2011-09-27 13:19:55 +02:00
|
|
|
ret bcx;
|
2011-05-31 14:24:04 +02:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn do_spill(cx: @block_ctxt, v: ValueRef, t: ty::t) -> result {
|
2011-09-02 15:12:27 -07:00
|
|
|
// We have a value but we have to spill it, and root it, to pass by alias.
|
|
|
|
let bcx = cx;
|
2011-09-21 10:54:56 -07:00
|
|
|
|
|
|
|
if ty::type_is_bot(bcx_tcx(bcx), t) {
|
|
|
|
ret rslt(bcx, C_null(T_ptr(T_i8())));
|
|
|
|
}
|
|
|
|
|
2011-09-02 15:12:27 -07:00
|
|
|
let r = alloc_ty(bcx, t);
|
|
|
|
bcx = r.bcx;
|
|
|
|
let llptr = r.val;
|
|
|
|
|
|
|
|
Store(bcx, v, llptr);
|
|
|
|
|
|
|
|
ret rslt(bcx, llptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Since this function does *not* root, it is the caller's responsibility to
|
|
|
|
// ensure that the referent is pointed to by a root.
|
2011-09-12 11:27:30 +02:00
|
|
|
fn do_spill_noroot(cx: @block_ctxt, v: ValueRef) -> ValueRef {
|
2011-07-27 14:19:39 +02:00
|
|
|
let llptr = alloca(cx, val_ty(v));
|
2011-08-30 09:59:30 +02:00
|
|
|
Store(cx, v, llptr);
|
2011-04-12 12:06:20 -07:00
|
|
|
ret llptr;
|
|
|
|
}
|
2010-12-03 13:03:07 -08:00
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn spill_if_immediate(cx: @block_ctxt, v: ValueRef, t: ty::t) -> result {
|
2011-10-10 12:23:58 +02:00
|
|
|
if ty::type_is_immediate(bcx_tcx(cx), t) { ret do_spill(cx, v, t); }
|
2011-09-02 15:12:27 -07:00
|
|
|
ret rslt(cx, v);
|
2011-04-12 12:06:20 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn load_if_immediate(cx: @block_ctxt, v: ValueRef, t: ty::t) -> ValueRef {
|
2011-10-10 12:23:58 +02:00
|
|
|
if ty::type_is_immediate(bcx_tcx(cx), t) { ret Load(cx, v); }
|
2011-04-12 12:06:20 -07:00
|
|
|
ret v;
|
2010-12-03 13:03:07 -08:00
|
|
|
}
|
|
|
|
|
2011-12-21 14:31:31 -08:00
|
|
|
fn trans_log(lvl: @ast::expr, cx: @block_ctxt, e: @ast::expr) -> @block_ctxt {
|
2011-10-14 16:45:25 -07:00
|
|
|
let ccx = bcx_ccx(cx);
|
2011-07-27 14:19:39 +02:00
|
|
|
let lcx = cx.fcx.lcx;
|
2012-01-19 14:28:58 -08:00
|
|
|
let tcx = ccx.tcx;
|
2011-09-02 15:34:58 -07:00
|
|
|
let modname = str::connect(lcx.module_path, "::");
|
2012-01-19 14:28:58 -08:00
|
|
|
|
|
|
|
if ty::type_is_bot(tcx, ty::expr_ty(tcx, lvl)) {
|
|
|
|
ret trans_expr(cx, lvl, ignore);
|
|
|
|
}
|
|
|
|
|
2011-09-26 13:21:47 +02:00
|
|
|
let global = if lcx.ccx.module_data.contains_key(modname) {
|
|
|
|
lcx.ccx.module_data.get(modname)
|
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-09-26 13:21:47 +02:00
|
|
|
let s = link::mangle_internal_name_by_path_and_seq(
|
|
|
|
lcx.ccx, lcx.module_path, "loglevel");
|
|
|
|
let global = str::as_buf(s, {|buf|
|
2011-12-21 14:31:31 -08:00
|
|
|
llvm::LLVMAddGlobal(lcx.ccx.llmod, T_i32(), buf)
|
2011-09-26 13:21:47 +02:00
|
|
|
});
|
2011-05-12 17:24:54 +02:00
|
|
|
llvm::LLVMSetGlobalConstant(global, False);
|
2011-12-21 14:31:31 -08:00
|
|
|
llvm::LLVMSetInitializer(global, C_null(T_i32()));
|
2011-06-15 11:19:50 -07:00
|
|
|
llvm::LLVMSetLinkage(global,
|
|
|
|
lib::llvm::LLVMInternalLinkage as llvm::Linkage);
|
2011-08-26 18:25:46 -07:00
|
|
|
lcx.ccx.module_data.insert(modname, global);
|
2011-09-26 13:21:47 +02:00
|
|
|
global
|
|
|
|
};
|
2011-12-21 14:31:31 -08:00
|
|
|
let level_cx = new_scope_block_ctxt(cx, "level");
|
2011-09-02 15:34:58 -07:00
|
|
|
let log_cx = new_scope_block_ctxt(cx, "log");
|
|
|
|
let after_cx = new_sub_block_ctxt(cx, "after");
|
2011-08-30 09:59:30 +02:00
|
|
|
let load = Load(cx, global);
|
2011-12-21 14:31:31 -08:00
|
|
|
|
|
|
|
Br(cx, level_cx.llbb);
|
|
|
|
let level_res = trans_temp_expr(level_cx, lvl);
|
|
|
|
let test = ICmp(level_res.bcx, lib::llvm::LLVMIntUGE,
|
|
|
|
load, level_res.val);
|
|
|
|
|
|
|
|
CondBr(level_res.bcx, test, log_cx.llbb, after_cx.llbb);
|
2011-10-05 11:26:27 +02:00
|
|
|
let sub = trans_temp_expr(log_cx, e);
|
2011-07-27 14:19:39 +02:00
|
|
|
let e_ty = ty::expr_ty(bcx_tcx(cx), e);
|
|
|
|
let log_bcx = sub.bcx;
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-08-13 00:09:25 -07:00
|
|
|
let ti = none::<@tydesc_info>;
|
2012-01-13 10:58:31 +01:00
|
|
|
let r = get_tydesc(log_bcx, e_ty, false, ti).result;
|
2011-08-10 12:55:29 -07:00
|
|
|
log_bcx = r.bcx;
|
2011-09-02 15:12:27 -07:00
|
|
|
let lltydesc = r.val;
|
2011-08-10 12:55:29 -07:00
|
|
|
|
|
|
|
// Call the polymorphic log function.
|
2011-09-02 15:12:27 -07:00
|
|
|
r = spill_if_immediate(log_bcx, sub.val, e_ty);
|
|
|
|
log_bcx = r.bcx;
|
|
|
|
let llvalptr = r.val;
|
2011-08-30 09:59:30 +02:00
|
|
|
let llval_i8 = PointerCast(log_bcx, llvalptr, T_ptr(T_i8()));
|
2011-08-10 12:55:29 -07:00
|
|
|
|
2011-10-25 13:13:55 -07:00
|
|
|
Call(log_bcx, ccx.upcalls.log_type,
|
2011-12-21 14:31:31 -08:00
|
|
|
[lltydesc, llval_i8, level_res.val]);
|
2011-07-27 14:19:39 +02:00
|
|
|
|
2011-04-29 19:19:54 -07:00
|
|
|
log_bcx = trans_block_cleanups(log_bcx, log_cx);
|
2011-08-30 09:59:30 +02:00
|
|
|
Br(log_bcx, after_cx.llbb);
|
2011-12-21 14:31:31 -08:00
|
|
|
ret trans_block_cleanups(after_cx, level_cx);
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
|
|
|
|
2011-09-26 13:21:47 +02:00
|
|
|
fn trans_check_expr(cx: @block_ctxt, e: @ast::expr, s: str) -> @block_ctxt {
|
2011-10-05 11:26:27 +02:00
|
|
|
let cond_res = trans_temp_expr(cx, e);
|
2011-09-02 15:34:58 -07:00
|
|
|
let expr_str = s + " " + expr_to_str(e) + " failed";
|
|
|
|
let fail_cx = new_sub_block_ctxt(cx, "fail");
|
2011-08-13 00:09:25 -07:00
|
|
|
trans_fail(fail_cx, some::<span>(e.span), expr_str);
|
2011-09-02 15:34:58 -07:00
|
|
|
let next_cx = new_sub_block_ctxt(cx, "next");
|
2011-08-30 09:59:30 +02:00
|
|
|
CondBr(cond_res.bcx, cond_res.val, next_cx.llbb, fail_cx.llbb);
|
2011-09-26 13:21:47 +02:00
|
|
|
ret next_cx;
|
2010-10-22 15:37:42 -07:00
|
|
|
}
|
|
|
|
|
2011-09-26 13:21:47 +02:00
|
|
|
fn trans_fail_expr(bcx: @block_ctxt, sp_opt: option::t<span>,
|
|
|
|
fail_expr: option::t<@ast::expr>) -> @block_ctxt {
|
2011-11-03 10:57:54 +01:00
|
|
|
let bcx = bcx;
|
2011-07-27 14:19:39 +02:00
|
|
|
alt fail_expr {
|
|
|
|
some(expr) {
|
|
|
|
let tcx = bcx_tcx(bcx);
|
2011-10-05 11:26:27 +02:00
|
|
|
let expr_res = trans_temp_expr(bcx, expr);
|
2011-07-27 14:19:39 +02:00
|
|
|
let e_ty = ty::expr_ty(tcx, expr);
|
|
|
|
bcx = expr_res.bcx;
|
2011-07-01 14:33:15 -04:00
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
if ty::type_is_str(tcx, e_ty) {
|
2011-09-26 13:21:47 +02:00
|
|
|
let data = tvec::get_dataptr(
|
|
|
|
bcx, expr_res.val, type_of_or_i8(
|
2011-12-07 21:06:12 +01:00
|
|
|
bcx, ty::mk_mach_uint(tcx, ast::ty_u8)));
|
2011-09-02 16:09:41 +02:00
|
|
|
ret trans_fail_value(bcx, sp_opt, data);
|
2012-01-19 13:29:26 -08:00
|
|
|
} else if bcx.unreachable || ty::type_is_bot(tcx, e_ty) {
|
2011-09-26 13:21:47 +02:00
|
|
|
ret bcx;
|
2011-07-27 14:19:39 +02:00
|
|
|
} else {
|
2011-09-26 13:21:47 +02:00
|
|
|
bcx_ccx(bcx).sess.span_bug(
|
|
|
|
expr.span, "fail called with unsupported type " +
|
|
|
|
ty_to_str(tcx, e_ty));
|
2011-07-01 14:33:15 -04:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-09-02 15:34:58 -07:00
|
|
|
_ { ret trans_fail(bcx, sp_opt, "explicit failure"); }
|
2011-07-01 14:33:15 -04:00
|
|
|
}
|
|
|
|
}
|
2011-07-13 15:44:09 -07:00
|
|
|
|
2011-09-26 13:21:47 +02:00
|
|
|
fn trans_fail(bcx: @block_ctxt, sp_opt: option::t<span>, fail_str: str) ->
|
|
|
|
@block_ctxt {
|
|
|
|
let V_fail_str = C_cstr(bcx_ccx(bcx), fail_str);
|
|
|
|
ret trans_fail_value(bcx, sp_opt, V_fail_str);
|
2011-07-01 14:33:15 -04:00
|
|
|
}
|
|
|
|
|
2011-09-26 13:21:47 +02:00
|
|
|
fn trans_fail_value(bcx: @block_ctxt, sp_opt: option::t<span>,
|
|
|
|
V_fail_str: ValueRef) -> @block_ctxt {
|
2011-10-14 16:45:25 -07:00
|
|
|
let ccx = bcx_ccx(bcx);
|
2011-07-27 14:19:39 +02:00
|
|
|
let V_filename;
|
|
|
|
let V_line;
|
|
|
|
alt sp_opt {
|
|
|
|
some(sp) {
|
2012-01-12 17:59:49 +01:00
|
|
|
let sess = bcx_ccx(bcx).sess;
|
|
|
|
let loc = codemap::lookup_char_pos(sess.parse_sess.cm, sp.lo);
|
2011-09-26 13:21:47 +02:00
|
|
|
V_filename = C_cstr(bcx_ccx(bcx), loc.filename);
|
2011-07-27 14:19:39 +02:00
|
|
|
V_line = loc.line as int;
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
none { V_filename = C_cstr(bcx_ccx(bcx), "<runtime>"); V_line = 0; }
|
2011-04-19 15:22:57 -07:00
|
|
|
}
|
2011-09-26 13:21:47 +02:00
|
|
|
let V_str = PointerCast(bcx, V_fail_str, T_ptr(T_i8()));
|
|
|
|
V_filename = PointerCast(bcx, V_filename, T_ptr(T_i8()));
|
2011-10-25 13:13:55 -07:00
|
|
|
let args = [V_str, V_filename, C_int(ccx, V_line)];
|
2011-09-26 13:21:47 +02:00
|
|
|
let bcx = invoke(bcx, bcx_ccx(bcx).upcalls._fail, args);
|
|
|
|
Unreachable(bcx);
|
|
|
|
ret bcx;
|
2011-01-28 00:09:26 -05:00
|
|
|
}
|
|
|
|
|
2011-09-26 13:21:47 +02:00
|
|
|
fn trans_break_cont(sp: span, bcx: @block_ctxt, to_end: bool)
|
|
|
|
-> @block_ctxt {
|
2011-03-25 16:28:16 +01:00
|
|
|
// Locate closest loop block, outputting cleanup as we go.
|
2011-11-03 10:57:54 +01:00
|
|
|
let cleanup_cx = bcx, bcx = bcx;
|
2011-07-27 14:19:39 +02:00
|
|
|
while true {
|
2011-03-25 16:28:16 +01:00
|
|
|
bcx = trans_block_cleanups(bcx, cleanup_cx);
|
2011-09-12 13:13:20 +02:00
|
|
|
alt copy cleanup_cx.kind {
|
2011-07-27 14:19:39 +02:00
|
|
|
LOOP_SCOPE_BLOCK(_cont, _break) {
|
|
|
|
if to_end {
|
2011-08-30 09:59:30 +02:00
|
|
|
Br(bcx, _break.llbb);
|
2011-07-27 14:19:39 +02:00
|
|
|
} else {
|
|
|
|
alt _cont {
|
2011-08-30 09:59:30 +02:00
|
|
|
option::some(_cont) { Br(bcx, _cont.llbb); }
|
|
|
|
_ { Br(bcx, cleanup_cx.llbb); }
|
2011-03-25 16:28:16 +01:00
|
|
|
}
|
|
|
|
}
|
2011-09-21 12:40:27 +02:00
|
|
|
Unreachable(bcx);
|
2011-09-26 13:21:47 +02:00
|
|
|
ret bcx;
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ {
|
2011-09-20 17:29:09 +02:00
|
|
|
alt cleanup_cx.parent {
|
2011-07-27 14:19:39 +02:00
|
|
|
parent_some(cx) { cleanup_cx = cx; }
|
2012-01-18 22:37:22 -08:00
|
|
|
parent_none {
|
2011-09-26 13:21:47 +02:00
|
|
|
bcx_ccx(bcx).sess.span_fatal
|
|
|
|
(sp, if to_end { "Break" } else { "Cont" } +
|
|
|
|
" outside a loop");
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-03-25 16:28:16 +01:00
|
|
|
}
|
2011-07-27 14:19:39 +02: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-09-26 13:21:47 +02:00
|
|
|
bcx_ccx(bcx).sess.bug("in trans::trans_break_cont()");
|
2011-03-25 16:28:16 +01:00
|
|
|
}
|
|
|
|
|
2011-09-26 13:21:47 +02:00
|
|
|
fn trans_break(sp: span, cx: @block_ctxt) -> @block_ctxt {
|
2011-06-10 14:34:01 -07:00
|
|
|
ret trans_break_cont(sp, cx, true);
|
2011-03-25 16:28:16 +01:00
|
|
|
}
|
|
|
|
|
2011-09-26 13:21:47 +02:00
|
|
|
fn trans_cont(sp: span, cx: @block_ctxt) -> @block_ctxt {
|
2011-06-10 14:34:01 -07:00
|
|
|
ret trans_break_cont(sp, cx, false);
|
2011-03-25 16:28:16 +01:00
|
|
|
}
|
|
|
|
|
2011-09-26 13:21:47 +02:00
|
|
|
fn trans_ret(bcx: @block_ctxt, e: option::t<@ast::expr>) -> @block_ctxt {
|
2011-11-03 10:57:54 +01:00
|
|
|
let cleanup_cx = bcx, bcx = bcx;
|
2011-07-27 14:19:39 +02:00
|
|
|
alt e {
|
2011-11-23 10:56:10 +01:00
|
|
|
some(x) { bcx = trans_expr_save_in(bcx, x, bcx.fcx.llretptr); }
|
2011-09-21 11:39:06 +02:00
|
|
|
_ {}
|
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
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
let more_cleanups: bool = true;
|
|
|
|
while more_cleanups {
|
2011-01-21 07:58:16 -08:00
|
|
|
bcx = trans_block_cleanups(bcx, cleanup_cx);
|
2011-09-20 17:29:09 +02:00
|
|
|
alt cleanup_cx.parent {
|
2011-07-27 14:19:39 +02:00
|
|
|
parent_some(b) { cleanup_cx = b; }
|
2012-01-18 22:37:22 -08:00
|
|
|
parent_none { more_cleanups = false; }
|
2010-11-10 17:46:49 -08:00
|
|
|
}
|
|
|
|
}
|
2011-08-17 17:49:54 -07:00
|
|
|
build_return(bcx);
|
2011-09-21 12:40:27 +02:00
|
|
|
Unreachable(bcx);
|
2011-09-26 13:21:47 +02:00
|
|
|
ret bcx;
|
2010-10-22 19:23:10 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn build_return(bcx: @block_ctxt) { Br(bcx, bcx_fcx(bcx).llreturn); }
|
2011-08-17 17:49:54 -07:00
|
|
|
|
2011-08-26 10:14:58 -07:00
|
|
|
// fn trans_be(cx: &@block_ctxt, e: &@ast::expr) -> result {
|
2011-12-22 13:47:30 +01:00
|
|
|
fn trans_be(cx: @block_ctxt, e: @ast::expr) : ast_util::is_call_expr(e) ->
|
2011-09-26 13:21:47 +02:00
|
|
|
@block_ctxt {
|
2011-02-09 22:36:37 -05:00
|
|
|
// FIXME: Turn this into a real tail call once
|
|
|
|
// calling convention issues are settled
|
2011-01-30 17:18:19 -05:00
|
|
|
ret trans_ret(cx, some(e));
|
|
|
|
}
|
|
|
|
|
2011-09-15 14:00:58 +02:00
|
|
|
fn init_local(bcx: @block_ctxt, local: @ast::local) -> @block_ctxt {
|
2011-07-28 12:01:45 +02:00
|
|
|
let ty = node_id_type(bcx_ccx(bcx), local.node.id);
|
2011-10-07 11:20:51 +02:00
|
|
|
let llptr = alt bcx.fcx.lllocals.find(local.node.id) {
|
|
|
|
some(local_mem(v)) { v }
|
|
|
|
// This is a local that is kept immediate
|
2012-01-18 22:37:22 -08:00
|
|
|
none {
|
2011-10-07 11:20:51 +02:00
|
|
|
let initexpr = alt local.node.init { some({expr, _}) { expr } };
|
2011-10-10 10:58:53 +02:00
|
|
|
let {bcx, val, kind} = trans_temp_lval(bcx, initexpr);
|
|
|
|
if kind != temporary {
|
|
|
|
if kind == owned { val = Load(bcx, val); }
|
|
|
|
let rs = take_ty_immediate(bcx, val, ty);
|
|
|
|
bcx = rs.bcx; val = rs.val;
|
|
|
|
add_clean_temp(bcx, val, ty);
|
|
|
|
}
|
|
|
|
bcx.fcx.lllocals.insert(local.node.pat.id, local_imm(val));
|
|
|
|
ret bcx;
|
2011-10-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
};
|
2011-08-23 15:45:24 -07:00
|
|
|
|
2011-11-03 10:57:54 +01:00
|
|
|
let bcx = bcx;
|
2011-07-27 14:19:39 +02:00
|
|
|
alt local.node.init {
|
|
|
|
some(init) {
|
2011-12-14 15:23:11 +01:00
|
|
|
if init.op == ast::init_assign || !expr_is_lval(bcx, init.expr) {
|
2011-10-05 10:21:48 +02:00
|
|
|
bcx = trans_expr_save_in(bcx, init.expr, llptr);
|
2011-09-28 15:15:29 +02:00
|
|
|
} else { // This is a move from an lval, must perform an actual move
|
2011-07-27 14:19:39 +02:00
|
|
|
let sub = trans_lval(bcx, init.expr);
|
2011-09-16 16:27:34 +02:00
|
|
|
bcx = move_val(sub.bcx, INIT, llptr, sub, ty);
|
2011-01-21 07:58:16 -08:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-09-28 11:12:22 +02:00
|
|
|
_ { bcx = zero_alloca(bcx, llptr, ty); }
|
2011-01-21 07:58:16 -08:00
|
|
|
}
|
2011-09-28 10:41:19 +02:00
|
|
|
// Make a note to drop this slot on the way out.
|
|
|
|
add_clean(bcx, llptr, ty);
|
2011-10-07 11:20:51 +02:00
|
|
|
ret trans_alt::bind_irrefutable_pat(bcx, local.node.pat, llptr, false);
|
2011-01-21 07:58:16 -08:00
|
|
|
}
|
|
|
|
|
2011-09-15 14:00:58 +02:00
|
|
|
fn init_ref_local(bcx: @block_ctxt, local: @ast::local) -> @block_ctxt {
|
|
|
|
let init_expr = option::get(local.node.init).expr;
|
2011-11-21 09:25:42 +01:00
|
|
|
let {bcx, val, kind} = trans_lval(bcx, init_expr);
|
|
|
|
alt kind {
|
2012-01-18 22:37:22 -08:00
|
|
|
owned_imm { val = do_spill_noroot(bcx, val); }
|
|
|
|
owned {}
|
2011-11-21 09:25:42 +01:00
|
|
|
}
|
|
|
|
ret trans_alt::bind_irrefutable_pat(bcx, local.node.pat, val, false);
|
2011-09-15 14:00:58 +02:00
|
|
|
}
|
|
|
|
|
2011-09-23 21:13:38 +02:00
|
|
|
fn zero_alloca(cx: @block_ctxt, llptr: ValueRef, t: ty::t)
|
|
|
|
-> @block_ctxt {
|
2011-07-27 14:19:39 +02:00
|
|
|
let bcx = cx;
|
2011-09-02 18:59:22 -07:00
|
|
|
let ccx = bcx_ccx(cx);
|
|
|
|
if check type_has_static_size(ccx, t) {
|
|
|
|
let sp = cx.sp;
|
|
|
|
let llty = type_of(ccx, sp, t);
|
|
|
|
Store(bcx, C_null(llty), llptr);
|
2011-09-12 11:27:30 +02:00
|
|
|
} else {
|
2012-01-17 15:51:45 -08:00
|
|
|
let key = alt ccx.sess.targ_cfg.arch {
|
2012-01-19 01:03:57 -08:00
|
|
|
session::arch_x86 | session::arch_arm { "llvm.memset.p0i8.i32" }
|
|
|
|
session::arch_x86_64 { "llvm.memset.p0i8.i64" }
|
2012-01-17 15:51:45 -08:00
|
|
|
};
|
|
|
|
let i = ccx.intrinsics;
|
|
|
|
let memset = i.get(key);
|
|
|
|
let dst_ptr = PointerCast(cx, llptr, T_ptr(T_i8()));
|
|
|
|
let size = size_of(cx, t);
|
|
|
|
bcx = size.bcx;
|
|
|
|
let align = C_i32(1i32); // cannot use computed value here.
|
|
|
|
let volatile = C_bool(false);
|
|
|
|
Call(cx, memset, [dst_ptr, C_u8(0u), size.val, align, volatile]);
|
2011-04-05 23:42:33 -04:00
|
|
|
}
|
2012-01-17 11:20:21 -08:00
|
|
|
ret bcx;
|
2011-06-15 11:19:50 -07:00
|
|
|
}
|
2011-04-05 23:42:33 -04:00
|
|
|
|
2011-09-23 21:13:38 +02:00
|
|
|
fn trans_stmt(cx: @block_ctxt, s: ast::stmt) -> @block_ctxt {
|
2011-06-15 12:17:51 +02:00
|
|
|
// FIXME Fill in cx.sp
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2012-01-12 17:59:49 +01:00
|
|
|
if (!bcx_ccx(cx).sess.opts.no_asm_comments) {
|
2011-12-06 14:02:06 -08:00
|
|
|
add_span_comment(cx, s.span, stmt_to_str(s));
|
|
|
|
}
|
2011-11-14 14:03:20 -08:00
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
let bcx = cx;
|
2011-12-18 23:32:38 -05:00
|
|
|
debuginfo::update_source_pos(cx, s.span);
|
2011-12-19 02:52:21 -05:00
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
alt s.node {
|
2012-01-04 14:16:41 -08:00
|
|
|
ast::stmt_expr(e, _) | ast::stmt_semi(e, _) {
|
|
|
|
bcx = trans_expr(cx, e, ignore);
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
ast::stmt_decl(d, _) {
|
|
|
|
alt d.node {
|
|
|
|
ast::decl_local(locals) {
|
2011-09-15 14:00:58 +02:00
|
|
|
for (style, local) in locals {
|
|
|
|
if style == ast::let_copy {
|
|
|
|
bcx = init_local(bcx, local);
|
|
|
|
} else {
|
|
|
|
bcx = init_ref_local(bcx, local);
|
|
|
|
}
|
2012-01-12 17:59:49 +01:00
|
|
|
if bcx_ccx(cx).sess.opts.extra_debuginfo {
|
2011-12-14 15:14:06 -05:00
|
|
|
debuginfo::create_local_var(bcx, local);
|
2011-11-15 21:11:22 -05:00
|
|
|
}
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
ast::decl_item(i) { trans_item(cx.fcx.lcx, *i); }
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-09-02 15:34:58 -07:00
|
|
|
_ { bcx_ccx(cx).sess.unimpl("stmt variant"); }
|
2010-09-23 13:15:51 -07:00
|
|
|
}
|
2011-11-15 21:11:22 -05:00
|
|
|
|
2011-09-23 21:13:38 +02:00
|
|
|
ret bcx;
|
2010-10-01 18:25:42 -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-09-12 11:27:30 +02:00
|
|
|
fn new_block_ctxt(cx: @fn_ctxt, parent: block_parent, kind: block_kind,
|
|
|
|
name: str) -> @block_ctxt {
|
2011-09-02 15:34:58 -07:00
|
|
|
let s = "";
|
2012-01-12 17:59:49 +01:00
|
|
|
if cx.lcx.ccx.sess.opts.save_temps ||
|
|
|
|
cx.lcx.ccx.sess.opts.debuginfo {
|
2012-01-13 09:32:05 +01:00
|
|
|
s = cx.lcx.ccx.names(name);
|
2011-05-10 16:43:34 -07:00
|
|
|
}
|
2011-09-02 15:34:58 -07:00
|
|
|
let llbb: BasicBlockRef =
|
|
|
|
str::as_buf(s, {|buf| llvm::LLVMAppendBasicBlock(cx.llfn, buf) });
|
2011-09-21 12:40:27 +02:00
|
|
|
let bcx = @{llbb: llbb,
|
|
|
|
mutable terminated: false,
|
|
|
|
mutable unreachable: false,
|
|
|
|
parent: parent,
|
|
|
|
kind: kind,
|
|
|
|
mutable cleanups: [],
|
|
|
|
mutable lpad_dirty: true,
|
|
|
|
mutable lpad: option::none,
|
|
|
|
sp: cx.sp,
|
2011-12-18 23:32:38 -05:00
|
|
|
fcx: cx};
|
2011-09-21 12:40:27 +02:00
|
|
|
alt parent {
|
|
|
|
parent_some(cx) {
|
|
|
|
if cx.unreachable { Unreachable(bcx); }
|
|
|
|
}
|
|
|
|
_ {}
|
|
|
|
}
|
|
|
|
ret bcx;
|
2010-09-27 15:38:34 -07:00
|
|
|
}
|
|
|
|
|
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-09-12 11:27:30 +02:00
|
|
|
fn new_top_block_ctxt(fcx: @fn_ctxt) -> @block_ctxt {
|
2011-09-02 15:34:58 -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-09-12 11:27:30 +02:00
|
|
|
fn new_scope_block_ctxt(bcx: @block_ctxt, n: str) -> @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-09-12 11:27:30 +02:00
|
|
|
fn new_loop_scope_block_ctxt(bcx: @block_ctxt, _cont: option::t<@block_ctxt>,
|
|
|
|
_break: @block_ctxt, n: str) -> @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-09-12 11:27:30 +02:00
|
|
|
fn new_sub_block_ctxt(bcx: @block_ctxt, n: str) -> @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-09-12 11:27:30 +02:00
|
|
|
fn new_raw_block_ctxt(fcx: @fn_ctxt, llbb: BasicBlockRef) -> @block_ctxt {
|
2011-07-27 14:19:39 +02:00
|
|
|
ret @{llbb: llbb,
|
2011-08-24 14:54:55 +02:00
|
|
|
mutable terminated: false,
|
2011-09-21 12:40:27 +02:00
|
|
|
mutable unreachable: false,
|
2011-07-27 14:19:39 +02:00
|
|
|
parent: parent_none,
|
|
|
|
kind: NON_SCOPE_BLOCK,
|
2011-08-24 14:54:55 +02:00
|
|
|
mutable cleanups: [],
|
2011-09-16 14:37:58 -07:00
|
|
|
mutable lpad_dirty: true,
|
2011-09-13 16:10:39 -07:00
|
|
|
mutable lpad: option::none,
|
2011-07-27 14:19:39 +02:00
|
|
|
sp: fcx.sp,
|
2011-12-18 23:32:38 -05: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
|
2011-07-13 15:44:09 -07:00
|
|
|
// block_ctxt and execute them.
|
2011-05-27 17:58:22 -07:00
|
|
|
//
|
|
|
|
// 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-09-21 12:40:27 +02:00
|
|
|
fn trans_block_cleanups(bcx: @block_ctxt, cleanup_cx: @block_ctxt) ->
|
2011-07-27 14:19:39 +02:00
|
|
|
@block_ctxt {
|
2011-09-21 12:40:27 +02:00
|
|
|
if bcx.unreachable { ret bcx; }
|
2011-07-27 14:19:39 +02:00
|
|
|
if cleanup_cx.kind == NON_SCOPE_BLOCK {
|
2011-12-13 16:25:51 -08:00
|
|
|
assert (vec::len::<cleanup>(cleanup_cx.cleanups) == 0u);
|
2010-12-02 19:12:34 -08:00
|
|
|
}
|
2011-12-13 16:25:51 -08:00
|
|
|
let i = vec::len::<cleanup>(cleanup_cx.cleanups), bcx = bcx;
|
2011-07-27 14:19:39 +02:00
|
|
|
while i > 0u {
|
2011-01-31 12:06:27 -08:00
|
|
|
i -= 1u;
|
2011-08-19 15:16:48 -07:00
|
|
|
let c = cleanup_cx.cleanups[i];
|
2011-07-27 14:19:39 +02:00
|
|
|
alt c {
|
2011-08-30 13:50:58 +02:00
|
|
|
clean(cfn) { bcx = cfn(bcx); }
|
|
|
|
clean_temp(_, cfn) { bcx = cfn(bcx); }
|
Make moving of temporaries do the right thing, use it to optimize
This adds support for dropping cleanups for temporary values when they
are moved somewhere else. It then adds wraps most copy operations
(return, put in data structure, box, etc) in a way that will fall back
to a move when it is safe.
This saves a lot of taking/dropping, shaving over a megabyte off the
stage2/rustc binary size.
In some cases, most notably function returns, we could detect that the
returned value is a local variable, and can thus be safely moved even
though it is not a temporary. This will require putting some more
information in lvals.
I did not yet handle function arguments, since the logic for passing
them looked too convoluted to touch. I'll probably try that in the
near future, since it's bound to be a big win.
2011-07-07 13:36:12 +02:00
|
|
|
}
|
2010-09-29 17:22:07 -07:00
|
|
|
}
|
2010-10-04 15:55:12 -07:00
|
|
|
ret bcx;
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trans_fn_cleanups(fcx: @fn_ctxt, cx: @block_ctxt) {
|
2011-08-17 17:49:54 -07:00
|
|
|
alt fcx.llobstacktoken {
|
2011-08-19 15:16:48 -07:00
|
|
|
some(lltoken_) {
|
|
|
|
let lltoken = lltoken_; // satisfy alias checker
|
2011-10-20 11:42:40 +02:00
|
|
|
Call(cx, fcx_ccx(fcx).upcalls.dynastack_free, [lltoken]);
|
2011-08-19 15:16:48 -07:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
none {/* nothing to do */ }
|
2011-08-17 17:27:31 -07:00
|
|
|
}
|
2011-08-17 13:58:49 -07:00
|
|
|
}
|
|
|
|
|
2011-10-21 13:14:28 +02:00
|
|
|
fn block_locals(b: ast::blk, it: block(@ast::local)) {
|
2011-08-15 21:54:52 -07:00
|
|
|
for s: @ast::stmt in b.node.stmts {
|
2011-07-27 14:19:39 +02:00
|
|
|
alt s.node {
|
|
|
|
ast::stmt_decl(d, _) {
|
|
|
|
alt d.node {
|
|
|
|
ast::decl_local(locals) {
|
2011-09-15 14:00:58 +02:00
|
|
|
for (style, local) in locals {
|
2011-10-21 13:14:28 +02:00
|
|
|
if style == ast::let_copy { it(local); }
|
2011-09-15 14:00:58 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ {/* fall through */ }
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ {/* fall through */ }
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn llstaticallocas_block_ctxt(fcx: @fn_ctxt) -> @block_ctxt {
|
2011-07-27 14:19:39 +02:00
|
|
|
ret @{llbb: fcx.llstaticallocas,
|
2011-08-24 14:54:55 +02:00
|
|
|
mutable terminated: false,
|
2011-09-21 12:40:27 +02:00
|
|
|
mutable unreachable: false,
|
2011-07-27 14:19:39 +02:00
|
|
|
parent: parent_none,
|
|
|
|
kind: SCOPE_BLOCK,
|
2011-08-24 14:54:55 +02:00
|
|
|
mutable cleanups: [],
|
2011-09-16 14:37:58 -07:00
|
|
|
mutable lpad_dirty: true,
|
2011-09-13 16:10:39 -07:00
|
|
|
mutable lpad: option::none,
|
2011-07-27 14:19:39 +02:00
|
|
|
sp: fcx.sp,
|
2011-12-18 23:32:38 -05:00
|
|
|
fcx: fcx};
|
2011-06-18 18:43:07 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn llderivedtydescs_block_ctxt(fcx: @fn_ctxt) -> @block_ctxt {
|
2011-07-27 14:19:39 +02:00
|
|
|
ret @{llbb: fcx.llderivedtydescs,
|
2011-08-24 14:54:55 +02:00
|
|
|
mutable terminated: false,
|
2011-09-21 12:40:27 +02:00
|
|
|
mutable unreachable: false,
|
2011-07-27 14:19:39 +02:00
|
|
|
parent: parent_none,
|
|
|
|
kind: SCOPE_BLOCK,
|
2011-08-24 14:54:55 +02:00
|
|
|
mutable cleanups: [],
|
2011-09-16 14:37:58 -07:00
|
|
|
mutable lpad_dirty: true,
|
2011-09-13 16:10:39 -07:00
|
|
|
mutable lpad: option::none,
|
2011-07-27 14:19:39 +02:00
|
|
|
sp: fcx.sp,
|
2011-12-18 23:32:38 -05:00
|
|
|
fcx: fcx};
|
2011-06-18 18:43:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn alloc_ty(cx: @block_ctxt, t: ty::t) -> result {
|
2011-08-11 14:33:40 -07:00
|
|
|
let bcx = cx;
|
2011-09-02 18:59:22 -07:00
|
|
|
let ccx = bcx_ccx(cx);
|
2011-09-12 11:27:30 +02:00
|
|
|
let val =
|
|
|
|
if check type_has_static_size(ccx, t) {
|
|
|
|
let sp = cx.sp;
|
|
|
|
alloca(bcx, type_of(ccx, sp, t))
|
|
|
|
} else {
|
|
|
|
// NB: we have to run this particular 'size_of' in a
|
|
|
|
// block_ctxt built on the llderivedtydescs block for the fn,
|
|
|
|
// so that the size dominates the array_alloca that
|
|
|
|
// comes next.
|
|
|
|
|
|
|
|
let n = size_of(llderivedtydescs_block_ctxt(bcx.fcx), t);
|
|
|
|
bcx.fcx.llderivedtydescs = n.bcx.llbb;
|
|
|
|
dynastack_alloca(bcx, T_i8(), n.val, t)
|
|
|
|
};
|
2011-09-02 18:59:22 -07:00
|
|
|
|
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
|
|
|
|
2012-01-12 17:59:49 +01:00
|
|
|
if bcx_tcx(cx).sess.opts.do_gc {
|
2011-08-18 18:13:36 -07:00
|
|
|
bcx = gc::add_gc_root(bcx, val, t);
|
|
|
|
}
|
2011-08-11 14:33:40 -07:00
|
|
|
|
2011-06-24 19:04:08 +02:00
|
|
|
ret rslt(cx, val);
|
2011-01-21 07:58:16 -08:00
|
|
|
}
|
|
|
|
|
2011-10-07 11:20:51 +02:00
|
|
|
fn alloc_local(cx: @block_ctxt, local: @ast::local) -> @block_ctxt {
|
2011-07-27 14:19:39 +02:00
|
|
|
let t = node_id_type(bcx_ccx(cx), local.node.id);
|
2012-01-14 16:05:07 -08:00
|
|
|
let p = normalize_pat(bcx_tcx(cx), local.node.pat);
|
|
|
|
let is_simple = alt p.node {
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::pat_ident(_, none) { true } _ { false }
|
2011-10-07 11:20:51 +02:00
|
|
|
};
|
|
|
|
// Do not allocate space for locals that can be kept immediate.
|
2011-11-18 15:10:14 +01:00
|
|
|
let ccx = bcx_ccx(cx);
|
|
|
|
if is_simple && !ccx.mut_map.contains_key(local.node.pat.id) &&
|
|
|
|
!ccx.last_uses.contains_key(local.node.pat.id) &&
|
|
|
|
ty::type_is_immediate(ccx.tcx, t) {
|
2011-10-07 11:20:51 +02:00
|
|
|
alt local.node.init {
|
2012-01-18 22:37:22 -08:00
|
|
|
some({op: ast::init_assign, _}) { ret cx; }
|
2011-10-07 11:20:51 +02:00
|
|
|
_ {}
|
|
|
|
}
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
let r = alloc_ty(cx, t);
|
2012-01-14 16:05:07 -08:00
|
|
|
alt p.node {
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::pat_ident(pth, none) {
|
2012-01-12 17:59:49 +01:00
|
|
|
if bcx_ccx(cx).sess.opts.debuginfo {
|
2012-01-14 16:05:07 -08:00
|
|
|
let _: () = str::as_buf(path_to_ident(pth), {|buf|
|
2011-10-07 11:20:51 +02:00
|
|
|
llvm::LLVMSetValueName(r.val, buf)
|
|
|
|
});
|
2011-07-28 12:01:45 +02:00
|
|
|
}
|
|
|
|
}
|
2011-08-19 15:16:48 -07:00
|
|
|
_ { }
|
2011-07-15 16:40:04 -07:00
|
|
|
}
|
2011-10-07 11:20:51 +02:00
|
|
|
cx.fcx.lllocals.insert(local.node.id, local_mem(r.val));
|
|
|
|
ret r.bcx;
|
2011-02-10 15:00:16 -08:00
|
|
|
}
|
|
|
|
|
2011-10-05 11:26:27 +02:00
|
|
|
fn trans_block(bcx: @block_ctxt, b: ast::blk) -> @block_ctxt {
|
|
|
|
trans_block_dps(bcx, b, ignore)
|
2011-09-23 21:13:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn trans_block_dps(bcx: @block_ctxt, b: ast::blk, dest: dest)
|
|
|
|
-> @block_ctxt {
|
2011-11-03 10:57:54 +01:00
|
|
|
let bcx = bcx;
|
2011-10-21 13:14:28 +02:00
|
|
|
block_locals(b) {|local| bcx = alloc_local(bcx, local); };
|
2011-08-15 21:54:52 -07:00
|
|
|
for s: @ast::stmt in b.node.stmts {
|
2011-12-18 23:32:38 -05:00
|
|
|
debuginfo::update_source_pos(bcx, b.span);
|
2011-09-23 21:13:38 +02:00
|
|
|
bcx = trans_stmt(bcx, *s);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
alt b.node.expr {
|
2011-09-26 13:21:47 +02:00
|
|
|
some(e) {
|
|
|
|
let bt = ty::type_is_bot(bcx_tcx(bcx), ty::expr_ty(bcx_tcx(bcx), e));
|
2011-12-18 23:32:38 -05:00
|
|
|
debuginfo::update_source_pos(bcx, e.span);
|
2011-10-05 11:26:27 +02:00
|
|
|
bcx = trans_expr(bcx, e, bt ? ignore : dest);
|
2011-09-26 13:21:47 +02:00
|
|
|
}
|
2011-09-23 21:13:50 +02:00
|
|
|
_ { assert dest == ignore || bcx.unreachable; }
|
2010-11-29 17:11:03 -08:00
|
|
|
}
|
2011-11-15 21:11:22 -05:00
|
|
|
let rv = trans_block_cleanups(bcx, find_scope_cx(bcx));
|
|
|
|
ret rv;
|
2010-09-23 13:15:51 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn new_local_ctxt(ccx: @crate_ctxt) -> @local_ctxt {
|
2011-09-02 15:34:58 -07:00
|
|
|
let pth: [str] = [];
|
2011-07-27 14:19:39 +02:00
|
|
|
ret @{path: pth,
|
2011-08-26 18:25:46 -07:00
|
|
|
module_path: [ccx.link_meta.name],
|
2011-07-27 14:19:39 +02:00
|
|
|
ccx: ccx};
|
2011-04-20 17:23:45 +02:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-18 18:43:07 -07:00
|
|
|
// Creates the standard quartet of basic blocks: static allocas, copy args,
|
|
|
|
// derived tydescs, and dynamic allocas.
|
2011-07-27 14:19:39 +02:00
|
|
|
fn mk_standard_basic_blocks(llfn: ValueRef) ->
|
|
|
|
{sa: BasicBlockRef,
|
|
|
|
ca: BasicBlockRef,
|
|
|
|
dt: BasicBlockRef,
|
2011-08-17 17:49:54 -07:00
|
|
|
da: BasicBlockRef,
|
|
|
|
rt: BasicBlockRef} {
|
2011-09-02 15:34:58 -07:00
|
|
|
ret {sa:
|
2011-09-07 15:13:19 +02:00
|
|
|
str::as_buf("static_allocas",
|
2011-09-02 15:34:58 -07:00
|
|
|
{|buf| llvm::LLVMAppendBasicBlock(llfn, buf) }),
|
|
|
|
ca:
|
2011-09-23 11:01:09 +02:00
|
|
|
str::as_buf("load_env",
|
2011-09-02 15:34:58 -07:00
|
|
|
{|buf| llvm::LLVMAppendBasicBlock(llfn, buf) }),
|
|
|
|
dt:
|
|
|
|
str::as_buf("derived_tydescs",
|
|
|
|
{|buf| llvm::LLVMAppendBasicBlock(llfn, buf) }),
|
|
|
|
da:
|
|
|
|
str::as_buf("dynamic_allocas",
|
|
|
|
{|buf| llvm::LLVMAppendBasicBlock(llfn, buf) }),
|
|
|
|
rt:
|
|
|
|
str::as_buf("return",
|
|
|
|
{|buf| llvm::LLVMAppendBasicBlock(llfn, buf) })};
|
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:
|
|
|
|
//
|
2011-09-14 14:34:50 +02:00
|
|
|
// - type_of_fn
|
2011-02-08 11:47:53 -08:00
|
|
|
// - create_llargs_for_fn_args.
|
|
|
|
// - new_fn_ctxt
|
|
|
|
// - trans_args
|
2011-09-12 11:27:30 +02:00
|
|
|
fn new_fn_ctxt_w_id(cx: @local_ctxt, sp: span, llfndecl: ValueRef,
|
2011-09-14 13:48:51 +02:00
|
|
|
id: ast::node_id, rstyle: ast::ret_style)
|
|
|
|
-> @fn_ctxt {
|
2011-07-27 14:19:39 +02:00
|
|
|
let llbbs = mk_standard_basic_blocks(llfndecl);
|
|
|
|
ret @{llfn: llfndecl,
|
2012-01-18 19:29:37 +08:00
|
|
|
llenv: llvm::LLVMGetParam(llfndecl, 1u as c_uint),
|
|
|
|
llretptr: llvm::LLVMGetParam(llfndecl, 0u as c_uint),
|
2011-07-27 14:19:39 +02:00
|
|
|
mutable llstaticallocas: llbbs.sa,
|
2011-09-23 11:01:09 +02:00
|
|
|
mutable llloadenv: llbbs.ca,
|
2011-07-27 14:19:39 +02:00
|
|
|
mutable llderivedtydescs_first: llbbs.dt,
|
|
|
|
mutable llderivedtydescs: llbbs.dt,
|
|
|
|
mutable lldynamicallocas: llbbs.da,
|
2011-08-17 17:49:54 -07:00
|
|
|
mutable llreturn: llbbs.rt,
|
2011-08-17 17:27:31 -07:00
|
|
|
mutable llobstacktoken: none::<ValueRef>,
|
2011-08-13 00:09:25 -07:00
|
|
|
mutable llself: none::<val_self_pair>,
|
2011-10-07 11:20:51 +02:00
|
|
|
llargs: new_int_hash::<local_val>(),
|
|
|
|
lllocals: new_int_hash::<local_val>(),
|
2011-09-14 13:26:39 +02:00
|
|
|
llupvars: new_int_hash::<ValueRef>(),
|
2012-01-02 16:50:51 +01:00
|
|
|
mutable lltyparams: [],
|
2011-12-22 14:24:36 +01:00
|
|
|
derived_tydescs: ty::new_ty_hash(),
|
2011-08-02 15:13:08 -07:00
|
|
|
id: id,
|
2011-09-14 13:48:51 +02:00
|
|
|
ret_style: rstyle,
|
2011-07-27 14:19:39 +02:00
|
|
|
sp: sp,
|
|
|
|
lcx: cx};
|
2010-09-27 15:38:34 -07:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn new_fn_ctxt(cx: @local_ctxt, sp: span, llfndecl: ValueRef) -> @fn_ctxt {
|
2011-09-14 13:48:51 +02:00
|
|
|
ret new_fn_ctxt_w_id(cx, sp, llfndecl, -1, ast::return_val);
|
2011-08-02 15:13:08 -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:
|
|
|
|
//
|
2011-09-14 14:34:50 +02:00
|
|
|
// - type_of_fn
|
2011-02-08 11:47:53 -08:00
|
|
|
// - 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-12-14 15:23:11 +01:00
|
|
|
fn create_llargs_for_fn_args(cx: @fn_ctxt, ty_self: self_arg,
|
2011-09-12 11:27:30 +02:00
|
|
|
args: [ast::arg], ty_params: [ast::ty_param]) {
|
2011-10-14 15:16:44 -07:00
|
|
|
// Skip the implicit arguments 0, and 1. TODO: Pull out 2u and define
|
|
|
|
// it as a constant, since we're using it in several places in trans this
|
|
|
|
// way.
|
2012-01-18 19:29:37 +08:00
|
|
|
let arg_n = 2u;
|
2011-07-27 14:19:39 +02:00
|
|
|
alt ty_self {
|
2012-01-13 10:58:31 +01:00
|
|
|
impl_self(tt) {
|
2011-12-16 11:37:38 +01:00
|
|
|
cx.llself = some({v: cx.llenv, t: tt});
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
no_self {}
|
2011-12-16 11:37:38 +01:00
|
|
|
}
|
2012-01-13 10:58:31 +01:00
|
|
|
for tp in ty_params {
|
2012-01-18 19:29:37 +08:00
|
|
|
let lltydesc = llvm::LLVMGetParam(cx.llfn, arg_n as c_uint);
|
|
|
|
let dicts = none;
|
|
|
|
arg_n += 1u;
|
2012-01-13 10:58:31 +01:00
|
|
|
for bound in *fcx_tcx(cx).ty_param_bounds.get(tp.id) {
|
|
|
|
alt bound {
|
|
|
|
ty::bound_iface(_) {
|
2012-01-18 19:29:37 +08:00
|
|
|
let dict = llvm::LLVMGetParam(cx.llfn, arg_n as c_uint);
|
|
|
|
arg_n += 1u;
|
2012-01-13 10:58:31 +01:00
|
|
|
dicts = some(alt dicts {
|
2012-01-18 22:37:22 -08:00
|
|
|
none { [dict] }
|
2012-01-13 10:58:31 +01:00
|
|
|
some(ds) { ds + [dict] }
|
|
|
|
});
|
|
|
|
}
|
|
|
|
_ {}
|
2012-01-02 16:50:51 +01:00
|
|
|
}
|
2011-02-09 09:54:58 -08:00
|
|
|
}
|
2012-01-13 10:58:31 +01:00
|
|
|
cx.lltyparams += [{desc: lltydesc, dicts: dicts}];
|
2010-12-20 14:33:11 -08:00
|
|
|
}
|
2011-08-02 16:24:38 -07: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-08-15 21:54:52 -07:00
|
|
|
for arg: ast::arg in args {
|
2012-01-18 19:29:37 +08:00
|
|
|
let llarg = llvm::LLVMGetParam(cx.llfn, arg_n as c_uint);
|
2011-05-02 17:47:24 -07:00
|
|
|
assert (llarg as int != 0);
|
2011-10-07 11:20:51 +02:00
|
|
|
// Note that this uses local_mem even for things passed by value.
|
|
|
|
// copy_args_to_allocas will overwrite the table entry with local_imm
|
|
|
|
// before it's actually used.
|
|
|
|
cx.llargs.insert(arg.id, local_mem(llarg));
|
2012-01-18 19:29:37 +08:00
|
|
|
arg_n += 1u;
|
2010-12-09 17:38:17 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-23 11:01:09 +02:00
|
|
|
fn copy_args_to_allocas(fcx: @fn_ctxt, bcx: @block_ctxt, args: [ast::arg],
|
2011-11-03 10:57:54 +01:00
|
|
|
arg_tys: [ty::arg]) -> @block_ctxt {
|
|
|
|
let arg_n: uint = 0u, bcx = bcx;
|
2011-10-06 14:17:56 +02:00
|
|
|
for arg in arg_tys {
|
|
|
|
let id = args[arg_n].id;
|
2011-10-07 11:20:51 +02:00
|
|
|
let argval = alt fcx.llargs.get(id) { local_mem(v) { v } };
|
2011-10-06 14:17:56 +02:00
|
|
|
alt arg.mode {
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::by_mut_ref { }
|
|
|
|
ast::by_move | ast::by_copy { add_clean(bcx, argval, arg.ty); }
|
|
|
|
ast::by_val {
|
2011-11-03 10:57:54 +01:00
|
|
|
if !ty::type_is_immediate(bcx_tcx(bcx), arg.ty) {
|
2011-10-07 11:20:51 +02:00
|
|
|
let {bcx: cx, val: alloc} = alloc_ty(bcx, arg.ty);
|
|
|
|
bcx = cx;
|
|
|
|
Store(bcx, argval, alloc);
|
|
|
|
fcx.llargs.insert(id, local_mem(alloc));
|
|
|
|
} else {
|
|
|
|
fcx.llargs.insert(id, local_imm(argval));
|
2011-10-06 14:17:56 +02:00
|
|
|
}
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::by_ref {}
|
2010-12-07 12:34:10 -08:00
|
|
|
}
|
2012-01-12 17:59:49 +01:00
|
|
|
if fcx_ccx(fcx).sess.opts.extra_debuginfo {
|
2011-12-14 15:14:06 -05:00
|
|
|
debuginfo::create_arg(bcx, args[arg_n]);
|
2011-12-06 00:05:22 -05:00
|
|
|
}
|
2010-11-26 17:47:27 -08:00
|
|
|
arg_n += 1u;
|
|
|
|
}
|
2011-09-23 11:01:09 +02:00
|
|
|
ret bcx;
|
2010-11-26 17:47:27 -08:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn arg_tys_of_fn(ccx: @crate_ctxt, id: ast::node_id) -> [ty::arg] {
|
2011-07-27 14:19:39 +02:00
|
|
|
alt ty::struct(ccx.tcx, ty::node_id_to_type(ccx.tcx, id)) {
|
2011-12-23 16:09:52 +01:00
|
|
|
ty::ty_fn({inputs, _}) { inputs }
|
2010-12-06 11:22:08 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-23 11:01:09 +02:00
|
|
|
// Ties up the llstaticallocas -> llloadenv -> llderivedtydescs ->
|
2011-08-17 17:49:54 -07:00
|
|
|
// lldynamicallocas -> lltop edges, and builds the return block.
|
2011-09-12 11:27:30 +02:00
|
|
|
fn finish_fn(fcx: @fn_ctxt, lltop: BasicBlockRef) {
|
2011-09-23 11:01:09 +02:00
|
|
|
Br(new_raw_block_ctxt(fcx, fcx.llstaticallocas), fcx.llloadenv);
|
|
|
|
Br(new_raw_block_ctxt(fcx, fcx.llloadenv), fcx.llderivedtydescs_first);
|
2011-09-02 15:34:58 -07:00
|
|
|
Br(new_raw_block_ctxt(fcx, fcx.llderivedtydescs), fcx.lldynamicallocas);
|
2011-08-30 09:59:30 +02:00
|
|
|
Br(new_raw_block_ctxt(fcx, fcx.lldynamicallocas), lltop);
|
2011-08-17 17:49:54 -07:00
|
|
|
|
2011-08-24 14:54:55 +02:00
|
|
|
let ret_cx = new_raw_block_ctxt(fcx, fcx.llreturn);
|
|
|
|
trans_fn_cleanups(fcx, ret_cx);
|
2011-08-30 09:59:30 +02:00
|
|
|
RetVoid(ret_cx);
|
2011-05-11 11:56:49 -07:00
|
|
|
}
|
|
|
|
|
2012-01-19 17:56:05 -08:00
|
|
|
enum self_arg { impl_self(ty::t), no_self, }
|
2011-12-14 15:23:11 +01:00
|
|
|
|
2011-06-29 19:50:50 -07:00
|
|
|
// trans_closure: Builds an LLVM function out of a source function.
|
|
|
|
// If the function closes over its environment a closure will be
|
|
|
|
// returned.
|
2011-12-22 17:49:54 +01:00
|
|
|
fn trans_closure(cx: @local_ctxt, sp: span, decl: ast::fn_decl,
|
|
|
|
body: ast::blk, llfndecl: ValueRef,
|
2011-12-14 15:23:11 +01:00
|
|
|
ty_self: self_arg, ty_params: [ast::ty_param],
|
2011-09-28 15:57:38 +02:00
|
|
|
id: ast::node_id, maybe_load_env: block(@fn_ctxt)) {
|
2011-05-24 13:47:27 -04:00
|
|
|
set_uwtable(llfndecl);
|
2010-11-26 17:47:27 -08:00
|
|
|
|
2011-06-28 18:54:05 -07:00
|
|
|
// Set up arguments to the function.
|
2011-12-22 17:49:54 +01:00
|
|
|
let fcx = new_fn_ctxt_w_id(cx, sp, llfndecl, id, decl.cf);
|
|
|
|
create_llargs_for_fn_args(fcx, ty_self, decl.inputs, ty_params);
|
2011-08-19 14:34:45 +02:00
|
|
|
|
|
|
|
// Create the first basic block in the function and keep a handle on it to
|
|
|
|
// pass to finish_fn later.
|
|
|
|
let bcx = new_top_block_ctxt(fcx);
|
|
|
|
let lltop = bcx.llbb;
|
2011-12-22 17:49:54 +01:00
|
|
|
let block_ty = node_id_type(cx.ccx, body.node.id);
|
2011-08-19 14:34:45 +02:00
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
let arg_tys = arg_tys_of_fn(fcx.lcx.ccx, id);
|
2011-12-22 17:49:54 +01:00
|
|
|
bcx = copy_args_to_allocas(fcx, bcx, decl.inputs, arg_tys);
|
2011-06-28 18:54:05 -07:00
|
|
|
|
2011-09-28 15:57:38 +02:00
|
|
|
maybe_load_env(fcx);
|
2011-06-28 18:54:05 -07:00
|
|
|
|
2011-08-16 21:34:52 +02:00
|
|
|
// This call to trans_block is the place where we bridge between
|
|
|
|
// translation calls that don't have a return value (trans_crate,
|
2012-01-13 10:58:31 +01:00
|
|
|
// trans_mod, trans_item, et cetera) and those that do
|
2011-08-16 21:34:52 +02:00
|
|
|
// (trans_block, trans_expr, et cetera).
|
2012-01-16 14:27:41 +01:00
|
|
|
if option::is_none(body.node.expr) ||
|
|
|
|
ty::type_is_bot(cx.ccx.tcx, block_ty) ||
|
|
|
|
ty::type_is_nil(cx.ccx.tcx, block_ty) {
|
|
|
|
bcx = trans_block(bcx, body);
|
2011-09-27 08:42:27 +02:00
|
|
|
} else {
|
2011-12-22 17:49:54 +01:00
|
|
|
bcx = trans_block_dps(bcx, body, save_in(fcx.llretptr));
|
2011-09-27 08:42:27 +02:00
|
|
|
}
|
2011-07-15 11:38:16 -07:00
|
|
|
|
2011-09-28 15:57:38 +02:00
|
|
|
// FIXME: until LLVM has a unit type, we are moving around
|
|
|
|
// C_nil values rather than their void type.
|
|
|
|
if !bcx.unreachable { build_return(bcx); }
|
2011-06-29 17:29:24 -07:00
|
|
|
// Insert the mandatory first few basic blocks before lltop.
|
2011-05-11 11:56:49 -07:00
|
|
|
finish_fn(fcx, lltop);
|
2011-06-29 19:50:50 -07:00
|
|
|
}
|
|
|
|
|
2011-07-19 11:56:46 -07:00
|
|
|
// trans_fn: creates an LLVM function corresponding to a source language
|
|
|
|
// function.
|
2011-12-22 17:49:54 +01:00
|
|
|
fn trans_fn(cx: @local_ctxt, sp: span, decl: ast::fn_decl, body: ast::blk,
|
|
|
|
llfndecl: ValueRef, ty_self: self_arg, ty_params: [ast::ty_param],
|
2011-07-27 14:19:39 +02:00
|
|
|
id: ast::node_id) {
|
2012-01-12 17:59:49 +01:00
|
|
|
let do_time = cx.ccx.sess.opts.stats;
|
2011-10-05 11:51:41 +02:00
|
|
|
let start = do_time ? time::get_time() : {sec: 0u32, usec: 0u32};
|
2011-12-06 00:05:22 -05:00
|
|
|
let fcx = option::none;
|
2011-12-22 17:49:54 +01:00
|
|
|
trans_closure(cx, sp, decl, body, llfndecl, ty_self, ty_params, id,
|
2011-12-19 02:52:21 -05:00
|
|
|
{|new_fcx| fcx = option::some(new_fcx);});
|
2012-01-12 17:59:49 +01:00
|
|
|
if cx.ccx.sess.opts.extra_debuginfo {
|
2011-12-18 23:32:38 -05:00
|
|
|
debuginfo::create_function(option::get(fcx));
|
2011-11-10 00:55:09 -05:00
|
|
|
}
|
2011-10-05 11:51:41 +02:00
|
|
|
if do_time {
|
|
|
|
let end = time::get_time();
|
|
|
|
log_fn_time(cx.ccx, str::connect(cx.path, "::"), start, end);
|
2011-07-19 11:56:46 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-22 17:49:54 +01:00
|
|
|
fn trans_res_ctor(cx: @local_ctxt, sp: span, dtor: ast::fn_decl,
|
2011-09-12 11:27:30 +02:00
|
|
|
ctor_id: ast::node_id, ty_params: [ast::ty_param]) {
|
2011-10-14 16:45:25 -07:00
|
|
|
let ccx = cx.ccx;
|
|
|
|
|
2011-06-30 12:35:19 +02:00
|
|
|
// Create a function for the constructor
|
2011-07-27 14:19:39 +02:00
|
|
|
let llctor_decl;
|
2011-10-14 16:45:25 -07:00
|
|
|
alt ccx.item_ids.find(ctor_id) {
|
2011-07-27 14:19:39 +02:00
|
|
|
some(x) { llctor_decl = x; }
|
2011-10-14 16:45:25 -07:00
|
|
|
_ { ccx.sess.span_fatal(sp, "unbound ctor_id in trans_res_ctor"); }
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
let fcx = new_fn_ctxt(cx, sp, llctor_decl);
|
|
|
|
let ret_t = ty::ret_ty_of_fn(cx.ccx.tcx, ctor_id);
|
2011-12-22 17:49:54 +01:00
|
|
|
create_llargs_for_fn_args(fcx, no_self, dtor.inputs, ty_params);
|
2011-07-27 14:19:39 +02:00
|
|
|
let bcx = new_top_block_ctxt(fcx);
|
|
|
|
let lltop = bcx.llbb;
|
2011-10-14 16:45:25 -07:00
|
|
|
let arg_t = arg_tys_of_fn(ccx, ctor_id)[0].ty;
|
|
|
|
let tup_t = ty::mk_tup(ccx.tcx, [ty::mk_int(ccx.tcx), arg_t]);
|
2011-12-22 17:49:54 +01:00
|
|
|
let arg = alt fcx.llargs.find(dtor.inputs[0].id) {
|
2011-11-16 13:35:34 +01:00
|
|
|
some(local_mem(x)) { x }
|
|
|
|
};
|
2011-07-27 14:19:39 +02:00
|
|
|
let llretptr = fcx.llretptr;
|
2011-10-14 16:45:25 -07:00
|
|
|
if ty::type_has_dynamic_size(ccx.tcx, ret_t) {
|
2011-11-17 13:36:09 -08:00
|
|
|
let llret_t = T_ptr(T_struct([ccx.int_type, llvm::LLVMTypeOf(arg)]));
|
2011-08-30 09:59:30 +02:00
|
|
|
llretptr = BitCast(bcx, llretptr, llret_t);
|
2011-06-30 14:46:17 +02:00
|
|
|
}
|
|
|
|
|
2011-09-17 10:18:30 -07:00
|
|
|
// FIXME: silly checks
|
|
|
|
check type_is_tup_like(bcx, tup_t);
|
2011-11-16 13:35:34 +01:00
|
|
|
let {bcx, val: dst} = GEP_tup_like(bcx, tup_t, llretptr, [0, 1]);
|
|
|
|
bcx = memmove_ty(bcx, dst, arg, arg_t);
|
2011-09-17 10:18:30 -07:00
|
|
|
check type_is_tup_like(bcx, tup_t);
|
2011-08-19 15:16:48 -07:00
|
|
|
let flag = GEP_tup_like(bcx, tup_t, llretptr, [0, 0]);
|
2011-06-28 16:14:01 +02:00
|
|
|
bcx = flag.bcx;
|
2011-11-17 13:43:34 -08:00
|
|
|
// FIXME #1184: Resource flag is larger than necessary
|
2011-11-17 13:36:09 -08:00
|
|
|
let one = C_int(ccx, 1);
|
|
|
|
Store(bcx, one, flag.val);
|
2011-08-17 17:49:54 -07:00
|
|
|
build_return(bcx);
|
2011-06-24 18:10:40 +02:00
|
|
|
finish_fn(fcx, lltop);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
|
2012-01-16 02:36:47 -07:00
|
|
|
variant: ast::variant, disr: int, is_degen: bool,
|
2011-09-12 11:27:30 +02:00
|
|
|
ty_params: [ast::ty_param]) {
|
2011-10-14 16:45:25 -07:00
|
|
|
let ccx = cx.ccx;
|
|
|
|
|
2011-12-13 16:25:51 -08: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-08-19 15:16:48 -07:00
|
|
|
let fn_args: [ast::arg] = [];
|
2011-07-27 14:19:39 +02:00
|
|
|
let i = 0u;
|
2011-08-15 21:54:52 -07:00
|
|
|
for varg: ast::variant_arg in variant.node.args {
|
2011-06-15 11:19:50 -07:00
|
|
|
fn_args +=
|
2011-11-16 13:35:34 +01:00
|
|
|
[{mode: ast::by_copy,
|
2011-08-19 15:16:48 -07:00
|
|
|
ty: varg.ty,
|
2011-09-02 15:34:58 -07:00
|
|
|
ident: "arg" + uint::to_str(i, 10u),
|
2011-08-19 15:16:48 -07:00
|
|
|
id: varg.id}];
|
2010-12-06 16:50:24 -08:00
|
|
|
}
|
2011-10-14 16:45:25 -07:00
|
|
|
assert (ccx.item_ids.contains_key(variant.node.id));
|
2011-07-27 14:19:39 +02:00
|
|
|
let llfndecl: ValueRef;
|
2011-10-14 16:45:25 -07:00
|
|
|
alt ccx.item_ids.find(variant.node.id) {
|
2011-07-27 14:19:39 +02:00
|
|
|
some(x) { llfndecl = x; }
|
|
|
|
_ {
|
2011-10-14 16:45:25 -07:00
|
|
|
ccx.sess.span_fatal(variant.span,
|
2011-09-02 15:34:58 -07:00
|
|
|
"unbound variant id in trans_tag_variant");
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-07-05 19:57:34 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
let fcx = new_fn_ctxt(cx, variant.span, llfndecl);
|
2011-12-14 15:23:11 +01:00
|
|
|
create_llargs_for_fn_args(fcx, no_self, fn_args, ty_params);
|
2011-08-19 15:16:48 -07:00
|
|
|
let ty_param_substs: [ty::t] = [];
|
2011-04-12 15:09:50 -07:00
|
|
|
i = 0u;
|
2011-08-15 21:54:52 -07:00
|
|
|
for tp: ast::ty_param in ty_params {
|
2011-12-29 11:23:35 +01:00
|
|
|
ty_param_substs += [ty::mk_param(ccx.tcx, i,
|
|
|
|
ast_util::local_def(tp.id))];
|
2011-04-12 15:09:50 -07:00
|
|
|
i += 1u;
|
2011-03-09 17:48:07 -08:00
|
|
|
}
|
2011-10-14 16:45:25 -07:00
|
|
|
let arg_tys = arg_tys_of_fn(ccx, variant.node.id);
|
2011-07-27 14:19:39 +02:00
|
|
|
let bcx = new_top_block_ctxt(fcx);
|
|
|
|
let lltop = bcx.llbb;
|
2011-11-03 10:57:54 +01:00
|
|
|
bcx = copy_args_to_allocas(fcx, bcx, fn_args, arg_tys);
|
2011-03-03 15:52:54 -08:00
|
|
|
|
2012-01-19 14:24:03 -08:00
|
|
|
// Cast the enum to a type we can GEP into.
|
2011-07-27 14:48:34 +02:00
|
|
|
let llblobptr =
|
2011-07-27 14:19:39 +02:00
|
|
|
if is_degen {
|
|
|
|
fcx.llretptr
|
|
|
|
} else {
|
|
|
|
let lltagptr =
|
2011-10-14 16:45:25 -07:00
|
|
|
PointerCast(bcx, fcx.llretptr, T_opaque_tag_ptr(ccx));
|
2011-10-25 22:23:28 -07:00
|
|
|
let lldiscrimptr = GEPi(bcx, lltagptr, [0, 0]);
|
2012-01-16 02:36:47 -07:00
|
|
|
Store(bcx, C_int(ccx, disr), lldiscrimptr);
|
2011-10-25 22:23:28 -07:00
|
|
|
GEPi(bcx, lltagptr, [0, 1])
|
2011-07-27 14:19:39 +02:00
|
|
|
};
|
2010-12-06 16:50:24 -08:00
|
|
|
i = 0u;
|
2011-09-01 17:25:06 -07:00
|
|
|
let t_id = ast_util::local_def(tag_id);
|
|
|
|
let v_id = ast_util::local_def(variant.node.id);
|
2011-08-15 21:54:52 -07:00
|
|
|
for va: ast::variant_arg in variant.node.args {
|
2011-09-02 15:34:58 -07:00
|
|
|
check (valid_variant_index(i, bcx, t_id, v_id));
|
|
|
|
let rslt = GEP_tag(bcx, llblobptr, t_id, v_id, ty_param_substs, i);
|
2011-03-03 15:52:54 -08:00
|
|
|
bcx = rslt.bcx;
|
2011-07-27 14:19:39 +02:00
|
|
|
let lldestptr = rslt.val;
|
2012-01-19 14:24:03 -08:00
|
|
|
// If this argument to this function is a enum, it'll have come in to
|
2011-03-04 15:08:33 -08:00
|
|
|
// 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-10-10 13:32:50 +02:00
|
|
|
let llarg = alt fcx.llargs.find(va.id) { some(local_mem(x)) { x } };
|
2011-08-19 15:16:48 -07:00
|
|
|
let arg_ty = arg_tys[i].ty;
|
2011-10-10 13:32:50 +02:00
|
|
|
if ty::type_contains_params(bcx_tcx(bcx), arg_ty) {
|
|
|
|
lldestptr = PointerCast(bcx, lldestptr, val_ty(llarg));
|
|
|
|
}
|
2011-11-16 13:35:34 +01:00
|
|
|
bcx = memmove_ty(bcx, lldestptr, llarg, arg_ty);
|
2010-12-06 16:50:24 -08:00
|
|
|
i += 1u;
|
|
|
|
}
|
2011-08-17 17:49:54 -07:00
|
|
|
build_return(bcx);
|
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-09-12 11:27:30 +02:00
|
|
|
fn trans_const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
|
2011-07-27 14:19:39 +02:00
|
|
|
alt e.node {
|
|
|
|
ast::expr_lit(lit) { ret trans_crate_lit(cx, *lit); }
|
2011-11-09 01:42:30 -08:00
|
|
|
ast::expr_binary(b, e1, e2) {
|
|
|
|
let te1 = trans_const_expr(cx, e1);
|
|
|
|
let te2 = trans_const_expr(cx, e2);
|
|
|
|
/* Neither type is bottom, and we expect them to be unified already,
|
|
|
|
* so the following is safe. */
|
|
|
|
let ty = ty::expr_ty(ccx_tcx(cx), e1);
|
|
|
|
let is_float = ty::type_is_fp(ccx_tcx(cx), ty);
|
|
|
|
let signed = ty::type_is_signed(ccx_tcx(cx), ty);
|
|
|
|
ret alt b {
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::add {
|
2011-11-09 01:42:30 -08:00
|
|
|
if is_float { llvm::LLVMConstFAdd(te1, te2) }
|
|
|
|
else { llvm::LLVMConstAdd(te1, te2) }
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::subtract {
|
2011-11-09 01:42:30 -08:00
|
|
|
if is_float { llvm::LLVMConstFSub(te1, te2) }
|
|
|
|
else { llvm::LLVMConstSub(te1, te2) }
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::mul {
|
2011-11-09 01:42:30 -08:00
|
|
|
if is_float { llvm::LLVMConstFMul(te1, te2) }
|
|
|
|
else { llvm::LLVMConstMul(te1, te2) }
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::div {
|
2011-11-09 01:42:30 -08:00
|
|
|
if is_float { llvm::LLVMConstFDiv(te1, te2) }
|
|
|
|
else if signed { llvm::LLVMConstSDiv(te1, te2) }
|
|
|
|
else { llvm::LLVMConstUDiv(te1, te2) }
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::rem {
|
2011-11-09 01:42:30 -08:00
|
|
|
if is_float { llvm::LLVMConstFRem(te1, te2) }
|
|
|
|
else if signed { llvm::LLVMConstSRem(te1, te2) }
|
|
|
|
else { llvm::LLVMConstURem(te1, te2) }
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::and |
|
|
|
|
ast::or { cx.sess.span_unimpl(e.span, "binop logic"); }
|
|
|
|
ast::bitxor { llvm::LLVMConstXor(te1, te2) }
|
|
|
|
ast::bitand { llvm::LLVMConstAnd(te1, te2) }
|
|
|
|
ast::bitor { llvm::LLVMConstOr(te1, te2) }
|
|
|
|
ast::lsl { llvm::LLVMConstShl(te1, te2) }
|
|
|
|
ast::lsr { llvm::LLVMConstLShr(te1, te2) }
|
|
|
|
ast::asr { llvm::LLVMConstAShr(te1, te2) }
|
|
|
|
ast::eq |
|
|
|
|
ast::lt |
|
|
|
|
ast::le |
|
|
|
|
ast::ne |
|
|
|
|
ast::ge |
|
|
|
|
ast::gt { cx.sess.span_unimpl(e.span, "binop comparator"); }
|
2011-11-09 01:42:30 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ast::expr_unary(u, e) {
|
|
|
|
let te = trans_const_expr(cx, e);
|
|
|
|
let ty = ty::expr_ty(ccx_tcx(cx), e);
|
|
|
|
let is_float = ty::type_is_fp(ccx_tcx(cx), ty);
|
|
|
|
ret alt u {
|
|
|
|
ast::box(_) |
|
|
|
|
ast::uniq(_) |
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::deref { cx.sess.span_bug(e.span,
|
2011-11-09 01:42:30 -08:00
|
|
|
"bad unop type in trans_const_expr"); }
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::not { llvm::LLVMConstNot(te) }
|
|
|
|
ast::neg {
|
2011-11-09 01:42:30 -08:00
|
|
|
if is_float { llvm::LLVMConstFNeg(te) }
|
|
|
|
else { llvm::LLVMConstNeg(te) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ { cx.sess.span_bug(e.span,
|
|
|
|
"bad constant expression type in trans_const_expr"); }
|
2011-01-21 12:09:25 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trans_const(cx: @crate_ctxt, e: @ast::expr, id: ast::node_id) {
|
2011-07-27 14:19:39 +02:00
|
|
|
let 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-07-27 14:19:39 +02:00
|
|
|
alt cx.consts.find(id) {
|
|
|
|
some(g) {
|
|
|
|
llvm::LLVMSetInitializer(g, v);
|
|
|
|
llvm::LLVMSetGlobalConstant(g, True);
|
|
|
|
}
|
2011-09-02 15:34:58 -07:00
|
|
|
_ { cx.sess.span_fatal(e.span, "Unbound const in trans_const"); }
|
2011-07-05 19:57:34 -07:00
|
|
|
}
|
2011-01-21 12:09:25 -08:00
|
|
|
}
|
|
|
|
|
2011-11-10 09:14:53 -08:00
|
|
|
type c_stack_tys = {
|
|
|
|
arg_tys: [TypeRef],
|
|
|
|
ret_ty: TypeRef,
|
2011-11-18 15:40:23 -08:00
|
|
|
ret_def: bool,
|
2011-11-10 09:14:53 -08:00
|
|
|
base_fn_ty: TypeRef,
|
|
|
|
bundle_ty: TypeRef,
|
|
|
|
shim_fn_ty: TypeRef
|
|
|
|
};
|
|
|
|
|
|
|
|
fn c_stack_tys(ccx: @crate_ctxt,
|
|
|
|
sp: span,
|
|
|
|
id: ast::node_id) -> @c_stack_tys {
|
|
|
|
alt ty::struct(ccx.tcx, ty::node_id_to_type(ccx.tcx, id)) {
|
2011-11-21 02:15:40 +08:00
|
|
|
ty::ty_native_fn(arg_tys, ret_ty) {
|
2011-11-18 15:40:23 -08:00
|
|
|
let tcx = ccx.tcx;
|
2011-11-10 09:14:53 -08:00
|
|
|
let llargtys = type_of_explicit_args(ccx, sp, arg_tys);
|
|
|
|
check non_ty_var(ccx, ret_ty); // NDM does this truly hold?
|
2011-11-18 15:40:23 -08:00
|
|
|
let llretty = type_of_inner(ccx, sp, ret_ty);
|
|
|
|
let bundle_ty = T_struct(llargtys + [T_ptr(llretty)]);
|
2011-11-10 09:14:53 -08:00
|
|
|
ret @{
|
|
|
|
arg_tys: llargtys,
|
|
|
|
ret_ty: llretty,
|
2011-11-18 15:40:23 -08:00
|
|
|
ret_def: !ty::type_is_bot(tcx, ret_ty) &&
|
|
|
|
!ty::type_is_nil(tcx, ret_ty),
|
2011-11-10 09:14:53 -08:00
|
|
|
base_fn_ty: T_fn(llargtys, llretty),
|
|
|
|
bundle_ty: bundle_ty,
|
|
|
|
shim_fn_ty: T_fn([T_ptr(bundle_ty)], T_void())
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
_ {
|
|
|
|
ccx.sess.span_fatal(
|
|
|
|
sp,
|
|
|
|
"Non-function type for native fn");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-17 18:45:18 -08:00
|
|
|
// For each native function F, we generate a wrapper function W and a shim
|
|
|
|
// function S that all work together. The wrapper function W is the function
|
|
|
|
// that other rust code actually invokes. Its job is to marshall the
|
|
|
|
// arguments into a struct. It then uses a small bit of assembly to switch
|
|
|
|
// over to the C stack and invoke the shim function. The shim function S then
|
|
|
|
// unpacks the arguments from the struct and invokes the actual function F
|
|
|
|
// according to its specified calling convention.
|
2011-11-10 09:14:53 -08:00
|
|
|
//
|
|
|
|
// Example: Given a native c-stack function F(x: X, y: Y) -> Z,
|
2011-11-17 18:45:18 -08:00
|
|
|
// we generate a wrapper function W that looks like:
|
2011-11-10 09:14:53 -08:00
|
|
|
//
|
2011-11-17 18:45:18 -08:00
|
|
|
// void W(Z* dest, void *env, X x, Y y) {
|
|
|
|
// struct { X x; Y y; Z *z; } args = { x, y, z };
|
|
|
|
// call_on_c_stack_shim(S, &args);
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// The shim function S then looks something like:
|
|
|
|
//
|
|
|
|
// void S(struct { X x; Y y; Z *z; } *args) {
|
2011-11-10 09:14:53 -08:00
|
|
|
// *args->z = F(args->x, args->y);
|
|
|
|
// }
|
|
|
|
//
|
2011-11-17 18:45:18 -08:00
|
|
|
// However, if the return type of F is dynamically sized or of aggregate type,
|
|
|
|
// the shim function looks like:
|
|
|
|
//
|
|
|
|
// void S(struct { X x; Y y; Z *z; } *args) {
|
|
|
|
// F(args->z, args->x, args->y);
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// Note: on i386, the layout of the args struct is generally the same as the
|
|
|
|
// desired layout of the arguments on the C stack. Therefore, we could use
|
|
|
|
// upcall_alloc_c_stack() to allocate the `args` structure and switch the
|
|
|
|
// stack pointer appropriately to avoid a round of copies. (In fact, the shim
|
|
|
|
// function itself is unnecessary). We used to do this, in fact, and will
|
|
|
|
// perhaps do so in the future.
|
2011-11-21 02:15:40 +08:00
|
|
|
fn trans_native_mod(lcx: @local_ctxt, native_mod: ast::native_mod,
|
|
|
|
abi: ast::native_abi) {
|
2011-11-15 11:31:48 -08:00
|
|
|
fn build_shim_fn(lcx: @local_ctxt,
|
|
|
|
native_item: @ast::native_item,
|
2011-11-17 18:45:18 -08:00
|
|
|
tys: @c_stack_tys,
|
|
|
|
cc: uint) -> ValueRef {
|
2011-11-16 16:13:43 -08:00
|
|
|
let lname = link_name(native_item);
|
2011-11-10 09:14:53 -08:00
|
|
|
let ccx = lcx_ccx(lcx);
|
|
|
|
let span = native_item.span;
|
|
|
|
|
|
|
|
// Declare the "prototype" for the base function F:
|
2011-11-16 16:13:43 -08:00
|
|
|
let llbasefn = decl_fn(ccx.llmod, lname, cc, tys.base_fn_ty);
|
2011-11-10 09:14:53 -08:00
|
|
|
|
2011-11-17 18:45:18 -08:00
|
|
|
// Create the shim function:
|
|
|
|
let shim_name = lname + "__c_stack_shim";
|
|
|
|
let llshimfn = decl_internal_cdecl_fn(
|
|
|
|
ccx.llmod, shim_name, tys.shim_fn_ty);
|
|
|
|
|
2011-11-10 09:14:53 -08:00
|
|
|
// Declare the body of the shim function:
|
|
|
|
let fcx = new_fn_ctxt(lcx, span, llshimfn);
|
|
|
|
let bcx = new_top_block_ctxt(fcx);
|
|
|
|
let lltop = bcx.llbb;
|
2012-01-18 19:29:37 +08:00
|
|
|
let llargbundle = llvm::LLVMGetParam(llshimfn, 0 as c_uint);
|
2011-11-10 09:14:53 -08:00
|
|
|
let i = 0u, n = vec::len(tys.arg_tys);
|
|
|
|
let llargvals = [];
|
|
|
|
while i < n {
|
|
|
|
let llargval = load_inbounds(bcx, llargbundle, [0, i as int]);
|
|
|
|
llargvals += [llargval];
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
|
2011-11-17 18:45:18 -08:00
|
|
|
// Create the call itself and store the return value:
|
2012-01-16 18:21:01 +08:00
|
|
|
let llretval = CallWithConv(bcx, llbasefn,
|
|
|
|
llargvals, cc as c_uint); // r
|
2011-11-18 15:40:23 -08:00
|
|
|
if tys.ret_def {
|
|
|
|
// R** llretptr = &args->r;
|
|
|
|
let llretptr = GEPi(bcx, llargbundle, [0, n as int]);
|
|
|
|
// R* llretloc = *llretptr; /* (args->r) */
|
|
|
|
let llretloc = Load(bcx, llretptr);
|
|
|
|
// *args->r = r;
|
|
|
|
Store(bcx, llretval, llretloc);
|
|
|
|
}
|
2011-11-17 18:45:18 -08:00
|
|
|
|
|
|
|
// Finish up:
|
|
|
|
build_return(bcx);
|
|
|
|
finish_fn(fcx, lltop);
|
|
|
|
|
|
|
|
ret llshimfn;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn build_wrap_fn(lcx: @local_ctxt,
|
|
|
|
native_item: @ast::native_item,
|
|
|
|
tys: @c_stack_tys,
|
2011-11-18 15:40:23 -08:00
|
|
|
num_tps: uint,
|
2011-11-17 18:45:18 -08:00
|
|
|
llshimfn: ValueRef,
|
|
|
|
llwrapfn: ValueRef) {
|
2011-11-18 15:40:23 -08:00
|
|
|
let span = native_item.span;
|
|
|
|
let ccx = lcx_ccx(lcx);
|
|
|
|
let fcx = new_fn_ctxt(lcx, span, llwrapfn);
|
2011-11-17 18:45:18 -08:00
|
|
|
let bcx = new_top_block_ctxt(fcx);
|
|
|
|
let lltop = bcx.llbb;
|
|
|
|
|
|
|
|
// Allocate the struct and write the arguments into it.
|
|
|
|
let llargbundle = alloca(bcx, tys.bundle_ty);
|
2011-11-18 15:40:23 -08:00
|
|
|
let i = 0u, n = vec::len(tys.arg_tys);
|
|
|
|
let implicit_args = 2u + num_tps; // ret + env
|
2011-11-17 18:45:18 -08:00
|
|
|
while i < n {
|
2012-01-16 18:21:01 +08:00
|
|
|
let llargval = llvm::LLVMGetParam(llwrapfn,
|
|
|
|
(i + implicit_args) as c_uint);
|
2011-11-17 18:45:18 -08:00
|
|
|
store_inbounds(bcx, llargval, llargbundle, [0, i as int]);
|
|
|
|
i += 1u;
|
|
|
|
}
|
2012-01-18 19:29:37 +08:00
|
|
|
let llretptr = llvm::LLVMGetParam(llwrapfn, 0 as c_uint);
|
2011-11-17 18:45:18 -08:00
|
|
|
store_inbounds(bcx, llretptr, llargbundle, [0, n as int]);
|
|
|
|
|
2011-11-18 15:40:23 -08:00
|
|
|
// Create call itself.
|
|
|
|
let call_shim_on_c_stack = ccx.upcalls.call_shim_on_c_stack;
|
|
|
|
let llshimfnptr = PointerCast(bcx, llshimfn, T_ptr(T_i8()));
|
|
|
|
let llrawargbundle = PointerCast(bcx, llargbundle, T_ptr(T_i8()));
|
|
|
|
Call(bcx, call_shim_on_c_stack, [llrawargbundle, llshimfnptr]);
|
2011-11-10 09:14:53 -08:00
|
|
|
build_return(bcx);
|
|
|
|
finish_fn(fcx, lltop);
|
|
|
|
}
|
|
|
|
|
|
|
|
let ccx = lcx_ccx(lcx);
|
2012-01-16 18:21:01 +08:00
|
|
|
let cc = lib::llvm::LLVMCCallConv;
|
2011-11-21 02:15:40 +08:00
|
|
|
alt abi {
|
2012-01-19 01:03:57 -08:00
|
|
|
ast::native_abi_rust_intrinsic { ret; }
|
|
|
|
ast::native_abi_cdecl { cc = lib::llvm::LLVMCCallConv; }
|
|
|
|
ast::native_abi_stdcall { cc = lib::llvm::LLVMX86StdcallCallConv; }
|
2011-11-15 16:49:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
for native_item in native_mod.items {
|
|
|
|
alt native_item.node {
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::native_item_ty {}
|
2011-11-18 15:40:23 -08:00
|
|
|
ast::native_item_fn(fn_decl, tps) {
|
|
|
|
let span = native_item.span;
|
2011-11-15 16:49:20 -08:00
|
|
|
let id = native_item.id;
|
2011-11-17 18:45:18 -08:00
|
|
|
let tys = c_stack_tys(ccx, span, id);
|
2011-11-15 16:49:20 -08:00
|
|
|
alt ccx.item_ids.find(id) {
|
2011-11-17 18:45:18 -08:00
|
|
|
some(llwrapfn) {
|
2011-11-18 15:40:23 -08:00
|
|
|
let llshimfn = build_shim_fn(lcx, native_item, tys, cc);
|
|
|
|
build_wrap_fn(lcx, native_item, tys,
|
|
|
|
vec::len(tps), llshimfn, llwrapfn);
|
2011-11-15 16:49:20 -08:00
|
|
|
}
|
2011-11-10 09:14:53 -08:00
|
|
|
|
2012-01-18 22:37:22 -08:00
|
|
|
none {
|
2011-11-15 16:49:20 -08:00
|
|
|
ccx.sess.span_fatal(
|
|
|
|
native_item.span,
|
|
|
|
"unbound function item in trans_native_mod");
|
2011-11-10 09:14:53 -08:00
|
|
|
}
|
2011-11-15 16:49:20 -08:00
|
|
|
}
|
2011-11-10 09:14:53 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trans_item(cx: @local_ctxt, item: ast::item) {
|
2011-07-27 14:19:39 +02:00
|
|
|
alt item.node {
|
2011-12-22 17:49:54 +01:00
|
|
|
ast::item_fn(decl, tps, body) {
|
2011-08-26 18:25:46 -07:00
|
|
|
let sub_cx = extend_path(cx, item.ident);
|
2011-07-27 14:19:39 +02:00
|
|
|
alt cx.ccx.item_ids.find(item.id) {
|
|
|
|
some(llfndecl) {
|
2011-12-22 17:49:54 +01:00
|
|
|
trans_fn(sub_cx, item.span, decl, body, llfndecl, no_self, tps,
|
|
|
|
item.id);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ {
|
|
|
|
cx.ccx.sess.span_fatal(item.span,
|
2011-09-02 15:34:58 -07:00
|
|
|
"unbound function item in trans_item");
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-05 13:57:27 +01:00
|
|
|
ast::item_impl(tps, _, _, ms) {
|
|
|
|
trans_impl::trans_impl(cx, item.ident, ms, item.id, tps);
|
2011-12-16 11:37:38 +01:00
|
|
|
}
|
2011-12-22 17:49:54 +01:00
|
|
|
ast::item_res(decl, tps, body, dtor_id, ctor_id) {
|
|
|
|
trans_res_ctor(cx, item.span, decl, ctor_id, tps);
|
2011-07-27 14:19:39 +02:00
|
|
|
|
|
|
|
// Create a function for the destructor
|
|
|
|
alt cx.ccx.item_ids.find(item.id) {
|
|
|
|
some(lldtor_decl) {
|
2011-12-22 17:49:54 +01:00
|
|
|
trans_fn(cx, item.span, decl, body, lldtor_decl, no_self,
|
|
|
|
tps, dtor_id);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ {
|
2011-09-02 15:34:58 -07:00
|
|
|
cx.ccx.sess.span_fatal(item.span, "unbound dtor in trans_item");
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2010-12-01 19:03:47 -08:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
ast::item_mod(m) {
|
|
|
|
let sub_cx =
|
2011-08-26 18:25:46 -07:00
|
|
|
@{path: cx.path + [item.ident],
|
2011-09-02 15:34:58 -07:00
|
|
|
module_path: cx.module_path + [item.ident] with *cx};
|
2011-07-27 14:19:39 +02:00
|
|
|
trans_mod(sub_cx, m);
|
|
|
|
}
|
|
|
|
ast::item_tag(variants, tps) {
|
2011-08-26 18:25:46 -07:00
|
|
|
let sub_cx = extend_path(cx, item.ident);
|
2011-12-13 16:25:51 -08:00
|
|
|
let degen = vec::len(variants) == 1u;
|
2012-01-16 02:36:47 -07:00
|
|
|
let vi = ty::tag_variants(cx.ccx.tcx, {crate: ast::local_crate,
|
|
|
|
node: item.id});
|
|
|
|
let i = 0;
|
2011-08-15 21:54:52 -07:00
|
|
|
for variant: ast::variant in variants {
|
2012-01-16 02:36:47 -07:00
|
|
|
trans_tag_variant(sub_cx, item.id, variant,
|
|
|
|
vi[i].disr_val, degen, tps);
|
|
|
|
i += 1;
|
2011-01-21 12:09:25 -08:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
ast::item_const(_, expr) { trans_const(cx.ccx, expr, item.id); }
|
2011-11-10 09:14:53 -08:00
|
|
|
ast::item_native_mod(native_mod) {
|
2011-11-21 02:15:40 +08:00
|
|
|
let abi = alt attr::native_abi(item.attrs) {
|
|
|
|
either::right(abi_) { abi_ }
|
|
|
|
either::left(msg) { cx.ccx.sess.span_fatal(item.span, msg) }
|
|
|
|
};
|
|
|
|
trans_native_mod(cx, native_mod, abi);
|
2011-11-10 09:14:53 -08:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
_ {/* fall through */ }
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-18 22:37:22 -08:00
|
|
|
// Translate a module. Doing this amounts to translating the items in the
|
2011-06-15 12:18:02 -07:00
|
|
|
// 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-09-12 11:27:30 +02:00
|
|
|
fn trans_mod(cx: @local_ctxt, m: ast::_mod) {
|
2011-08-15 21:54:52 -07:00
|
|
|
for item: @ast::item in m.items { trans_item(cx, *item); }
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
fn get_pair_fn_ty(llpairty: TypeRef) -> TypeRef {
|
2011-01-07 15:12:23 -08:00
|
|
|
// 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-09-18 22:05:58 +02:00
|
|
|
fn register_fn(ccx: @crate_ctxt, sp: span, path: [str], flav: str,
|
|
|
|
ty_params: [ast::ty_param], node_id: ast::node_id) {
|
2011-09-16 13:04:14 -07:00
|
|
|
// FIXME: pull this out
|
|
|
|
let t = node_id_type(ccx, node_id);
|
|
|
|
check returns_non_ty_var(ccx, t);
|
2011-09-18 22:05:58 +02:00
|
|
|
register_fn_full(ccx, sp, path, flav, ty_params, node_id, t);
|
2011-06-30 12:35:19 +02:00
|
|
|
}
|
|
|
|
|
2012-01-02 12:00:40 +01:00
|
|
|
fn param_bounds(ccx: @crate_ctxt, tp: ast::ty_param) -> ty::param_bounds {
|
2012-01-02 12:13:26 +01:00
|
|
|
ccx.tcx.ty_param_bounds.get(tp.id)
|
2012-01-02 12:00:40 +01:00
|
|
|
}
|
|
|
|
|
2011-09-18 22:05:58 +02:00
|
|
|
fn register_fn_full(ccx: @crate_ctxt, sp: span, path: [str], _flav: str,
|
2012-01-02 12:00:40 +01:00
|
|
|
tps: [ast::ty_param], node_id: ast::node_id,
|
2011-09-18 22:05:58 +02:00
|
|
|
node_type: ty::t)
|
2011-09-16 13:04:14 -07:00
|
|
|
: returns_non_ty_var(ccx, node_type) {
|
2011-08-26 21:34:56 -07:00
|
|
|
let path = path;
|
2012-01-02 12:00:40 +01:00
|
|
|
let llfty = type_of_fn_from_ty(ccx, sp, node_type,
|
|
|
|
vec::map(tps, {|p| param_bounds(ccx, p)}));
|
2011-09-02 15:34:58 -07:00
|
|
|
let ps: str = mangle_exported_name(ccx, path, node_type);
|
2011-09-27 18:42:06 -07:00
|
|
|
let llfn: ValueRef = decl_cdecl_fn(ccx.llmod, ps, llfty);
|
2011-09-18 22:05:58 +02:00
|
|
|
ccx.item_ids.insert(node_id, llfn);
|
|
|
|
ccx.item_symbols.insert(node_id, ps);
|
2011-08-12 18:43:44 -07:00
|
|
|
|
2012-01-12 17:59:49 +01:00
|
|
|
let is_main: bool = is_main_name(path) && !ccx.sess.building_library;
|
2011-08-19 15:16:48 -07:00
|
|
|
if is_main { create_main_wrapper(ccx, sp, llfn, node_type); }
|
2011-08-12 18:43:44 -07:00
|
|
|
}
|
|
|
|
|
2011-08-17 20:31:55 -07:00
|
|
|
// Create a _rust_main(args: [str]) function which will be called from the
|
|
|
|
// runtime rust_start function
|
2011-09-12 11:27:30 +02:00
|
|
|
fn create_main_wrapper(ccx: @crate_ctxt, sp: span, main_llfn: ValueRef,
|
2011-08-19 15:16:48 -07:00
|
|
|
main_node_type: ty::t) {
|
2011-08-12 18:43:44 -07:00
|
|
|
|
2011-08-13 00:09:25 -07:00
|
|
|
if ccx.main_fn != none::<ValueRef> {
|
2011-09-02 15:34:58 -07:00
|
|
|
ccx.sess.span_fatal(sp, "multiple 'main' functions");
|
2011-08-12 18:43:44 -07:00
|
|
|
}
|
|
|
|
|
2011-09-01 22:08:59 -07:00
|
|
|
let main_takes_argv =
|
2011-08-19 15:16:48 -07:00
|
|
|
alt ty::struct(ccx.tcx, main_node_type) {
|
2011-12-23 16:09:52 +01:00
|
|
|
ty::ty_fn({inputs, _}) { vec::len(inputs) != 0u }
|
2011-08-19 15:16:48 -07:00
|
|
|
};
|
2011-08-12 18:43:44 -07:00
|
|
|
|
2011-09-02 15:34:58 -07:00
|
|
|
let llfn = create_main(ccx, sp, main_llfn, main_takes_argv);
|
2011-08-17 16:50:49 -07:00
|
|
|
ccx.main_fn = some(llfn);
|
2011-10-20 13:48:10 +02:00
|
|
|
create_entry_fn(ccx, llfn);
|
2011-08-12 18:43:44 -07:00
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn create_main(ccx: @crate_ctxt, sp: span, main_llfn: ValueRef,
|
2011-09-01 22:08:59 -07:00
|
|
|
takes_argv: bool) -> ValueRef {
|
2011-09-02 16:52:14 -07:00
|
|
|
let unit_ty = ty::mk_str(ccx.tcx);
|
2011-09-02 16:09:41 +02:00
|
|
|
let vecarg_ty: ty::arg =
|
2011-10-10 13:54:03 +02:00
|
|
|
{mode: ast::by_val,
|
2011-09-02 15:34:58 -07:00
|
|
|
ty: ty::mk_vec(ccx.tcx, {ty: unit_ty, mut: ast::imm})};
|
2011-09-16 10:49:05 -07:00
|
|
|
// FIXME: mk_nil should have a postcondition
|
2011-09-15 20:47:38 -07:00
|
|
|
let nt = ty::mk_nil(ccx.tcx);
|
2012-01-13 10:58:31 +01:00
|
|
|
let llfty = type_of_fn(ccx, sp, [vecarg_ty], nt, []);
|
2011-09-27 18:42:06 -07:00
|
|
|
let llfdecl = decl_fn(ccx.llmod, "_rust_main",
|
2011-10-14 20:54:11 +02:00
|
|
|
lib::llvm::LLVMCCallConv, llfty);
|
2011-08-12 18:43:44 -07:00
|
|
|
|
|
|
|
let fcx = new_fn_ctxt(new_local_ctxt(ccx), sp, llfdecl);
|
2011-08-17 20:31:55 -07:00
|
|
|
|
2011-08-12 18:43:44 -07:00
|
|
|
let bcx = new_top_block_ctxt(fcx);
|
2011-08-17 20:31:55 -07:00
|
|
|
let lltop = bcx.llbb;
|
2011-08-12 18:43:44 -07:00
|
|
|
|
2012-01-18 19:29:37 +08:00
|
|
|
let lloutputarg = llvm::LLVMGetParam(llfdecl, 0 as c_uint);
|
|
|
|
let llenvarg = llvm::LLVMGetParam(llfdecl, 1 as c_uint);
|
2011-10-20 11:56:45 +02:00
|
|
|
let args = [lloutputarg, llenvarg];
|
2012-01-18 19:29:37 +08:00
|
|
|
if takes_argv { args += [llvm::LLVMGetParam(llfdecl, 2 as c_uint)]; }
|
2011-09-27 18:42:06 -07:00
|
|
|
Call(bcx, main_llfn, args);
|
2011-08-17 17:49:54 -07:00
|
|
|
build_return(bcx);
|
2011-08-12 18:43:44 -07:00
|
|
|
|
|
|
|
finish_fn(fcx, lltop);
|
|
|
|
|
|
|
|
ret llfdecl;
|
|
|
|
}
|
2011-10-20 13:48:10 +02:00
|
|
|
|
|
|
|
fn create_entry_fn(ccx: @crate_ctxt, rust_main: ValueRef) {
|
|
|
|
#[cfg(target_os = "win32")]
|
|
|
|
fn main_name() -> str { ret "WinMain@16"; }
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
fn main_name() -> str { ret "main"; }
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
fn main_name() -> str { ret "main"; }
|
2011-12-30 16:18:55 +08:00
|
|
|
#[cfg(target_os = "freebsd")]
|
|
|
|
fn main_name() -> str { ret "main"; }
|
2011-10-25 13:13:55 -07:00
|
|
|
let llfty = T_fn([ccx.int_type, ccx.int_type], ccx.int_type);
|
2011-10-20 13:48:10 +02:00
|
|
|
let llfn = decl_cdecl_fn(ccx.llmod, main_name(), llfty);
|
|
|
|
let llbb = str::as_buf("top", {|buf|
|
|
|
|
llvm::LLVMAppendBasicBlock(llfn, buf)
|
|
|
|
});
|
|
|
|
let bld = *ccx.builder;
|
|
|
|
llvm::LLVMPositionBuilderAtEnd(bld, llbb);
|
|
|
|
let crate_map = ccx.crate_map;
|
2011-10-25 13:13:55 -07:00
|
|
|
let start_ty = T_fn([val_ty(rust_main), ccx.int_type, ccx.int_type,
|
|
|
|
val_ty(crate_map)], ccx.int_type);
|
2011-10-20 13:48:10 +02:00
|
|
|
let start = str::as_buf("rust_start", {|buf|
|
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, start_ty, buf)
|
|
|
|
});
|
2012-01-18 19:29:37 +08:00
|
|
|
let args = [rust_main, llvm::LLVMGetParam(llfn, 0 as c_uint),
|
|
|
|
llvm::LLVMGetParam(llfn, 1 as c_uint), crate_map];
|
2011-10-20 13:48:10 +02:00
|
|
|
let result = unsafe {
|
|
|
|
llvm::LLVMBuildCall(bld, start, vec::to_ptr(args),
|
2012-01-16 18:21:01 +08:00
|
|
|
vec::len(args) as c_uint, noname())
|
2011-10-20 13:48:10 +02:00
|
|
|
};
|
|
|
|
llvm::LLVMBuildRet(bld, result);
|
|
|
|
}
|
2011-02-28 17:33:46 -05:00
|
|
|
}
|
|
|
|
|
2011-06-29 18:44:38 -07:00
|
|
|
// Create a /real/ closure: this is like create_fn_pair, but creates a
|
|
|
|
// a fn value on the stack with a specified environment (which need not be
|
|
|
|
// on the stack).
|
2011-09-12 11:27:30 +02:00
|
|
|
fn create_real_fn_pair(cx: @block_ctxt, llfnty: TypeRef, llfn: ValueRef,
|
2011-07-27 14:19:39 +02:00
|
|
|
llenvptr: ValueRef) -> ValueRef {
|
|
|
|
let lcx = cx.fcx.lcx;
|
2011-06-29 18:44:38 -07:00
|
|
|
|
2011-10-14 16:45:25 -07:00
|
|
|
let pair = alloca(cx, T_fn_pair(lcx.ccx, llfnty));
|
2011-09-28 15:57:38 +02:00
|
|
|
fill_fn_pair(cx, pair, llfn, llenvptr);
|
2011-06-29 18:44:38 -07:00
|
|
|
ret pair;
|
|
|
|
}
|
|
|
|
|
2011-09-28 15:57:38 +02:00
|
|
|
fn fill_fn_pair(bcx: @block_ctxt, pair: ValueRef, llfn: ValueRef,
|
|
|
|
llenvptr: ValueRef) {
|
2011-10-14 16:45:25 -07:00
|
|
|
let ccx = bcx_ccx(bcx);
|
2011-10-25 22:23:28 -07:00
|
|
|
let code_cell = GEPi(bcx, pair, [0, abi::fn_field_code]);
|
2011-09-28 15:57:38 +02:00
|
|
|
Store(bcx, llfn, code_cell);
|
2011-10-25 22:23:28 -07:00
|
|
|
let env_cell = GEPi(bcx, pair, [0, abi::fn_field_box]);
|
2011-09-28 15:57:38 +02:00
|
|
|
let llenvblobptr =
|
2012-01-05 16:19:12 -08:00
|
|
|
PointerCast(bcx, llenvptr, T_opaque_cbox_ptr(ccx));
|
2011-09-28 15:57:38 +02:00
|
|
|
Store(bcx, llenvblobptr, env_cell);
|
|
|
|
}
|
|
|
|
|
2011-03-08 16:51:23 -08:00
|
|
|
// Returns the number of type parameters that the given native function has.
|
2011-09-12 11:27:30 +02:00
|
|
|
fn native_fn_ty_param_count(cx: @crate_ctxt, id: ast::node_id) -> uint {
|
2011-07-27 14:19:39 +02:00
|
|
|
let count;
|
|
|
|
let native_item =
|
|
|
|
alt cx.ast_map.find(id) { some(ast_map::node_native_item(i)) { i } };
|
|
|
|
alt native_item.node {
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::native_item_ty {
|
2011-09-18 22:05:58 +02:00
|
|
|
cx.sess.bug("register_native_fn(): native fn isn't \
|
2011-07-22 23:56:02 -07:00
|
|
|
actually a fn");
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-11-14 21:06:39 +08:00
|
|
|
ast::native_item_fn(_, tps) {
|
2011-12-13 16:25:51 -08:00
|
|
|
count = vec::len::<ast::ty_param>(tps);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-03-08 16:51:23 -08:00
|
|
|
}
|
|
|
|
ret count;
|
|
|
|
}
|
|
|
|
|
2012-01-02 12:00:40 +01:00
|
|
|
fn native_fn_wrapper_type(cx: @crate_ctxt, sp: span,
|
|
|
|
param_bounds: [ty::param_bounds],
|
2011-07-27 14:19:39 +02:00
|
|
|
x: ty::t) -> TypeRef {
|
|
|
|
alt ty::struct(cx.tcx, x) {
|
2011-11-21 02:15:40 +08:00
|
|
|
ty::ty_native_fn(args, out) {
|
2012-01-13 10:58:31 +01:00
|
|
|
ret type_of_fn(cx, sp, args, out, param_bounds);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-02-28 17:33:46 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-28 15:15:54 -07:00
|
|
|
fn raw_native_fn_type(ccx: @crate_ctxt, sp: span, args: [ty::arg],
|
|
|
|
ret_ty: ty::t) -> TypeRef {
|
|
|
|
check type_has_static_size(ccx, ret_ty);
|
|
|
|
ret T_fn(type_of_explicit_args(ccx, sp, args), type_of(ccx, sp, ret_ty));
|
|
|
|
}
|
|
|
|
|
2011-11-16 16:13:43 -08:00
|
|
|
fn link_name(i: @ast::native_item) -> str {
|
|
|
|
alt attr::get_meta_item_value_str_by_name(i.attrs, "link_name") {
|
2012-01-18 22:37:22 -08:00
|
|
|
none { ret i.ident; }
|
2011-11-16 16:13:43 -08:00
|
|
|
option::some(ln) { ret ln; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-21 02:15:40 +08:00
|
|
|
fn collect_native_item(ccx: @crate_ctxt,
|
|
|
|
abi: @mutable option::t<ast::native_abi>,
|
|
|
|
i: @ast::native_item,
|
|
|
|
&&pt: [str],
|
2011-09-12 11:27:30 +02:00
|
|
|
_v: vt<[str]>) {
|
2011-07-27 14:19:39 +02:00
|
|
|
alt i.node {
|
2011-11-17 18:45:18 -08:00
|
|
|
ast::native_item_fn(_, tps) {
|
2012-01-02 12:58:31 +01:00
|
|
|
let sp = i.span;
|
|
|
|
let id = i.id;
|
|
|
|
let node_type = node_id_type(ccx, id);
|
|
|
|
let fn_abi =
|
|
|
|
alt attr::get_meta_item_value_str_by_name(i.attrs, "abi") {
|
2012-01-18 22:37:22 -08:00
|
|
|
option::none {
|
2011-11-21 02:15:40 +08:00
|
|
|
// if abi isn't specified for this function, inherit from
|
2012-01-02 12:58:31 +01:00
|
|
|
// its enclosing native module
|
|
|
|
option::get(*abi)
|
2011-11-21 02:15:40 +08:00
|
|
|
}
|
2012-01-02 12:58:31 +01:00
|
|
|
_ {
|
|
|
|
alt attr::native_abi(i.attrs) {
|
|
|
|
either::right(abi_) { abi_ }
|
|
|
|
either::left(msg) { ccx.sess.span_fatal(i.span, msg) }
|
|
|
|
}
|
2011-11-21 02:15:40 +08:00
|
|
|
}
|
|
|
|
};
|
2012-01-02 12:58:31 +01:00
|
|
|
alt fn_abi {
|
2012-01-19 01:03:57 -08:00
|
|
|
ast::native_abi_rust_intrinsic {
|
2012-01-02 12:58:31 +01:00
|
|
|
// For intrinsics: link the function directly to the intrinsic
|
|
|
|
// function itself.
|
|
|
|
let fn_type = type_of_fn_from_ty(
|
|
|
|
ccx, sp, node_type,
|
|
|
|
vec::map(tps, {|p| param_bounds(ccx, p)}));
|
|
|
|
let ri_name = "rust_intrinsic_" + link_name(i);
|
|
|
|
let llnativefn = get_extern_fn(
|
|
|
|
ccx.externs, ccx.llmod, ri_name,
|
|
|
|
lib::llvm::LLVMCCallConv, fn_type);
|
|
|
|
ccx.item_ids.insert(id, llnativefn);
|
|
|
|
ccx.item_symbols.insert(id, ri_name);
|
|
|
|
}
|
2011-11-17 18:45:18 -08:00
|
|
|
|
2012-01-19 01:03:57 -08:00
|
|
|
ast::native_abi_cdecl | ast::native_abi_stdcall {
|
2012-01-02 12:58:31 +01:00
|
|
|
// For true external functions: create a rust wrapper
|
|
|
|
// and link to that. The rust wrapper will handle
|
|
|
|
// switching to the C stack.
|
|
|
|
let new_pt = pt + [i.ident];
|
|
|
|
register_fn(ccx, i.span, new_pt, "native fn", tps, i.id);
|
|
|
|
}
|
2011-03-26 17:36:47 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ { }
|
2011-03-26 17:36:47 -07:00
|
|
|
}
|
|
|
|
}
|
2011-01-05 15:31:35 -08:00
|
|
|
|
2012-01-02 12:58:31 +01:00
|
|
|
fn collect_item(ccx: @crate_ctxt, abi: @mutable option::t<ast::native_abi>,
|
|
|
|
i: @ast::item, &&pt: [str], v: vt<[str]>) {
|
|
|
|
let new_pt = pt + [i.ident];
|
2011-07-27 14:19:39 +02:00
|
|
|
alt i.node {
|
|
|
|
ast::item_const(_, _) {
|
|
|
|
let typ = node_id_type(ccx, i.id);
|
|
|
|
let s =
|
2011-08-26 21:34:56 -07:00
|
|
|
mangle_exported_name(ccx, pt + [i.ident],
|
2011-07-27 14:19:39 +02:00
|
|
|
node_id_type(ccx, i.id));
|
2011-09-12 12:39:38 +02:00
|
|
|
// FIXME: Could follow from a constraint on types of const
|
|
|
|
// items
|
|
|
|
let g = str::as_buf(s, {|buf|
|
|
|
|
check (type_has_static_size(ccx, typ));
|
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, type_of(ccx, i.span, typ), buf)
|
|
|
|
});
|
2011-08-26 17:14:13 -07:00
|
|
|
ccx.item_symbols.insert(i.id, s);
|
2011-07-27 14:19:39 +02:00
|
|
|
ccx.consts.insert(i.id, g);
|
|
|
|
}
|
2011-11-21 02:15:40 +08:00
|
|
|
ast::item_native_mod(native_mod) {
|
|
|
|
// Propagate the native ABI down to collect_native_item(),
|
|
|
|
alt attr::native_abi(i.attrs) {
|
|
|
|
either::left(msg) { ccx.sess.span_fatal(i.span, msg); }
|
|
|
|
either::right(abi_) {
|
|
|
|
*abi = option::some(abi_);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-12-22 17:49:54 +01:00
|
|
|
ast::item_fn(_, tps, _) {
|
2012-01-02 12:58:31 +01:00
|
|
|
register_fn(ccx, i.span, new_pt, "fn", tps, i.id);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-12-20 16:33:55 +01:00
|
|
|
ast::item_impl(tps, _, _, methods) {
|
2012-01-05 14:55:23 +01:00
|
|
|
let name = i.ident + int::str(i.id);
|
2011-12-14 14:38:25 +01:00
|
|
|
for m in methods {
|
2011-12-22 17:49:54 +01:00
|
|
|
register_fn(ccx, i.span, pt + [name, m.ident],
|
|
|
|
"impl_method", tps + m.tps, m.id);
|
2011-12-14 14:38:25 +01:00
|
|
|
}
|
|
|
|
}
|
2011-12-22 17:49:54 +01:00
|
|
|
ast::item_res(_, tps, _, dtor_id, ctor_id) {
|
2011-09-18 22:05:58 +02:00
|
|
|
register_fn(ccx, i.span, new_pt, "res_ctor", tps, ctor_id);
|
2011-07-27 14:19:39 +02:00
|
|
|
// Note that the destructor is associated with the item's id, not
|
|
|
|
// the dtor_id. This is a bit counter-intuitive, but simplifies
|
|
|
|
// ty_res, which would have to carry around two def_ids otherwise
|
|
|
|
// -- one to identify the type, and one to find the dtor symbol.
|
2011-09-16 13:04:14 -07:00
|
|
|
let t = node_id_type(ccx, dtor_id);
|
|
|
|
// FIXME: how to get rid of this check?
|
|
|
|
check returns_non_ty_var(ccx, t);
|
2011-09-18 22:05:58 +02:00
|
|
|
register_fn_full(ccx, i.span, new_pt, "res_dtor", tps, i.id, t);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
ast::item_tag(variants, tps) {
|
2012-01-02 12:58:31 +01:00
|
|
|
for variant in variants {
|
2011-12-13 16:25:51 -08:00
|
|
|
if vec::len(variant.node.args) != 0u {
|
2011-09-18 22:05:58 +02:00
|
|
|
register_fn(ccx, i.span, new_pt + [variant.node.name],
|
2012-01-19 14:24:03 -08:00
|
|
|
"enum", tps, variant.node.id);
|
2011-01-05 15:31:35 -08:00
|
|
|
}
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-02 12:58:31 +01:00
|
|
|
_ { }
|
2011-01-05 15:31:35 -08:00
|
|
|
}
|
2012-01-02 12:58:31 +01:00
|
|
|
visit::visit_item(i, new_pt, v);
|
2011-01-05 15:31:35 -08:00
|
|
|
}
|
|
|
|
|
2012-01-02 12:58:31 +01:00
|
|
|
fn collect_items(ccx: @crate_ctxt, crate: @ast::crate) {
|
|
|
|
let abi = @mutable none::<ast::native_abi>;
|
|
|
|
visit::visit_crate(*crate, [], visit::mk_vt(@{
|
|
|
|
visit_native_item: bind collect_native_item(ccx, abi, _, _, _),
|
|
|
|
visit_item: bind collect_item(ccx, abi, _, _, _)
|
|
|
|
with *visit::default_visitor()
|
|
|
|
}));
|
2011-01-05 15:31:35 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
// The constant translation pass.
|
2011-10-10 13:54:03 +02:00
|
|
|
fn trans_constant(ccx: @crate_ctxt, it: @ast::item, &&pt: [str],
|
|
|
|
v: vt<[str]>) {
|
2011-12-14 14:38:25 +01:00
|
|
|
let new_pt = pt + [it.ident];
|
2011-06-10 17:24:20 +02:00
|
|
|
visit::visit_item(it, new_pt, v);
|
2011-07-27 14:19:39 +02:00
|
|
|
alt it.node {
|
|
|
|
ast::item_tag(variants, _) {
|
2012-01-16 02:36:47 -07:00
|
|
|
let vi = ty::tag_variants(ccx.tcx, {crate: ast::local_crate,
|
|
|
|
node: it.id});
|
|
|
|
let i = 0;
|
2012-01-02 12:58:31 +01:00
|
|
|
for variant in variants {
|
2012-01-02 13:26:51 +01:00
|
|
|
let p = new_pt + [variant.node.name, "discrim"];
|
2011-09-02 15:34:58 -07:00
|
|
|
let s = mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx));
|
2012-01-16 02:36:47 -07:00
|
|
|
let disr_val = vi[i].disr_val;
|
2012-01-02 12:58:31 +01:00
|
|
|
let discrim_gvar = str::as_buf(s, {|buf|
|
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type, buf)
|
|
|
|
});
|
2012-01-10 14:50:40 -07:00
|
|
|
llvm::LLVMSetInitializer(discrim_gvar, C_int(ccx, disr_val));
|
2011-09-06 22:44:16 -07:00
|
|
|
llvm::LLVMSetGlobalConstant(discrim_gvar, True);
|
2011-10-20 15:26:26 -07:00
|
|
|
ccx.discrims.insert(
|
|
|
|
ast_util::local_def(variant.node.id), discrim_gvar);
|
2011-08-26 17:14:13 -07:00
|
|
|
ccx.discrim_symbols.insert(variant.node.id, s);
|
2012-01-16 02:36:47 -07:00
|
|
|
i += 1;
|
2010-12-02 19:30:06 -08:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-02 13:26:51 +01:00
|
|
|
ast::item_impl(tps, some(@{node: ast::ty_path(_, id), _}), _, ms) {
|
|
|
|
let i_did = ast_util::def_id_of_def(ccx.tcx.def_map.get(id));
|
2012-01-12 16:57:30 +01:00
|
|
|
trans_impl::trans_impl_vtable(ccx, pt, i_did, ms, tps, it);
|
|
|
|
}
|
|
|
|
ast::item_iface(_, _) {
|
|
|
|
trans_impl::trans_iface_vtable(ccx, pt, it);
|
2012-01-02 13:26:51 +01:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
_ { }
|
2010-12-02 19:30:06 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trans_constants(ccx: @crate_ctxt, crate: @ast::crate) {
|
2011-07-27 14:19:39 +02:00
|
|
|
let visitor =
|
|
|
|
@{visit_item: bind trans_constant(ccx, _, _, _)
|
|
|
|
with *visit::default_visitor()};
|
2011-08-19 15:16:48 -07:00
|
|
|
visit::visit_crate(*crate, [], visit::mk_vt(visitor));
|
2010-12-02 19:30:06 -08:00
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn vp2i(cx: @block_ctxt, v: ValueRef) -> ValueRef {
|
2011-10-14 17:00:17 -07:00
|
|
|
let ccx = bcx_ccx(cx);
|
|
|
|
ret PtrToInt(cx, v, ccx.int_type);
|
2011-03-02 16:42:09 -08:00
|
|
|
}
|
|
|
|
|
2011-10-14 17:00:17 -07:00
|
|
|
fn p2i(ccx: @crate_ctxt, v: ValueRef) -> ValueRef {
|
|
|
|
ret llvm::LLVMConstPtrToInt(v, ccx.int_type);
|
|
|
|
}
|
2010-09-27 13:43:53 -07:00
|
|
|
|
2011-09-02 15:34:58 -07:00
|
|
|
fn declare_intrinsics(llmod: ModuleRef) -> hashmap<str, ValueRef> {
|
2011-08-04 16:20:09 -07:00
|
|
|
let T_memmove32_args: [TypeRef] =
|
2011-08-19 15:16:48 -07:00
|
|
|
[T_ptr(T_i8()), T_ptr(T_i8()), T_i32(), T_i32(), T_i1()];
|
2011-08-04 16:20:09 -07:00
|
|
|
let T_memmove64_args: [TypeRef] =
|
2011-08-19 15:16:48 -07:00
|
|
|
[T_ptr(T_i8()), T_ptr(T_i8()), T_i64(), T_i32(), T_i1()];
|
2011-08-04 16:20:09 -07:00
|
|
|
let T_memset32_args: [TypeRef] =
|
2011-08-19 15:16:48 -07:00
|
|
|
[T_ptr(T_i8()), T_i8(), T_i32(), T_i32(), T_i1()];
|
2011-08-04 16:20:09 -07:00
|
|
|
let T_memset64_args: [TypeRef] =
|
2011-08-19 15:16:48 -07:00
|
|
|
[T_ptr(T_i8()), T_i8(), T_i64(), T_i32(), T_i1()];
|
|
|
|
let T_trap_args: [TypeRef] = [];
|
2011-08-17 19:11:01 -07:00
|
|
|
let gcroot =
|
2011-09-02 15:34:58 -07:00
|
|
|
decl_cdecl_fn(llmod, "llvm.gcroot",
|
2011-08-19 15:16:48 -07:00
|
|
|
T_fn([T_ptr(T_ptr(T_i8())), T_ptr(T_i8())], T_void()));
|
2011-08-10 17:59:33 -07:00
|
|
|
let gcread =
|
2011-09-02 15:34:58 -07:00
|
|
|
decl_cdecl_fn(llmod, "llvm.gcread",
|
2011-08-19 15:16:48 -07:00
|
|
|
T_fn([T_ptr(T_i8()), T_ptr(T_ptr(T_i8()))], T_void()));
|
2011-07-27 14:19:39 +02:00
|
|
|
let memmove32 =
|
2011-09-02 15:34:58 -07:00
|
|
|
decl_cdecl_fn(llmod, "llvm.memmove.p0i8.p0i8.i32",
|
2011-06-15 11:19:50 -07:00
|
|
|
T_fn(T_memmove32_args, T_void()));
|
2011-07-27 14:19:39 +02:00
|
|
|
let memmove64 =
|
2011-09-02 15:34:58 -07:00
|
|
|
decl_cdecl_fn(llmod, "llvm.memmove.p0i8.p0i8.i64",
|
2011-06-15 11:19:50 -07:00
|
|
|
T_fn(T_memmove64_args, T_void()));
|
2011-07-27 14:19:39 +02:00
|
|
|
let memset32 =
|
2011-09-02 15:34:58 -07:00
|
|
|
decl_cdecl_fn(llmod, "llvm.memset.p0i8.i32",
|
2011-06-15 11:19:50 -07:00
|
|
|
T_fn(T_memset32_args, T_void()));
|
2011-07-27 14:19:39 +02:00
|
|
|
let memset64 =
|
2011-09-02 15:34:58 -07:00
|
|
|
decl_cdecl_fn(llmod, "llvm.memset.p0i8.i64",
|
2011-06-15 11:19:50 -07:00
|
|
|
T_fn(T_memset64_args, T_void()));
|
2011-09-02 15:34:58 -07:00
|
|
|
let trap = decl_cdecl_fn(llmod, "llvm.trap", T_fn(T_trap_args, T_void()));
|
2011-08-13 00:09:25 -07:00
|
|
|
let intrinsics = new_str_hash::<ValueRef>();
|
2011-09-02 15:34:58 -07:00
|
|
|
intrinsics.insert("llvm.gcroot", gcroot);
|
|
|
|
intrinsics.insert("llvm.gcread", gcread);
|
|
|
|
intrinsics.insert("llvm.memmove.p0i8.p0i8.i32", memmove32);
|
|
|
|
intrinsics.insert("llvm.memmove.p0i8.p0i8.i64", memmove64);
|
|
|
|
intrinsics.insert("llvm.memset.p0i8.i32", memset32);
|
|
|
|
intrinsics.insert("llvm.memset.p0i8.i64", memset64);
|
|
|
|
intrinsics.insert("llvm.trap", trap);
|
2010-11-25 17:45:26 -08:00
|
|
|
ret intrinsics;
|
2010-11-14 11:21:49 -08:00
|
|
|
}
|
|
|
|
|
2011-11-15 21:11:22 -05:00
|
|
|
fn declare_dbg_intrinsics(llmod: ModuleRef,
|
|
|
|
intrinsics: hashmap<str, ValueRef>) {
|
|
|
|
let declare =
|
|
|
|
decl_cdecl_fn(llmod, "llvm.dbg.declare",
|
|
|
|
T_fn([T_metadata(), T_metadata()], T_void()));
|
|
|
|
let value =
|
|
|
|
decl_cdecl_fn(llmod, "llvm.dbg.value",
|
|
|
|
T_fn([T_metadata(), T_i64(), T_metadata()], T_void()));
|
|
|
|
intrinsics.insert("llvm.dbg.declare", declare);
|
|
|
|
intrinsics.insert("llvm.dbg.value", value);
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trap(bcx: @block_ctxt) {
|
2011-08-19 15:16:48 -07:00
|
|
|
let v: [ValueRef] = [];
|
2011-09-02 15:34:58 -07:00
|
|
|
alt bcx_ccx(bcx).intrinsics.find("llvm.trap") {
|
2011-08-30 09:59:30 +02:00
|
|
|
some(x) { Call(bcx, x, v); }
|
2011-09-02 15:34:58 -07:00
|
|
|
_ { bcx_ccx(bcx).sess.bug("unbound llvm.trap in trap"); }
|
2011-07-05 19:57:34 -07:00
|
|
|
}
|
2011-02-02 15:23:49 -08:00
|
|
|
}
|
2010-12-06 17:17:49 -08:00
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn create_module_map(ccx: @crate_ctxt) -> ValueRef {
|
2011-10-14 17:00:17 -07:00
|
|
|
let elttype = T_struct([ccx.int_type, ccx.int_type]);
|
2011-07-27 14:19:39 +02:00
|
|
|
let maptype = T_array(elttype, ccx.module_data.size() + 1u);
|
2011-09-02 15:34:58 -07:00
|
|
|
let map =
|
|
|
|
str::as_buf("_rust_mod_map",
|
|
|
|
{|buf| llvm::LLVMAddGlobal(ccx.llmod, maptype, buf) });
|
2011-07-08 15:03:48 -04:00
|
|
|
llvm::LLVMSetLinkage(map,
|
2011-07-27 14:19:39 +02:00
|
|
|
lib::llvm::LLVMInternalLinkage as llvm::Linkage);
|
2011-08-19 15:16:48 -07:00
|
|
|
let elts: [ValueRef] = [];
|
2011-10-21 12:21:27 +02:00
|
|
|
ccx.module_data.items {|key, val|
|
2011-10-25 13:13:55 -07:00
|
|
|
let elt = C_struct([p2i(ccx, C_cstr(ccx, key)),
|
|
|
|
p2i(ccx, val)]);
|
2011-08-19 15:16:48 -07:00
|
|
|
elts += [elt];
|
2011-10-21 12:21:27 +02:00
|
|
|
};
|
2011-10-25 13:13:55 -07:00
|
|
|
let term = C_struct([C_int(ccx, 0), C_int(ccx, 0)]);
|
2011-08-19 15:16:48 -07:00
|
|
|
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
|
|
|
|
2011-10-20 13:48:10 +02:00
|
|
|
fn decl_crate_map(sess: session::session, mapname: str,
|
|
|
|
llmod: ModuleRef) -> ValueRef {
|
2012-01-12 17:59:49 +01:00
|
|
|
let targ_cfg = sess.targ_cfg;
|
2011-10-25 13:13:55 -07:00
|
|
|
let int_type = T_int(targ_cfg);
|
2011-10-20 13:48:10 +02:00
|
|
|
let n_subcrates = 1;
|
2012-01-12 17:59:49 +01:00
|
|
|
let cstore = sess.cstore;
|
2011-10-20 13:48:10 +02:00
|
|
|
while cstore::have_crate_data(cstore, n_subcrates) { n_subcrates += 1; }
|
2012-01-12 17:59:49 +01:00
|
|
|
let mapname = sess.building_library ? mapname : "toplevel";
|
2011-10-20 13:48:10 +02:00
|
|
|
let sym_name = "_rust_crate_map_" + mapname;
|
2011-10-25 13:13:55 -07:00
|
|
|
let arrtype = T_array(int_type, n_subcrates as uint);
|
|
|
|
let maptype = T_struct([int_type, arrtype]);
|
2011-10-20 13:48:10 +02:00
|
|
|
let map = str::as_buf(sym_name, {|buf|
|
|
|
|
llvm::LLVMAddGlobal(llmod, maptype, buf)
|
|
|
|
});
|
|
|
|
llvm::LLVMSetLinkage(map, lib::llvm::LLVMExternalLinkage
|
|
|
|
as llvm::Linkage);
|
|
|
|
ret map;
|
|
|
|
}
|
|
|
|
|
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-10-20 13:48:10 +02:00
|
|
|
fn fill_crate_map(ccx: @crate_ctxt, map: ValueRef) {
|
2011-08-19 15:16:48 -07:00
|
|
|
let subcrates: [ValueRef] = [];
|
2011-07-27 14:19:39 +02:00
|
|
|
let i = 1;
|
2012-01-12 17:59:49 +01:00
|
|
|
let cstore = ccx.sess.cstore;
|
2011-07-27 14:19:39 +02:00
|
|
|
while cstore::have_crate_data(cstore, i) {
|
2011-09-02 15:34:58 -07:00
|
|
|
let nm = "_rust_crate_map_" + cstore::get_crate_data(cstore, i).name;
|
2011-10-20 13:48:10 +02:00
|
|
|
let cr = str::as_buf(nm, {|buf|
|
2011-10-25 13:13:55 -07:00
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type, buf)
|
2011-10-20 13:48:10 +02:00
|
|
|
});
|
2011-10-25 13:13:55 -07:00
|
|
|
subcrates += [p2i(ccx, 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-10-14 17:00:17 -07:00
|
|
|
subcrates += [C_int(ccx, 0)];
|
2011-10-25 13:13:55 -07:00
|
|
|
llvm::LLVMSetInitializer(map, C_struct(
|
|
|
|
[p2i(ccx, create_module_map(ccx)),
|
|
|
|
C_array(ccx.int_type, 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
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn write_metadata(cx: @crate_ctxt, crate: @ast::crate) {
|
2012-01-12 17:59:49 +01:00
|
|
|
if !cx.sess.building_library { ret; }
|
2011-09-02 15:34:58 -07:00
|
|
|
let llmeta = C_postr(metadata::encoder::encode_metadata(cx, crate));
|
2011-08-19 15:16:48 -07:00
|
|
|
let llconst = trans_common::C_struct([llmeta]);
|
2011-09-02 15:34:58 -07:00
|
|
|
let llglobal =
|
|
|
|
str::as_buf("rust_metadata",
|
|
|
|
{|buf|
|
|
|
|
llvm::LLVMAddGlobal(cx.llmod, val_ty(llconst), buf)
|
|
|
|
});
|
2011-06-27 16:09:28 -07:00
|
|
|
llvm::LLVMSetInitializer(llglobal, llconst);
|
2011-09-02 15:34:58 -07:00
|
|
|
let _: () =
|
2012-01-12 17:59:49 +01:00
|
|
|
str::as_buf(cx.sess.targ_cfg.target_strs.meta_sect_name,
|
2011-09-02 15:34:58 -07:00
|
|
|
{|buf| llvm::LLVMSetSection(llglobal, buf) });
|
2011-07-20 14:52:31 -04:00
|
|
|
llvm::LLVMSetLinkage(llglobal,
|
|
|
|
lib::llvm::LLVMInternalLinkage as llvm::Linkage);
|
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
let t_ptr_i8 = T_ptr(T_i8());
|
2011-07-20 14:52:31 -04:00
|
|
|
llglobal = llvm::LLVMConstBitCast(llglobal, t_ptr_i8);
|
2011-09-02 15:34:58 -07:00
|
|
|
let llvm_used =
|
|
|
|
str::as_buf("llvm.used",
|
|
|
|
{|buf|
|
|
|
|
llvm::LLVMAddGlobal(cx.llmod, T_array(t_ptr_i8, 1u),
|
|
|
|
buf)
|
|
|
|
});
|
2011-07-20 14:52:31 -04:00
|
|
|
llvm::LLVMSetLinkage(llvm_used,
|
|
|
|
lib::llvm::LLVMAppendingLinkage as llvm::Linkage);
|
2011-08-19 15:16:48 -07:00
|
|
|
llvm::LLVMSetInitializer(llvm_used, C_array(t_ptr_i8, [llglobal]));
|
2011-06-27 16:09:28 -07:00
|
|
|
}
|
|
|
|
|
2011-08-20 14:22:09 -07:00
|
|
|
// Writes the current ABI version into the crate.
|
2011-09-12 11:27:30 +02:00
|
|
|
fn write_abi_version(ccx: @crate_ctxt) {
|
2011-10-14 17:00:17 -07:00
|
|
|
shape::mk_global(ccx, "rust_abi_version", C_uint(ccx, abi::abi_version),
|
2011-08-20 14:22:09 -07:00
|
|
|
false);
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
|
2011-12-15 18:42:27 +08:00
|
|
|
output: str, emap: resolve::exp_map, amap: ast_map::map,
|
|
|
|
mut_map: mut::mut_map, copy_map: alias::copy_map,
|
2012-01-02 16:50:51 +01:00
|
|
|
last_uses: last_use::last_uses, method_map: typeck::method_map,
|
|
|
|
dict_map: typeck::dict_map)
|
2011-12-03 00:51:59 +08:00
|
|
|
-> (ModuleRef, link::link_meta) {
|
2011-11-07 22:59:21 +08:00
|
|
|
let sha = std::sha1::mk_sha1();
|
|
|
|
let link_meta = link::build_link_meta(sess, *crate, output, sha);
|
2011-12-05 14:56:11 +08:00
|
|
|
|
|
|
|
// Append ".rc" to crate name as LLVM module identifier.
|
|
|
|
//
|
|
|
|
// LLVM code generator emits a ".file filename" directive
|
|
|
|
// for ELF backends. Value of the "filename" is set as the
|
|
|
|
// LLVM module identifier. Due to a LLVM MC bug[1], LLVM
|
|
|
|
// crashes if the module identifer is same as other symbols
|
2011-12-05 11:21:44 -08:00
|
|
|
// such as a function name in the module.
|
2011-12-05 14:56:11 +08:00
|
|
|
// 1. http://llvm.org/bugs/show_bug.cgi?id=11479
|
|
|
|
let llmod_id = link_meta.name + ".rc";
|
|
|
|
|
|
|
|
let llmod = str::as_buf(llmod_id, {|buf|
|
2011-09-12 12:39:38 +02:00
|
|
|
llvm::LLVMModuleCreateWithNameInContext
|
|
|
|
(buf, llvm::LLVMGetGlobalContext())
|
|
|
|
});
|
2012-01-12 17:59:49 +01:00
|
|
|
let data_layout = sess.targ_cfg.target_strs.data_layout;
|
|
|
|
let targ_triple = sess.targ_cfg.target_strs.target_triple;
|
2011-09-02 15:34:58 -07:00
|
|
|
let _: () =
|
2011-10-31 10:28:18 -07:00
|
|
|
str::as_buf(data_layout,
|
2011-09-02 15:34:58 -07:00
|
|
|
{|buf| llvm::LLVMSetDataLayout(llmod, buf) });
|
|
|
|
let _: () =
|
2011-10-31 10:28:18 -07:00
|
|
|
str::as_buf(targ_triple,
|
2011-09-02 15:34:58 -07:00
|
|
|
{|buf| llvm::LLVMSetTarget(llmod, buf) });
|
2012-01-12 17:59:49 +01:00
|
|
|
let targ_cfg = sess.targ_cfg;
|
|
|
|
let td = mk_target_data(sess.targ_cfg.target_strs.data_layout);
|
2011-07-27 14:19:39 +02:00
|
|
|
let tn = mk_type_names();
|
|
|
|
let intrinsics = declare_intrinsics(llmod);
|
2012-01-12 17:59:49 +01:00
|
|
|
if sess.opts.extra_debuginfo {
|
2011-11-15 21:11:22 -05:00
|
|
|
declare_dbg_intrinsics(llmod, intrinsics);
|
|
|
|
}
|
2011-10-14 20:38:24 -07:00
|
|
|
let int_type = T_int(targ_cfg);
|
|
|
|
let float_type = T_float(targ_cfg);
|
|
|
|
let task_type = T_task(targ_cfg);
|
2011-10-14 17:00:17 -07:00
|
|
|
let taskptr_type = T_ptr(task_type);
|
2012-01-13 09:32:05 +01:00
|
|
|
lib::llvm::associate_type(tn, "taskptr", taskptr_type);
|
2011-10-25 13:13:55 -07:00
|
|
|
let tydesc_type = T_tydesc(targ_cfg);
|
2012-01-13 09:32:05 +01:00
|
|
|
lib::llvm::associate_type(tn, "tydesc", tydesc_type);
|
2011-10-20 13:48:10 +02:00
|
|
|
let crate_map = decl_crate_map(sess, link_meta.name, llmod);
|
2012-01-12 17:59:49 +01:00
|
|
|
let dbg_cx = if sess.opts.debuginfo {
|
2011-12-09 11:32:23 -05:00
|
|
|
option::some(@{llmetadata: map::new_int_hash(),
|
2012-01-13 09:32:05 +01:00
|
|
|
names: new_namegen()})
|
2011-12-09 11:32:23 -05:00
|
|
|
} else {
|
|
|
|
option::none
|
|
|
|
};
|
2011-07-27 14:19:39 +02:00
|
|
|
let ccx =
|
|
|
|
@{sess: sess,
|
|
|
|
llmod: llmod,
|
|
|
|
td: td,
|
|
|
|
tn: tn,
|
2011-08-13 00:09:25 -07:00
|
|
|
externs: new_str_hash::<ValueRef>(),
|
2011-07-27 14:19:39 +02:00
|
|
|
intrinsics: intrinsics,
|
2011-08-13 00:09:25 -07:00
|
|
|
item_ids: new_int_hash::<ValueRef>(),
|
2011-07-27 14:19:39 +02:00
|
|
|
ast_map: amap,
|
2011-12-15 18:42:27 +08:00
|
|
|
exp_map: emap,
|
2011-09-02 15:34:58 -07:00
|
|
|
item_symbols: new_int_hash::<str>(),
|
2011-08-13 00:09:25 -07:00
|
|
|
mutable main_fn: none::<ValueRef>,
|
2011-10-20 13:48:10 +02:00
|
|
|
link_meta: link_meta,
|
2011-12-22 14:24:36 +01:00
|
|
|
tag_sizes: ty::new_ty_hash(),
|
2011-10-20 15:26:26 -07:00
|
|
|
discrims: ast_util::new_def_id_hash::<ValueRef>(),
|
2011-09-02 15:34:58 -07:00
|
|
|
discrim_symbols: new_int_hash::<str>(),
|
2011-08-13 00:09:25 -07:00
|
|
|
consts: new_int_hash::<ValueRef>(),
|
2011-12-22 14:24:36 +01:00
|
|
|
tydescs: ty::new_ty_hash(),
|
2012-01-06 14:22:31 +01:00
|
|
|
dicts: map::mk_hashmap(hash_dict_id, {|a, b| a == b}),
|
2011-08-13 00:09:25 -07:00
|
|
|
module_data: new_str_hash::<ValueRef>(),
|
2011-12-22 14:24:36 +01:00
|
|
|
lltypes: ty::new_ty_hash(),
|
2012-01-13 09:32:05 +01:00
|
|
|
names: new_namegen(),
|
2011-07-27 14:19:39 +02:00
|
|
|
sha: sha,
|
2011-12-22 14:24:36 +01:00
|
|
|
type_sha1s: ty::new_ty_hash(),
|
|
|
|
type_short_names: ty::new_ty_hash(),
|
2011-07-27 14:19:39 +02:00
|
|
|
tcx: tcx,
|
2011-08-19 14:34:45 +02:00
|
|
|
mut_map: mut_map,
|
2011-09-07 15:13:19 +02:00
|
|
|
copy_map: copy_map,
|
2011-11-18 15:10:14 +01:00
|
|
|
last_uses: last_uses,
|
2011-12-14 14:38:25 +01:00
|
|
|
method_map: method_map,
|
2012-01-02 16:50:51 +01:00
|
|
|
dict_map: dict_map,
|
2011-07-27 14:19:39 +02:00
|
|
|
stats:
|
|
|
|
{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,
|
2011-08-19 15:16:48 -07:00
|
|
|
fn_times: @mutable []},
|
2011-07-27 14:19:39 +02:00
|
|
|
upcalls:
|
2011-10-14 20:38:24 -07:00
|
|
|
upcall::declare_upcalls(targ_cfg, tn, tydesc_type,
|
|
|
|
llmod),
|
2011-07-27 14:19:39 +02:00
|
|
|
tydesc_type: tydesc_type,
|
2011-10-14 17:00:17 -07:00
|
|
|
int_type: int_type,
|
|
|
|
float_type: float_type,
|
2011-08-04 10:46:10 -07:00
|
|
|
task_type: task_type,
|
2011-10-14 20:38:24 -07:00
|
|
|
opaque_vec_type: T_opaque_vec(targ_cfg),
|
2011-08-24 16:30:20 +02:00
|
|
|
builder: BuilderRef_res(llvm::LLVMCreateBuilder()),
|
2011-08-17 19:11:01 -07:00
|
|
|
shape_cx: shape::mk_ctxt(llmod),
|
2011-10-20 13:48:10 +02:00
|
|
|
gc_cx: gc::mk_ctxt(),
|
2011-11-10 00:55:09 -05:00
|
|
|
crate_map: crate_map,
|
2011-12-09 11:32:23 -05:00
|
|
|
dbg_cx: dbg_cx};
|
2011-07-27 14:19:39 +02:00
|
|
|
let cx = new_local_ctxt(ccx);
|
2011-04-20 17:23:45 +02:00
|
|
|
collect_items(ccx, crate);
|
2011-04-20 17:43:13 +02:00
|
|
|
trans_constants(ccx, crate);
|
2010-10-05 18:21:44 -07:00
|
|
|
trans_mod(cx, crate.node.module);
|
2011-10-20 13:48:10 +02:00
|
|
|
fill_crate_map(ccx, crate_map);
|
2011-05-12 15:42:12 -07:00
|
|
|
emit_tydescs(ccx);
|
2011-08-04 11:25:09 -07:00
|
|
|
shape::gen_shape_tables(ccx);
|
2011-08-20 14:22:09 -07:00
|
|
|
write_abi_version(ccx);
|
2011-03-11 15:35:20 -08:00
|
|
|
|
2011-08-04 11:25:09 -07:00
|
|
|
// Translate the metadata.
|
2011-06-27 16:09:28 -07:00
|
|
|
write_metadata(cx.ccx, crate);
|
2012-01-12 17:59:49 +01:00
|
|
|
if ccx.sess.opts.stats {
|
2011-12-22 14:42:52 -08:00
|
|
|
#error("--- trans stats ---");
|
|
|
|
#error("n_static_tydescs: %u", ccx.stats.n_static_tydescs);
|
|
|
|
#error("n_derived_tydescs: %u", ccx.stats.n_derived_tydescs);
|
|
|
|
#error("n_glues_created: %u", ccx.stats.n_glues_created);
|
|
|
|
#error("n_null_glues: %u", ccx.stats.n_null_glues);
|
|
|
|
#error("n_real_glues: %u", ccx.stats.n_real_glues);
|
2011-07-19 11:56:46 -07:00
|
|
|
|
2011-09-02 15:34:58 -07:00
|
|
|
for timing: {ident: str, time: int} in *ccx.stats.fn_times {
|
2011-12-22 14:42:52 -08:00
|
|
|
#error("time: %s took %d ms", timing.ident, timing.time);
|
2011-07-19 11:56:46 -07:00
|
|
|
}
|
2011-05-12 15:42:12 -07:00
|
|
|
}
|
2011-12-03 00:51:59 +08:00
|
|
|
ret (llmod, link_meta);
|
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
|
|
|
|
// End:
|
|
|
|
//
|