trans.rs 227.0 KB
Newer Older
L
Lindsey Kuper 已提交
1 2 3 4 5 6
// trans.rs: Translate the completed AST to the LLVM IR.
//
// Some functions here, such as trans_block and trans_expr, return a value --
// the result of the translation to LLVM -- while others, such as trans_fn,
// trans_obj, and trans_item, are called only for the side effect of adding a
// particular definition to the LLVM IR output we're producing.
L
Lindsey Kuper 已提交
7 8
//
// Hopefully useful general knowledge about trans:
9
//
L
Lindsey Kuper 已提交
10 11 12 13 14
//   * 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.
G
Graydon Hoare 已提交
15
import std::{int, str, uint, map, option, fs, time, vec};
16
import std::map::hashmap;
G
Graydon Hoare 已提交
17 18
import std::map::{new_int_hash, new_str_hash};
import std::option::{some, none};
19
import driver::session;
G
Graydon Hoare 已提交
20
import middle::{ty, gc};
21
import middle::freevars::*;
G
Graydon Hoare 已提交
22 23
import back::{link, x86, abi, upcall};
import syntax::{ast, ast_util};
24
import syntax::visit;
G
Graydon Hoare 已提交
25 26
import syntax::codemap::span;
import syntax::print::pprust::{expr_to_str, path_to_str};
27
import visit::vt;
28
import util::common;
29
import util::common::*;
G
Graydon Hoare 已提交
30 31
import lib::llvm::{llvm, target_data, type_names,
                   mk_target_data, mk_type_names};
G
Graydon Hoare 已提交
32
import lib::llvm::llvm::{ModuleRef, ValueRef, TypeRef, TypeHandleRef,
G
Graydon Hoare 已提交
33 34 35 36 37 38 39 40 41
                         BuilderRef, BasicBlockRef};
import lib::llvm::{Bool, True, False};
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};
import metadata::{creader, csearch, cstore};
import util::ppaux::{ty_to_str, ty_to_short_str};
42

43
import trans_common::*;
44
import trans_build::*;
45

G
Graydon Hoare 已提交
46
import trans_objects::{trans_anon_obj, trans_obj};
47
import tvec = trans_vec;
48

49 50
fn type_of(cx: @crate_ctxt, sp: span, t: ty::t) : type_has_static_size(cx, t)
   -> TypeRef {
51
    // Should follow from type_has_static_size -- argh.
52
    // FIXME (requires Issue #586)
53
    check non_ty_var(cx, t);
54 55
    type_of_inner(cx, sp, t)
}
56

57
fn type_of_explicit_args(cx: @crate_ctxt, sp: span, inputs: [ty::arg]) ->
58
   [TypeRef] {
59
    let atys = [];
60 61
    for arg in inputs {
        let arg_ty = arg.ty;
62 63
        // FIXME: would be nice to have a constraint on arg
        // that would obviate the need for this check
64 65 66
        check non_ty_var(cx, arg_ty);
        atys += [T_ptr(type_of_inner(cx, sp, arg_ty))];
    }
67 68
    ret atys;
}
69

70

71 72
// NB: must keep 4 fns in sync:
//
73
//  - type_of_fn
74 75 76
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args
77 78
fn type_of_fn(cx: @crate_ctxt, sp: span, proto: ast::proto,
              is_method: bool, ret_ref: bool, inputs: [ty::arg],
79 80
              output: ty::t, ty_param_count: uint)
   : non_ty_var(cx, output) -> TypeRef {
B
Brian Anderson 已提交
81
    let atys: [TypeRef] = [];
82

L
Lindsey Kuper 已提交
83
    // Arg 0: Output pointer.
84 85
    let out_ty = T_ptr(type_of_inner(cx, sp, output));
    atys += [ret_ref ? T_ptr(out_ty) : out_ty];
86

L
Lindsey Kuper 已提交
87
    // Arg 1: task pointer.
B
Brian Anderson 已提交
88
    atys += [T_taskptr(*cx)];
89

L
Lindsey Kuper 已提交
90
    // Arg 2: Env (closure-bindings / self-obj)
M
Marijn Haverbeke 已提交
91
    if is_method {
B
Brian Anderson 已提交
92 93
        atys += [T_ptr(cx.rust_object_type)];
    } else { atys += [T_opaque_closure_ptr(*cx)]; }
94

L
Lindsey Kuper 已提交
95
    // Args >3: ty params, if not acquired via capture...
M
Marijn Haverbeke 已提交
96 97
    if !is_method {
        let i = 0u;
B
Brian Anderson 已提交
98
        while i < ty_param_count { atys += [T_ptr(cx.tydesc_type)]; i += 1u; }
99
    }
M
Marijn Haverbeke 已提交
100
    if proto == ast::proto_iter {
101 102 103
        // If it's an iter, the 'output' type of the iter is actually the
        // *input* type of the function we're given as our iter-block
        // argument.
104 105 106 107 108 109 110
        let iter_body_ty = ty::mk_iter_body_fn(cx.tcx, output);
        // FIXME: this check could be avoided pretty easily if we had
        // postconditions
        // (or better yet, just use a constraiend type that expresses
        // non-ty-var things)
        check non_ty_var(cx, iter_body_ty);
        atys += [type_of_inner(cx, sp, iter_body_ty)];
111
    }
L
Lindsey Kuper 已提交
112
    // ... then explicit args.
113
    atys += type_of_explicit_args(cx, sp, inputs);
114
    ret T_fn(atys, llvm::LLVMVoidType());
115 116
}

M
Michael Sullivan 已提交
117
// Given a function type and a count of ty params, construct an llvm type
118
fn type_of_fn_from_ty(cx: @crate_ctxt, sp: span, fty: ty::t,
119 120
                      ty_param_count: uint)
    : returns_non_ty_var(cx, fty) -> TypeRef {
121
    let by_ref = ast_util::ret_by_ref(ty::ty_fn_ret_style(cx.tcx, fty));
122 123 124
    // FIXME: Check should be unnecessary, b/c it's implied
    // by returns_non_ty_var(t). Make that a postcondition
    // (see Issue #586)
125 126
    let ret_ty = ty::ty_fn_ret(cx.tcx, fty);
    check non_ty_var(cx, ret_ty);
B
Brian Anderson 已提交
127
    ret type_of_fn(cx, sp, ty::ty_fn_proto(cx.tcx, fty),
128
                   false, by_ref, ty::ty_fn_args(cx.tcx, fty),
129
                   ret_ty, ty_param_count);
M
Michael Sullivan 已提交
130 131
}

132 133
fn type_of_inner(cx: @crate_ctxt, sp: span, t: ty::t)
    : non_ty_var(cx, t) -> TypeRef {
134 135
    // Check the cache.

M
Marijn Haverbeke 已提交
136
    if cx.lltypes.contains_key(t) { ret cx.lltypes.get(t); }
137
    let llty =
M
Marijn Haverbeke 已提交
138
    alt ty::struct(cx.tcx, t) {
139 140
      ty::ty_native(_) { T_ptr(T_i8()) }
      ty::ty_nil. { T_nil() }
M
Marijn Haverbeke 已提交
141
      ty::ty_bot. {
142
        T_nil() /* ...I guess? */
M
Marijn Haverbeke 已提交
143
      }
144 145 146 147
      ty::ty_bool. { T_bool() }
      ty::ty_int. { T_int() }
      ty::ty_float. { T_float() }
      ty::ty_uint. { T_int() }
M
Marijn Haverbeke 已提交
148 149
      ty::ty_machine(tm) {
        alt tm {
150 151 152 153 154 155
          ast::ty_i8. | ast::ty_u8. { T_i8() }
          ast::ty_i16. | ast::ty_u16. { T_i16() }
          ast::ty_i32. | ast::ty_u32. { T_i32() }
          ast::ty_i64. | ast::ty_u64. { T_i64() }
          ast::ty_f32. { T_f32() }
          ast::ty_f64. { T_f64() }
156
        }
M
Marijn Haverbeke 已提交
157
      }
158 159 160 161 162 163 164
      ty::ty_char. { T_char() }
      ty::ty_str. { T_ptr(T_vec(T_i8())) }
      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);
        T_ptr(T_box(type_of_inner(cx, sp, mt_ty))) }
165 166 167 168
      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)) }
169
      ty::ty_vec(mt) {
170 171 172 173 174 175 176 177 178 179 180 181
        let mt_ty = mt.ty;
        if ty::type_has_dynamic_size(cx.tcx, mt_ty) {
            T_ptr(T_opaque_vec())
        } else {
            // should be unnecessary
            check non_ty_var(cx, mt_ty);
            T_ptr(T_vec(type_of_inner(cx, sp, mt_ty))) }
      }
      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)) }
M
Marijn Haverbeke 已提交
182
      ty::ty_rec(fields) {
B
Brian Anderson 已提交
183
        let tys: [TypeRef] = [];
184
        for f: ty::field in fields {
185 186 187
            let mt_ty = f.mt.ty;
            check non_ty_var(cx, mt_ty);
            tys += [type_of_inner(cx, sp, mt_ty)];
M
Marijn Haverbeke 已提交
188
        }
189
        T_struct(tys)
M
Marijn Haverbeke 已提交
190
      }
M
Michael Sullivan 已提交
191
      ty::ty_fn(_, _, _, _, _) {
192 193
        // FIXME: could be a constraint on ty_fn
        check returns_non_ty_var(cx, t);
194
        T_fn_pair(*cx, type_of_fn_from_ty(cx, sp, t, 0u))
M
Marijn Haverbeke 已提交
195 196
      }
      ty::ty_native_fn(abi, args, out) {
197 198 199 200 201 202
        if native_abi_requires_pair(abi) {
            let nft = native_fn_wrapper_type(cx, sp, 0u, t);
            T_fn_pair(*cx, nft)
        } else {
            raw_native_fn_type(cx, sp, args, out)
        }
M
Marijn Haverbeke 已提交
203
      }
204
      ty::ty_obj(meths) { cx.rust_object_type }
M
Marijn Haverbeke 已提交
205 206
      ty::ty_res(_, sub, tps) {
        let sub1 = ty::substitute_type_params(cx.tcx, tps, sub);
207
        check non_ty_var(cx, sub1);
B
Brian Anderson 已提交
208
        ret T_struct([T_i32(), type_of_inner(cx, sp, sub1)]);
M
Marijn Haverbeke 已提交
209 210
      }
      ty::ty_var(_) {
211 212 213 214 215
        // 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()
M
Marijn Haverbeke 已提交
216
      }
217 218
      ty::ty_param(_, _) { T_typaram(cx.tn) }
      ty::ty_type. { T_ptr(cx.tydesc_type) }
219
      ty::ty_tup(elts) {
B
Brian Anderson 已提交
220
        let tys = [];
221 222 223 224 225
        for elt in elts {
            check non_ty_var(cx, elt);
            tys += [type_of_inner(cx, sp, elt)];
        }
        T_struct(tys)
226
      }
227
    };
228
    cx.lltypes.insert(t, llty);
229
    ret llty;
230 231
}

232 233
fn type_of_tag(cx: @crate_ctxt, sp: span, did: ast::def_id, t: ty::t)
    -> TypeRef {
B
Brian Anderson 已提交
234
    let degen = std::vec::len(ty::tag_variants(cx.tcx, did)) == 1u;
235
    if check type_has_static_size(cx, t) {
M
Marijn Haverbeke 已提交
236 237
        let size = static_size_of_tag(cx, sp, t);
        if !degen { ret T_tag(cx.tn, size); }
238
        // LLVM does not like 0-size arrays, apparently
M
Marijn Haverbeke 已提交
239
        if size == 0u { size = 1u; }
240 241
        ret T_array(T_i8(), size);
    }
242 243 244
    else {
        if degen { ret T_i8(); } else { ret T_opaque_tag(cx.tn); }
    }
245 246
}

247 248
fn type_of_ty_param_kinds_and_ty(lcx: @local_ctxt, sp: span,
                                 tpt: ty::ty_param_kinds_and_ty) -> TypeRef {
249 250 251
    let cx = lcx.ccx;
    let t = tpt.ty;
    alt ty::struct(cx.tcx, t) {
252
      ty::ty_fn(_, _, _, _, _) | ty::ty_native_fn(_, _, _) {
253
        check returns_non_ty_var(cx, t);
254
        ret type_of_fn_from_ty(cx, sp, t, std::vec::len(tpt.kinds));
M
Marijn Haverbeke 已提交
255 256 257 258
      }
      _ {
        // fall through
      }
259
    }
260 261 262
    // FIXME: could have a precondition on tpt, but that
    // doesn't work right now because one predicate can't imply
    // another
263
    check (type_has_static_size(cx, t));
264
    type_of(cx, sp, t)
265 266
}

267
fn type_of_or_i8(bcx: @block_ctxt, typ: ty::t) -> TypeRef {
268 269 270 271
    let ccx = bcx_ccx(bcx);
    if check type_has_static_size(ccx, typ) {
        let sp = bcx.sp;
        type_of(ccx, sp, typ)
272 273
    } else { T_i8() }
}
274

275

276 277
// Name sanitation. LLVM will happily accept identifiers with weird names, but
// gas doesn't!
278
fn sanitize(s: str) -> str {
B
Brian Anderson 已提交
279
    let result = "";
280
    for c: u8 in s {
M
Marijn Haverbeke 已提交
281
        if c == '@' as u8 {
B
Brian Anderson 已提交
282
            result += "boxed_";
283
        } else {
M
Marijn Haverbeke 已提交
284
            if c == ',' as u8 {
B
Brian Anderson 已提交
285
                result += "_";
286
            } else {
M
Marijn Haverbeke 已提交
287
                if c == '{' as u8 || c == '(' as u8 {
B
Brian Anderson 已提交
288
                    result += "_of_";
289
                } else {
M
Marijn Haverbeke 已提交
290 291 292
                    if c != 10u8 && c != '}' as u8 && c != ')' as u8 &&
                           c != ' ' as u8 && c != '\t' as u8 && c != ';' as u8
                       {
B
Brian Anderson 已提交
293
                        let v = [c];
294
                        result += str::unsafe_from_bytes(v);
295 296 297
                    }
                }
            }
298 299 300 301 302
        }
    }
    ret result;
}

303

304 305
fn log_fn_time(ccx: @crate_ctxt, name: str, start: time::timeval,
               end: time::timeval) {
M
Marijn Haverbeke 已提交
306 307 308
    let elapsed =
        1000 * (end.sec - start.sec as int) +
            ((end.usec as int) - (start.usec as int)) / 1000;
B
Brian Anderson 已提交
309
    *ccx.stats.fn_times += [{ident: name, time: elapsed}];
310 311 312
}


313
fn decl_fn(llmod: ModuleRef, name: str, cc: uint, llty: TypeRef) -> ValueRef {
B
Brian Anderson 已提交
314 315
    let llfn: ValueRef =
        str::as_buf(name, {|buf| llvm::LLVMAddFunction(llmod, buf, llty) });
316
    llvm::LLVMSetFunctionCallConv(llfn, cc);
317 318 319
    ret llfn;
}

320
fn decl_cdecl_fn(llmod: ModuleRef, name: str, llty: TypeRef) -> ValueRef {
321
    ret decl_fn(llmod, name, lib::llvm::LLVMCCallConv, llty);
322 323
}

324

325 326
// Only use this if you are going to actually define the function. It's
// not valid to simply declare a function as internal.
327
fn decl_internal_cdecl_fn(llmod: ModuleRef, name: str, llty: TypeRef) ->
328
   ValueRef {
329
    let llfn = decl_cdecl_fn(llmod, name, llty);
330 331
    llvm::LLVMSetLinkage(llfn,
                         lib::llvm::LLVMInternalLinkage as llvm::Linkage);
332 333 334
    ret llfn;
}

335
fn decl_glue(llmod: ModuleRef, cx: crate_ctxt, s: str) -> ValueRef {
B
Brian Anderson 已提交
336
    ret decl_cdecl_fn(llmod, s, T_fn([T_taskptr(cx)], T_void()));
337 338
}

339 340
fn get_extern_fn(externs: hashmap<str, ValueRef>, llmod: ModuleRef, name: str,
                 cc: uint, ty: TypeRef) -> ValueRef {
B
Brian Anderson 已提交
341
    if externs.contains_key(name) { ret externs.get(name); }
M
Marijn Haverbeke 已提交
342
    let f = decl_fn(llmod, name, cc, ty);
343
    externs.insert(name, f);
344 345 346
    ret f;
}

347 348
fn get_extern_const(externs: hashmap<str, ValueRef>, llmod: ModuleRef,
                    name: str, ty: TypeRef) -> ValueRef {
B
Brian Anderson 已提交
349 350
    if externs.contains_key(name) { ret externs.get(name); }
    let c = str::as_buf(name, {|buf| llvm::LLVMAddGlobal(llmod, ty, buf) });
351
    externs.insert(name, c);
352 353 354
    ret c;
}

355 356
fn get_simple_extern_fn(externs: hashmap<str, ValueRef>, llmod: ModuleRef,
                        name: str, n_args: int) -> ValueRef {
357
    let inputs = std::vec::init_elt::<TypeRef>(T_int(), n_args as uint);
M
Marijn Haverbeke 已提交
358 359
    let output = T_int();
    let t = T_fn(inputs, output);
360
    ret get_extern_fn(externs, llmod, name, lib::llvm::LLVMCCallConv, t);
361 362
}

363 364
fn trans_native_call(cx: @block_ctxt, externs: hashmap<str, ValueRef>,
                     llmod: ModuleRef, name: str, args: [ValueRef]) ->
B
Brian Anderson 已提交
365
   ValueRef {
366
    let n: int = std::vec::len::<ValueRef>(args) as int;
M
Marijn Haverbeke 已提交
367
    let llnative: ValueRef = get_simple_extern_fn(externs, llmod, name, n);
B
Brian Anderson 已提交
368
    let call_args: [ValueRef] = [];
B
Brian Anderson 已提交
369
    for a: ValueRef in args { call_args += [ZExtOrBitCast(cx, a, T_int())]; }
370
    ret Call(cx, llnative, call_args);
371 372
}

373
fn trans_non_gc_free(cx: @block_ctxt, v: ValueRef) -> @block_ctxt {
374
    Call(cx, bcx_ccx(cx).upcalls.free,
B
Brian Anderson 已提交
375
         [cx.fcx.lltaskptr, PointerCast(cx, v, T_ptr(T_i8())), C_int(0)]);
376
    ret cx;
377 378
}

379
fn trans_shared_free(cx: @block_ctxt, v: ValueRef) -> @block_ctxt {
380
    Call(cx, bcx_ccx(cx).upcalls.shared_free,
B
Brian Anderson 已提交
381
         [cx.fcx.lltaskptr, PointerCast(cx, v, T_ptr(T_i8()))]);
382
    ret cx;
383 384
}

385
fn umax(cx: @block_ctxt, a: ValueRef, b: ValueRef) -> ValueRef {
386 387
    let cond = ICmp(cx, lib::llvm::LLVMIntULT, a, b);
    ret Select(cx, cond, b, a);
388 389
}

390
fn umin(cx: @block_ctxt, a: ValueRef, b: ValueRef) -> ValueRef {
391 392
    let cond = ICmp(cx, lib::llvm::LLVMIntULT, a, b);
    ret Select(cx, cond, a, b);
393 394
}

395
fn align_to(cx: @block_ctxt, off: ValueRef, align: ValueRef) -> ValueRef {
396 397 398
    let mask = Sub(cx, align, C_int(1));
    let bumped = Add(cx, off, mask);
    ret And(cx, bumped, Not(cx, mask));
399 400
}

401

402
// Returns the real size of the given type for the current target.
403
fn llsize_of_real(cx: @crate_ctxt, t: TypeRef) -> uint {
404
    ret llvm::LLVMStoreSizeOfType(cx.td.lltd, t);
405 406
}

P
Patrick Walton 已提交
407
// Returns the real alignment of the given type for the current target.
408
fn llalign_of_real(cx: @crate_ctxt, t: TypeRef) -> uint {
P
Patrick Walton 已提交
409 410 411
    ret llvm::LLVMPreferredAlignmentOfType(cx.td.lltd, t);
}

M
Marijn Haverbeke 已提交
412
fn llsize_of(t: TypeRef) -> ValueRef {
413 414
    ret llvm::LLVMConstIntCast(lib::llvm::llvm::LLVMSizeOf(t), T_int(),
                               False);
415 416
}

M
Marijn Haverbeke 已提交
417
fn llalign_of(t: TypeRef) -> ValueRef {
418 419
    ret llvm::LLVMConstIntCast(lib::llvm::llvm::LLVMAlignOf(t), T_int(),
                               False);
420 421
}

422
fn size_of(cx: @block_ctxt, t: ty::t) -> result {
423 424 425 426
    let ccx = bcx_ccx(cx);
    if check type_has_static_size(ccx, t) {
        let sp = cx.sp;
        rslt(cx, llsize_of(type_of(ccx, sp, t)))
427
    } else { dynamic_size_of(cx, t) }
428 429
}

430
fn align_of(cx: @block_ctxt, t: ty::t) -> result {
431 432 433 434
    let ccx = bcx_ccx(cx);
    if check type_has_static_size(ccx, t) {
        let sp = cx.sp;
        rslt(cx, llalign_of(type_of(ccx, sp, t)))
435
    } else { dynamic_align_of(cx, t) }
436 437
}

438
fn alloca(cx: @block_ctxt, t: TypeRef) -> ValueRef {
M
Marijn Haverbeke 已提交
439
    if cx.unreachable { ret llvm::LLVMGetUndef(t); }
440
    ret Alloca(new_raw_block_ctxt(cx.fcx, cx.fcx.llstaticallocas), t);
441 442
}

443
fn dynastack_alloca(cx: @block_ctxt, t: TypeRef, n: ValueRef, ty: ty::t) ->
B
Brian Anderson 已提交
444
   ValueRef {
M
Marijn Haverbeke 已提交
445
    if cx.unreachable { ret llvm::LLVMGetUndef(t); }
446
    let bcx = cx;
447
    let dy_cx = new_raw_block_ctxt(cx.fcx, cx.fcx.lldynamicallocas);
448
    let lltaskptr = bcx_fcx(bcx).lltaskptr;
449
    alt bcx_fcx(cx).llobstacktoken {
B
Brian Anderson 已提交
450 451
      none. {
        bcx_fcx(cx).llobstacktoken =
452
            some(mk_obstack_token(bcx_ccx(cx), cx.fcx, lltaskptr));
B
Brian Anderson 已提交
453 454
      }
      some(_) {/* no-op */ }
455
    }
456 457

    let dynastack_alloc = bcx_ccx(bcx).upcalls.dynastack_alloc;
458
    let llsz = Mul(dy_cx, C_uint(llsize_of_real(bcx_ccx(bcx), t)), n);
459 460 461 462 463

    let ti = none;
    let lltydesc = get_tydesc(cx, ty, false, tps_normal, ti).result.val;

    let llresult = Call(dy_cx, dynastack_alloc, [lltaskptr, llsz, lltydesc]);
464
    ret PointerCast(dy_cx, llresult, T_ptr(t));
465 466
}

467
fn mk_obstack_token(ccx: @crate_ctxt, fcx: @fn_ctxt, lltaskptr: ValueRef) ->
B
Brian Anderson 已提交
468
   ValueRef {
469
    let cx = new_raw_block_ctxt(fcx, fcx.lldynamicallocas);
470
    ret Call(cx, ccx.upcalls.dynastack_mark, [lltaskptr]);
471 472 473
}


474 475 476 477
// 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.
478
fn simplify_type(ccx: @crate_ctxt, typ: ty::t) -> ty::t {
M
Marijn Haverbeke 已提交
479 480 481
    fn simplifier(ccx: @crate_ctxt, typ: ty::t) -> ty::t {
        alt ty::struct(ccx.tcx, typ) {
          ty::ty_box(_) { ret ty::mk_imm_box(ccx.tcx, ty::mk_nil(ccx.tcx)); }
482 483 484
          ty::ty_uniq(_) {
            ret ty::mk_imm_uniq(ccx.tcx, ty::mk_nil(ccx.tcx));
          }
M
Marijn Haverbeke 已提交
485
          ty::ty_fn(_, _, _, _, _) {
M
Marijn Haverbeke 已提交
486
            ret ty::mk_tup(ccx.tcx,
B
Brian Anderson 已提交
487 488
                           [ty::mk_imm_box(ccx.tcx, ty::mk_nil(ccx.tcx)),
                            ty::mk_imm_box(ccx.tcx, ty::mk_nil(ccx.tcx))]);
M
Marijn Haverbeke 已提交
489 490
          }
          ty::ty_obj(_) {
M
Marijn Haverbeke 已提交
491
            ret ty::mk_tup(ccx.tcx,
B
Brian Anderson 已提交
492 493
                           [ty::mk_imm_box(ccx.tcx, ty::mk_nil(ccx.tcx)),
                            ty::mk_imm_box(ccx.tcx, ty::mk_nil(ccx.tcx))]);
M
Marijn Haverbeke 已提交
494 495 496
          }
          ty::ty_res(_, sub, tps) {
            let sub1 = ty::substitute_type_params(ccx.tcx, tps, sub);
M
Marijn Haverbeke 已提交
497
            ret ty::mk_tup(ccx.tcx,
B
Brian Anderson 已提交
498
                           [ty::mk_int(ccx.tcx), simplify_type(ccx, sub1)]);
M
Marijn Haverbeke 已提交
499 500
          }
          _ { ret typ; }
501 502
        }
    }
503
    ret ty::fold_ty(ccx.tcx, ty::fm_general(bind simplifier(ccx, _)), typ);
504 505
}

506

507
// Computes the size of the data part of a non-dynamically-sized tag.
508 509
fn static_size_of_tag(cx: @crate_ctxt, sp: span, t: ty::t)
    : type_has_static_size(cx, t) -> uint {
M
Marijn Haverbeke 已提交
510 511 512 513
    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).
514

M
Marijn Haverbeke 已提交
515 516
        let max_size = 0u;
        let variants = ty::tag_variants(cx.tcx, tid);
517
        for variant: ty::variant_info in variants {
B
Brian Anderson 已提交
518
            let tup_ty = simplify_type(cx, ty::mk_tup(cx.tcx, variant.args));
M
Marijn Haverbeke 已提交
519
            // Perform any type parameter substitutions.
520

M
Marijn Haverbeke 已提交
521 522
            tup_ty = ty::substitute_type_params(cx.tcx, subtys, tup_ty);
            // Here we possibly do a recursive call.
523

524 525 526
            // 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.
527
            check (type_has_static_size(cx, tup_ty));
M
Marijn Haverbeke 已提交
528 529
            let this_size = llsize_of_real(cx, type_of(cx, sp, tup_ty));
            if max_size < this_size { max_size = this_size; }
530
        }
M
Marijn Haverbeke 已提交
531 532 533 534
        cx.tag_sizes.insert(t, max_size);
        ret max_size;
      }
      _ {
B
Brian Anderson 已提交
535
        cx.tcx.sess.span_fatal(sp, "non-tag passed to static_size_of_tag()");
M
Marijn Haverbeke 已提交
536
      }
537 538 539
    }
}

540 541
fn dynamic_size_of(cx: @block_ctxt, t: ty::t) -> result {
    fn align_elements(cx: @block_ctxt, elts: [ty::t]) -> result {
542 543 544 545 546 547 548 549
        //
        // 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.
        //
550

M
Marijn Haverbeke 已提交
551 552 553
        let off = C_int(0);
        let max_align = C_int(1);
        let bcx = cx;
554
        for e: ty::t in elts {
M
Marijn Haverbeke 已提交
555
            let elt_align = align_of(bcx, e);
556
            bcx = elt_align.bcx;
M
Marijn Haverbeke 已提交
557
            let elt_size = size_of(bcx, e);
558
            bcx = elt_size.bcx;
M
Marijn Haverbeke 已提交
559
            let aligned_off = align_to(bcx, off, elt_align.val);
560
            off = Add(bcx, aligned_off, elt_size.val);
561 562 563
            max_align = umax(bcx, max_align, elt_align.val);
        }
        off = align_to(bcx, off, max_align);
564
        ret rslt(bcx, off);
565
    }
M
Marijn Haverbeke 已提交
566
    alt ty::struct(bcx_tcx(cx), t) {
B
Brian Anderson 已提交
567
      ty::ty_param(p, _) {
M
Marijn Haverbeke 已提交
568
        let szptr = field_of_tydesc(cx, t, false, abi::tydesc_field_size);
569
        ret rslt(szptr.bcx, Load(szptr.bcx, szptr.val));
M
Marijn Haverbeke 已提交
570 571
      }
      ty::ty_rec(flds) {
B
Brian Anderson 已提交
572 573
        let tys: [ty::t] = [];
        for f: ty::field in flds { tys += [f.mt.ty]; }
M
Marijn Haverbeke 已提交
574 575
        ret align_elements(cx, tys);
      }
576
      ty::ty_tup(elts) {
B
Brian Anderson 已提交
577 578
        let tys = [];
        for tp in elts { tys += [tp]; }
579 580
        ret align_elements(cx, tys);
      }
M
Marijn Haverbeke 已提交
581 582 583 584 585
      ty::ty_tag(tid, tps) {
        let bcx = cx;
        // Compute max(variant sizes).

        let max_size: ValueRef = alloca(bcx, T_int());
586
        Store(bcx, C_int(0), max_size);
M
Marijn Haverbeke 已提交
587
        let variants = ty::tag_variants(bcx_tcx(bcx), tid);
588
        for variant: ty::variant_info in variants {
M
Marijn Haverbeke 已提交
589 590
            // Perform type substitution on the raw argument types.

591
            let raw_tys: [ty::t] = variant.args;
B
Brian Anderson 已提交
592
            let tys: [ty::t] = [];
593
            for raw_ty: ty::t in raw_tys {
M
Marijn Haverbeke 已提交
594
                let t = ty::substitute_type_params(bcx_tcx(cx), tps, raw_ty);
B
Brian Anderson 已提交
595
                tys += [t];
596
            }
M
Marijn Haverbeke 已提交
597 598 599
            let rslt = align_elements(bcx, tys);
            bcx = rslt.bcx;
            let this_size = rslt.val;
600 601
            let old_max_size = Load(bcx, max_size);
            Store(bcx, umax(bcx, this_size, old_max_size), max_size);
M
Marijn Haverbeke 已提交
602
        }
603
        let max_size_val = Load(bcx, max_size);
M
Marijn Haverbeke 已提交
604
        let total_size =
B
Brian Anderson 已提交
605
            if std::vec::len(variants) != 1u {
606
                Add(bcx, max_size_val, llsize_of(T_int()))
607
            } else { max_size_val };
M
Marijn Haverbeke 已提交
608 609
        ret rslt(bcx, total_size);
      }
610 611 612
    }
}

613
fn dynamic_align_of(cx: @block_ctxt, t: ty::t) -> result {
614 615
// FIXME: Typestate constraint that shows this alt is
// exhaustive
M
Marijn Haverbeke 已提交
616
    alt ty::struct(bcx_tcx(cx), t) {
B
Brian Anderson 已提交
617
      ty::ty_param(p, _) {
M
Marijn Haverbeke 已提交
618
        let aptr = field_of_tydesc(cx, t, false, abi::tydesc_field_align);
619
        ret rslt(aptr.bcx, Load(aptr.bcx, aptr.val));
M
Marijn Haverbeke 已提交
620 621 622 623
      }
      ty::ty_rec(flds) {
        let a = C_int(1);
        let bcx = cx;
624
        for f: ty::field in flds {
M
Marijn Haverbeke 已提交
625 626 627 628 629 630 631 632 633
            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(1)); // FIXME: stub
      }
634 635 636 637
      ty::ty_tup(elts) {
        let a = C_int(1);
        let bcx = cx;
        for e in elts {
M
Marijn Haverbeke 已提交
638
            let align = align_of(bcx, e);
639 640 641 642 643
            bcx = align.bcx;
            a = umax(bcx, a, align.val);
        }
        ret rslt(bcx, a);
      }
644 645 646
    }
}

647 648
// Simple wrapper around GEP that takes an array of ints and wraps them
// in C_int()
649
fn GEPi(cx: @block_ctxt, base: ValueRef, ixs: [int]) -> ValueRef {
B
Brian Anderson 已提交
650 651
    let v: [ValueRef] = [];
    for i: int in ixs { v += [C_int(i)]; }
652
    ret InBoundsGEP(cx, base, v);
653 654 655 656
}

// Increment a pointer by a given amount and then cast it to be a pointer
// to a given type.
657
fn bump_ptr(bcx: @block_ctxt, t: ty::t, base: ValueRef, sz: ValueRef) ->
B
Brian Anderson 已提交
658
   ValueRef {
659 660
    let raw = PointerCast(bcx, base, T_ptr(T_i8()));
    let bumped = GEP(bcx, raw, [sz]);
661 662 663 664 665
    let ccx = bcx_ccx(bcx);
    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)
666
    } else { bumped }
667
}
668

669 670 671 672 673 674 675 676
// 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);
}

677
// Replacement for the LLVM 'GEP' instruction when field-indexing into a
678
// tuple-like structure (tup, rec) with a static index. This one is driven off
679
// ty::struct and knows what to do when it runs into a ty_param stuck in the
680 681
// middle of the thing it's GEP'ing into. Much like size_of and align_of,
// above.
682 683
fn GEP_tup_like(cx: @block_ctxt, t: ty::t, base: ValueRef, ixs: [int])
    : type_is_tup_like(cx, t) -> result {
684
    // It might be a static-known type. Handle this.
M
Marijn Haverbeke 已提交
685
    if !ty::type_has_dynamic_size(bcx_tcx(cx), t) {
686
        ret rslt(cx, GEPi(cx, base, ixs));
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
    }
    // It is a dynamic-containing type that, if we convert directly to an LLVM
    // TypeRef, will be all wrong; there's no proper LLVM type to represent
    // it, and the lowering function will stick in i8* values for each
    // ty_param, which is not right; the ty_params are all of some dynamic
    // size.
    //
    // What we must do instead is sadder. We must look through the indices
    // manually and split the input type into a prefix and a target. We then
    // measure the prefix size, bump the input pointer by that amount, and
    // cast to a pointer-to-target type.

    // Given a type, an index vector and an element number N in that vector,
    // calculate index X and the type that results by taking the first X-1
    // elements of the type and splitting the Xth off. Return the prefix as
    // well as the innermost Xth type.

704
    fn split_type(ccx: @crate_ctxt, t: ty::t, ixs: [int], n: uint) ->
705
       {prefix: [ty::t], target: ty::t} {
706
        let len: uint = std::vec::len::<int>(ixs);
707
        // We don't support 0-index or 1-index GEPs: The former is nonsense
708 709 710
        // and the latter would only be meaningful if we supported non-0
        // values for the 0th index (we don't).

711
        assert (len > 1u);
M
Marijn Haverbeke 已提交
712
        if n == 0u {
713 714 715
            // Since we're starting from a value that's a pointer to a
            // *single* structure, the first index (in GEP-ese) should just be
            // 0, to yield the pointee.
716

B
Brian Anderson 已提交
717
            assert (ixs[n] == 0);
718
            ret split_type(ccx, t, ixs, n + 1u);
719
        }
720
        assert (n < len);
B
Brian Anderson 已提交
721 722
        let ix: int = ixs[n];
        let prefix: [ty::t] = [];
M
Marijn Haverbeke 已提交
723 724
        let i: int = 0;
        while i < ix {
B
Brian Anderson 已提交
725
            prefix += [ty::get_element_type(ccx.tcx, t, i as uint)];
726
            i += 1;
727
        }
M
Marijn Haverbeke 已提交
728 729
        let selected = ty::get_element_type(ccx.tcx, t, i as uint);
        if n == len - 1u {
730 731
            // We are at the innermost index.

M
Marijn Haverbeke 已提交
732
            ret {prefix: prefix, target: selected};
733 734 735 736
        } else {
            // Not the innermost index; call self recursively to dig deeper.
            // Once we get an inner result, append it current prefix and
            // return to caller.
737

M
Marijn Haverbeke 已提交
738
            let inner = split_type(ccx, selected, ixs, n + 1u);
739
            prefix += inner.prefix;
M
Marijn Haverbeke 已提交
740
            ret {prefix: prefix with inner};
741 742 743 744 745 746
        }
    }
    // We make a fake prefix tuple-type here; luckily for measuring sizes
    // the tuple parens are associative so it doesn't matter that we've
    // flattened the incoming structure.

M
Marijn Haverbeke 已提交
747
    let s = split_type(bcx_ccx(cx), t, ixs, 0u);
748

B
Brian Anderson 已提交
749 750
    let args = [];
    for typ: ty::t in s.prefix { args += [typ]; }
M
Marijn Haverbeke 已提交
751
    let prefix_ty = ty::mk_tup(bcx_tcx(cx), args);
752

M
Marijn Haverbeke 已提交
753 754
    let bcx = cx;
    let sz = size_of(bcx, prefix_ty);
755
    ret rslt(sz.bcx, bump_ptr(sz.bcx, s.target, base, sz.val));
756 757
}

758

759 760 761 762
// Replacement for the LLVM 'GEP' instruction when field indexing into a tag.
// This function uses GEP_tup_like() above and automatically performs casts as
// appropriate. @llblobptr is the data part of a tag value; its actual type is
// meaningless, as it will be cast away.
763 764
fn GEP_tag(cx: @block_ctxt, llblobptr: ValueRef, tag_id: ast::def_id,
           variant_id: ast::def_id, ty_substs: [ty::t],
B
Brian Anderson 已提交
765 766
           ix: uint) : valid_variant_index(ix, cx, tag_id, variant_id) ->
   result {
M
Marijn Haverbeke 已提交
767
    let variant = ty::tag_variant_with_id(bcx_tcx(cx), tag_id, variant_id);
768 769
    // Synthesize a tuple type so that GEP_tup_like() can work its magic.
    // Separately, store the type of the element we're interested in.
770

M
Marijn Haverbeke 已提交
771
    let arg_tys = variant.args;
772

B
Brian Anderson 已提交
773
    let true_arg_tys: [ty::t] = [];
774
    for aty: ty::t in arg_tys {
M
Marijn Haverbeke 已提交
775
        let arg_ty = ty::substitute_type_params(bcx_tcx(cx), ty_substs, aty);
B
Brian Anderson 已提交
776
        true_arg_tys += [arg_ty];
777
    }
T
Tim Chevalier 已提交
778 779 780 781 782 783 784

    // 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];

M
Marijn Haverbeke 已提交
785
    let tup_ty = ty::mk_tup(bcx_tcx(cx), true_arg_tys);
786 787
    // Cast the blob pointer to the appropriate type, if we need to (i.e. if
    // the blob pointer isn't dynamically sized).
788

M
Marijn Haverbeke 已提交
789
    let llunionptr: ValueRef;
790 791 792 793
    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);
794
        llunionptr = TruncOrBitCast(cx, llblobptr, T_ptr(llty));
795
    } else { llunionptr = llblobptr; }
796

797
    // Do the GEP_tup_like().
798 799
    // Silly check -- postcondition on mk_tup?
    check type_is_tup_like(cx, tup_ty);
800
    let rs = GEP_tup_like(cx, tup_ty, llunionptr, [0, ix as int]);
801
    // Cast the result to the appropriate type, if necessary.
802

803
    let rs_ccx = bcx_ccx(rs.bcx);
804 805 806 807 808
    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 };
809

810
    ret rslt(rs.bcx, val);
811 812
}

813 814
// trans_shared_malloc: expects a type indicating which pointer type we want
// and a size indicating how much space we want malloc'd.
815
fn trans_shared_malloc(cx: @block_ctxt, llptr_ty: TypeRef, llsize: ValueRef)
M
Marijn Haverbeke 已提交
816
   -> result {
817 818
    // FIXME: need a table to collect tydesc globals.

M
Marijn Haverbeke 已提交
819 820
    let tydesc = C_null(T_ptr(bcx_ccx(cx).tydesc_type));
    let rval =
821
        Call(cx, bcx_ccx(cx).upcalls.shared_malloc,
B
Brian Anderson 已提交
822
             [cx.fcx.lltaskptr, llsize, tydesc]);
823
    ret rslt(cx, PointerCast(cx, rval, llptr_ty));
824
}
L
Lindsey Kuper 已提交
825

826 827 828
// 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.
829
fn trans_malloc_boxed_raw(cx: @block_ctxt, t: ty::t) -> result {
830 831
    let bcx = cx;

832 833
    // Synthesize a fake box type structurally so we have something
    // to measure the size of.
L
Lindsey Kuper 已提交
834 835 836 837 838

    // 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.
839

840 841
    // The mk_int here is the space being
    // reserved for the refcount.
842 843 844 845
    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;
846

L
Lindsey Kuper 已提交
847 848
    // Grab the TypeRef type of box_ptr, because that's what trans_raw_malloc
    // wants.
849 850
    // FIXME: Could avoid this check with a postcondition on mk_imm_box?
    // (requires Issue #586)
851 852
    let ccx = bcx_ccx(bcx);
    let sp = bcx.sp;
853
    check (type_has_static_size(ccx, box_ptr));
854
    let llty = type_of(ccx, sp, box_ptr);
855

856 857 858 859 860 861
    let ti = none;
    let tydesc_result = get_tydesc(bcx, t, true, tps_normal, ti);
    let lltydesc = tydesc_result.result.val; bcx = tydesc_result.result.bcx;

    let rval = Call(cx, ccx.upcalls.malloc,
                    [cx.fcx.lltaskptr, llsz, lltydesc]);
862
    ret rslt(cx, PointerCast(cx, rval, llty));
863 864
}

865 866
// 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
867
fn trans_malloc_boxed(cx: @block_ctxt, t: ty::t) ->
B
Brian Anderson 已提交
868
   {bcx: @block_ctxt, box: ValueRef, body: ValueRef} {
869 870
    let res = trans_malloc_boxed_raw(cx, t);
    let box = res.val;
B
Brian Anderson 已提交
871
    let rc = GEPi(res.bcx, box, [0, abi::box_rc_field_refcnt]);
872
    Store(res.bcx, C_int(1), rc);
B
Brian Anderson 已提交
873
    let body = GEPi(res.bcx, box, [0, abi::box_rc_field_body]);
874
    ret {bcx: res.bcx, box: res.val, body: body};
875
}
876

877 878 879 880 881
// Type descriptor and type glue stuff

// Given a type and a field index into its corresponding type descriptor,
// returns an LLVM ValueRef of that field from the tydesc, generating the
// tydesc if necessary.
882
fn field_of_tydesc(cx: @block_ctxt, t: ty::t, escapes: bool, field: int) ->
883
   result {
884
    let ti = none::<@tydesc_info>;
885
    let tydesc = get_tydesc(cx, t, escapes, tps_normal, ti).result;
886
    ret rslt(tydesc.bcx,
887
             GEP(tydesc.bcx, tydesc.val, [C_int(0), C_int(field)]));
888
}
889

890

891
// Given a type containing ty params, build a vector containing a ValueRef for
892 893
// 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
894
// constructing derived tydescs.
895
fn linearize_ty_params(cx: @block_ctxt, t: ty::t) ->
896
   {params: [uint], descs: [ValueRef]} {
B
Brian Anderson 已提交
897 898
    let param_vals: [ValueRef] = [];
    let param_defs: [uint] = [];
M
Marijn Haverbeke 已提交
899
    type rr =
900
        {cx: @block_ctxt, mutable vals: [ValueRef], mutable defs: [uint]};
M
Marijn Haverbeke 已提交
901 902 903

    fn linearizer(r: @rr, t: ty::t) {
        alt ty::struct(bcx_tcx(r.cx), t) {
B
Brian Anderson 已提交
904
          ty::ty_param(pid, _) {
M
Marijn Haverbeke 已提交
905
            let seen: bool = false;
906
            for d: uint in r.defs { if d == pid { seen = true; } }
B
Brian Anderson 已提交
907
            if !seen { r.vals += [r.cx.fcx.lltydescs[pid]]; r.defs += [pid]; }
M
Marijn Haverbeke 已提交
908 909
          }
          _ { }
910 911
        }
    }
M
Marijn Haverbeke 已提交
912 913
    let x = @{cx: cx, mutable vals: param_vals, mutable defs: param_defs};
    let f = bind linearizer(x, _);
914
    ty::walk_ty(bcx_tcx(cx), f, t);
M
Marijn Haverbeke 已提交
915
    ret {params: x.defs, descs: x.vals};
916 917
}

918
fn trans_stack_local_derived_tydesc(cx: @block_ctxt, llsz: ValueRef,
M
Marijn Haverbeke 已提交
919
                                    llalign: ValueRef, llroottydesc: ValueRef,
920
                                    llfirstparam: ValueRef, n_params: uint,
B
Brian Anderson 已提交
921
                                    obj_params: uint) -> ValueRef {
M
Marijn Haverbeke 已提交
922
    let llmyroottydesc = alloca(cx, bcx_ccx(cx).tydesc_type);
923

924
    // By convention, desc 0 is the root descriptor.
925 926
    llroottydesc = Load(cx, llroottydesc);
    Store(cx, llroottydesc, llmyroottydesc);
927

928
    // Store a pointer to the rest of the descriptors.
P
Patrick Walton 已提交
929
    store_inbounds(cx, llfirstparam, llmyroottydesc,
B
Brian Anderson 已提交
930
                   [C_int(0), C_int(abi::tydesc_field_first_param)]);
P
Patrick Walton 已提交
931
    store_inbounds(cx, C_uint(n_params), llmyroottydesc,
B
Brian Anderson 已提交
932
                   [C_int(0), C_int(abi::tydesc_field_n_params)]);
P
Patrick Walton 已提交
933
    store_inbounds(cx, llsz, llmyroottydesc,
B
Brian Anderson 已提交
934
                   [C_int(0), C_int(abi::tydesc_field_size)]);
P
Patrick Walton 已提交
935
    store_inbounds(cx, llalign, llmyroottydesc,
B
Brian Anderson 已提交
936
                   [C_int(0), C_int(abi::tydesc_field_align)]);
937 938
    store_inbounds(cx, C_uint(obj_params), llmyroottydesc,
                   [C_int(0), C_int(abi::tydesc_field_obj_params)]);
939
    ret llmyroottydesc;
940 941
}

P
Patrick Walton 已提交
942 943
// Objects and closures store their type parameters differently (in the object
// or closure itself rather than in the type descriptor).
B
Brian Anderson 已提交
944
tag ty_param_storage { tps_normal; tps_obj(uint); tps_fn(uint); }
945

946
fn get_derived_tydesc(cx: @block_ctxt, t: ty::t, escapes: bool,
947
                      storage: ty_param_storage,
948
                      &static_ti: option::t<@tydesc_info>) -> result {
M
Marijn Haverbeke 已提交
949 950
    alt cx.fcx.derived_tydescs.find(t) {
      some(info) {
951

M
Marijn Haverbeke 已提交
952 953 954

        // If the tydesc escapes in this context, the cached derived
        // tydesc also has to be one that was marked as escaping.
955 956 957
        if !(escapes && !info.escapes) && storage == tps_normal {
            ret rslt(cx, info.lltydesc);
        }
M
Marijn Haverbeke 已提交
958 959
      }
      none. {/* fall through */ }
960
    }
961

962 963 964 965 966 967
    let is_obj_body;
    alt storage {
        tps_normal. { is_obj_body = false; }
        tps_obj(_) | tps_fn(_) { is_obj_body = true; }
    }

968
    bcx_ccx(cx).stats.n_derived_tydescs += 1u;
M
Marijn Haverbeke 已提交
969 970
    let bcx = new_raw_block_ctxt(cx.fcx, cx.fcx.llderivedtydescs);
    let tys = linearize_ty_params(bcx, t);
971
    let root_ti = get_static_tydesc(bcx, t, tys.params, is_obj_body);
972
    static_ti = some::<@tydesc_info>(root_ti);
973
    lazily_emit_all_tydesc_glue(cx, static_ti);
M
Marijn Haverbeke 已提交
974 975
    let root = root_ti.tydesc;
    let sz = size_of(bcx, t);
976
    bcx = sz.bcx;
M
Marijn Haverbeke 已提交
977
    let align = align_of(bcx, t);
978
    bcx = align.bcx;
979 980 981 982 983 984 985 986 987 988 989 990 991 992

    // 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);

    assert (n_params == std::vec::len::<uint>(tys.params));
    assert (n_params == std::vec::len::<ValueRef>(tys.descs));

    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.
M
Marijn Haverbeke 已提交
993
    if escapes {
994
        Store(bcx, root, GEPi(bcx, llparamtydescs, [0, 0]));
995
        i += 1;
996 997 998
    }

    for td: ValueRef in tys.descs {
999
        Store(bcx, td, GEPi(bcx, llparamtydescs, [0, i]));
1000 1001 1002 1003
        i += 1;
    }

    let llfirstparam =
1004
        PointerCast(bcx, llparamtydescs,
B
Brian Anderson 已提交
1005
                    T_ptr(T_ptr(bcx_ccx(bcx).tydesc_type)));
1006

P
Patrick Walton 已提交
1007 1008
    // The top bit indicates whether this type descriptor describes an object
    // (0) or a function (1).
1009 1010
    let obj_params;
    alt storage {
B
Brian Anderson 已提交
1011 1012 1013
      tps_normal. { obj_params = 0u; }
      tps_obj(np) { obj_params = np; }
      tps_fn(np) { obj_params = 0x80000000u | np; }
1014 1015 1016 1017
    }

    let v;
    if escapes {
M
Marijn Haverbeke 已提交
1018
        let td_val =
1019
            Call(bcx, bcx_ccx(bcx).upcalls.get_type_desc,
B
Brian Anderson 已提交
1020 1021 1022
                 [bcx.fcx.lltaskptr, C_null(T_ptr(T_nil())), sz.val,
                  align.val, C_uint(1u + n_params), llfirstparam,
                  C_uint(obj_params)]);
1023
        v = td_val;
1024
    } else {
B
Brian Anderson 已提交
1025 1026
        v =
            trans_stack_local_derived_tydesc(bcx, sz.val, align.val, root,
1027 1028
                                             llfirstparam, n_params,
                                             obj_params);
1029
    }
M
Marijn Haverbeke 已提交
1030
    bcx.fcx.derived_tydescs.insert(t, {lltydesc: v, escapes: escapes});
1031
    ret rslt(cx, v);
1032 1033
}

B
Brian Anderson 已提交
1034
type get_tydesc_result = {kind: tydesc_kind, result: result};
1035

1036
fn get_tydesc(cx: @block_ctxt, orig_t: ty::t, escapes: bool,
1037 1038
              storage: ty_param_storage, &static_ti: option::t<@tydesc_info>)
   -> get_tydesc_result {
1039

M
Marijn Haverbeke 已提交
1040
    let t = ty::strip_cname(bcx_tcx(cx), orig_t);
1041

L
Lindsey Kuper 已提交
1042
    // Is the supplied type a type param? If so, return the passed-in tydesc.
M
Marijn Haverbeke 已提交
1043
    alt ty::type_param(bcx_tcx(cx), t) {
1044
      some(id) {
1045
        if id < vec::len(cx.fcx.lltydescs) {
B
Brian Anderson 已提交
1046 1047
            ret {kind: tk_param, result: rslt(cx, cx.fcx.lltydescs[id])};
        } else {
B
Brian Anderson 已提交
1048 1049 1050 1051 1052 1053
            bcx_tcx(cx).sess.span_bug(cx.sp,
                                      "Unbound typaram in get_tydesc: " +
                                          "orig_t = " +
                                          ty_to_str(bcx_tcx(cx), orig_t) +
                                          " ty_param = " +
                                          std::uint::str(id));
1054 1055
        }
      }
M
Marijn Haverbeke 已提交
1056
      none. {/* fall through */ }
1057
    }
1058

L
Lindsey Kuper 已提交
1059
    // Does it contain a type param? If so, generate a derived tydesc.
M
Marijn Haverbeke 已提交
1060
    if ty::type_contains_params(bcx_tcx(cx), t) {
B
Brian Anderson 已提交
1061
        ret {kind: tk_derived,
1062
             result: get_derived_tydesc(cx, t, escapes, storage, static_ti)};
1063
    }
L
Lindsey Kuper 已提交
1064
    // Otherwise, generate a tydesc if necessary, and return it.
1065
    let info = get_static_tydesc(cx, t, [], false);
1066
    static_ti = some::<@tydesc_info>(info);
B
Brian Anderson 已提交
1067
    ret {kind: tk_static, result: rslt(cx, info.tydesc)};
1068 1069
}

1070 1071
fn get_static_tydesc(cx: @block_ctxt, orig_t: ty::t, ty_params: [uint],
                     is_obj_body: bool) -> @tydesc_info {
M
Marijn Haverbeke 已提交
1072
    let t = ty::strip_cname(bcx_tcx(cx), orig_t);
1073

M
Marijn Haverbeke 已提交
1074 1075 1076 1077 1078

    alt bcx_ccx(cx).tydescs.find(t) {
      some(info) { ret info; }
      none. {
        bcx_ccx(cx).stats.n_static_tydescs += 1u;
1079 1080
        let info = declare_tydesc(cx.fcx.lcx, cx.sp, t, ty_params,
                                  is_obj_body);
M
Marijn Haverbeke 已提交
1081 1082 1083
        bcx_ccx(cx).tydescs.insert(t, info);
        ret info;
      }
1084
    }
1085 1086
}

M
Marijn Haverbeke 已提交
1087
fn set_no_inline(f: ValueRef) {
1088 1089
    llvm::LLVMAddFunctionAttr(f,
                              lib::llvm::LLVMNoInlineAttribute as
1090 1091
                                  lib::llvm::llvm::Attribute,
                              0u);
1092 1093
}

L
Lindsey Kuper 已提交
1094 1095
// Tell LLVM to emit the information necessary to unwind the stack for the
// function f.
M
Marijn Haverbeke 已提交
1096
fn set_uwtable(f: ValueRef) {
1097 1098
    llvm::LLVMAddFunctionAttr(f,
                              lib::llvm::LLVMUWTableAttribute as
1099 1100
                                  lib::llvm::llvm::Attribute,
                              0u);
1101 1102
}

M
Marijn Haverbeke 已提交
1103
fn set_always_inline(f: ValueRef) {
1104 1105
    llvm::LLVMAddFunctionAttr(f,
                              lib::llvm::LLVMAlwaysInlineAttribute as
1106 1107 1108 1109 1110 1111 1112
                                  lib::llvm::llvm::Attribute,
                              0u);
}

fn set_custom_stack_growth_fn(f: ValueRef) {
    // TODO: Remove this hack to work around the lack of u64 in the FFI.
    llvm::LLVMAddFunctionAttr(f, 0 as lib::llvm::llvm::Attribute, 1u);
1113 1114
}

1115
fn set_glue_inlining(cx: @local_ctxt, f: ValueRef, t: ty::t) {
M
Marijn Haverbeke 已提交
1116
    if ty::type_is_structural(cx.ccx.tcx, t) {
1117
        set_no_inline(f);
1118
    } else { set_always_inline(f); }
1119 1120 1121
}


1122
// Generates the declaration for (but doesn't emit) a type descriptor.
1123 1124
fn declare_tydesc(cx: @local_ctxt, sp: span, t: ty::t, ty_params: [uint],
                  is_obj_body: bool) ->
1125
   @tydesc_info {
B
Brian Anderson 已提交
1126
    log "+++ declare_tydesc " + ty_to_str(cx.ccx.tcx, t);
M
Marijn Haverbeke 已提交
1127 1128 1129
    let ccx = cx.ccx;
    let llsize;
    let llalign;
1130
    if check type_has_static_size(ccx, t) {
M
Marijn Haverbeke 已提交
1131
        let llty = type_of(ccx, sp, t);
1132 1133 1134 1135 1136
        llsize = llsize_of(llty);
        llalign = llalign_of(llty);
    } else {
        // These will be overwritten as the derived tydesc is generated, so
        // we create placeholder values.
1137

1138 1139 1140
        llsize = C_int(0);
        llalign = C_int(0);
    }
M
Marijn Haverbeke 已提交
1141 1142
    let name;
    if cx.ccx.sess.get_opts().debuginfo {
B
Brian Anderson 已提交
1143
        name = mangle_internal_name_by_type_only(cx.ccx, t, "tydesc");
1144
        name = sanitize(name);
B
Brian Anderson 已提交
1145 1146 1147 1148 1149 1150
    } 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)
                    });
M
Marijn Haverbeke 已提交
1151 1152 1153 1154 1155
    let info =
        @{ty: t,
          tydesc: gvar,
          size: llsize,
          align: llalign,
1156
          mutable take_glue: none::<ValueRef>,
1157 1158 1159
          mutable drop_glue: none::<ValueRef>,
          mutable free_glue: none::<ValueRef>,
          mutable cmp_glue: none::<ValueRef>,
1160 1161
          ty_params: ty_params,
          is_obj_body: is_obj_body};
B
Brian Anderson 已提交
1162
    log "--- declare_tydesc " + ty_to_str(cx.ccx.tcx, t);
1163
    ret info;
1164 1165
}

1166
tag glue_helper {
1167 1168
    default_helper(fn(@block_ctxt, ValueRef, ty::t));
    copy_helper(fn(@block_ctxt, ValueRef, ValueRef, ty::t));
1169
}
1170

1171 1172
fn declare_generic_glue(cx: @local_ctxt, t: ty::t, llfnty: TypeRef, name: str)
   -> ValueRef {
1173
    let name = name;
M
Marijn Haverbeke 已提交
1174 1175
    let fn_nm;
    if cx.ccx.sess.get_opts().debuginfo {
B
Brian Anderson 已提交
1176
        fn_nm = mangle_internal_name_by_type_only(cx.ccx, t, "glue_" + name);
1177
        fn_nm = sanitize(fn_nm);
B
Brian Anderson 已提交
1178
    } else { fn_nm = mangle_internal_name_by_seq(cx.ccx, "glue_" + name); }
1179
    let llfn = decl_cdecl_fn(cx.ccx.llmod, fn_nm, llfnty);
1180
    set_glue_inlining(cx, llfn, t);
1181
    ret llfn;
1182
}
1183

1184
// FIXME: was this causing the leak?
1185 1186 1187
fn make_generic_glue_inner(cx: @local_ctxt, sp: span, t: ty::t,
                           llfn: ValueRef, helper: glue_helper,
                           ty_params: [uint]) -> ValueRef {
M
Marijn Haverbeke 已提交
1188
    let fcx = new_fn_ctxt(cx, sp, llfn);
1189 1190
    llvm::LLVMSetLinkage(llfn,
                         lib::llvm::LLVMInternalLinkage as llvm::Linkage);
1191
    cx.ccx.stats.n_glues_created += 1u;
1192 1193 1194 1195
    // 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.
1196

1197
    let ccx = cx.ccx;
1198 1199 1200 1201
    let llty =
        if check type_has_static_size(ccx, t) {
            T_ptr(type_of(ccx, sp, t))
        } else { T_ptr(T_i8()) };
1202

1203
    let ty_param_count = std::vec::len::<uint>(ty_params);
M
Marijn Haverbeke 已提交
1204
    let lltyparams = llvm::LLVMGetParam(llfn, 3u);
1205
    let load_env_bcx = new_raw_block_ctxt(fcx, fcx.llloadenv);
B
Brian Anderson 已提交
1206
    let lltydescs = [mutable];
M
Marijn Haverbeke 已提交
1207 1208
    let p = 0u;
    while p < ty_param_count {
1209 1210
        let llparam = GEP(load_env_bcx, lltyparams, [C_int(p as int)]);
        llparam = Load(load_env_bcx, llparam);
B
Brian Anderson 已提交
1211
        std::vec::grow_set(lltydescs, ty_params[p], 0 as ValueRef, llparam);
1212 1213
        p += 1u;
    }
1214

1215
    // FIXME: Implement some kind of freeze operation in the standard library.
B
Brian Anderson 已提交
1216 1217
    let lltydescs_frozen = [];
    for lltydesc: ValueRef in lltydescs { lltydescs_frozen += [lltydesc]; }
1218 1219
    fcx.lltydescs = lltydescs_frozen;

M
Marijn Haverbeke 已提交
1220 1221 1222
    let bcx = new_top_block_ctxt(fcx);
    let lltop = bcx.llbb;
    let llrawptr0 = llvm::LLVMGetParam(llfn, 4u);
1223
    let llval0 = BitCast(bcx, llrawptr0, llty);
1224
    alt helper {
B
Brian Anderson 已提交
1225
      default_helper(helper) { helper(bcx, llval0, t); }
1226
      copy_helper(helper) {
M
Marijn Haverbeke 已提交
1227
        let llrawptr1 = llvm::LLVMGetParam(llfn, 5u);
1228
        let llval1 = BitCast(bcx, llrawptr1, llty);
1229 1230 1231
        helper(bcx, llval0, llval1, t);
      }
    }
1232
    finish_fn(fcx, lltop);
1233 1234 1235
    ret llfn;
}

1236 1237
fn make_generic_glue(cx: @local_ctxt, sp: span, t: ty::t, llfn: ValueRef,
                     helper: glue_helper, ty_params: [uint], name: str) ->
B
Brian Anderson 已提交
1238
   ValueRef {
1239 1240 1241 1242
    if !cx.ccx.sess.get_opts().stats {
        ret make_generic_glue_inner(cx, sp, t, llfn, helper, ty_params);
    }

M
Marijn Haverbeke 已提交
1243 1244 1245
    let start = time::get_time();
    let llval = make_generic_glue_inner(cx, sp, t, llfn, helper, ty_params);
    let end = time::get_time();
B
Brian Anderson 已提交
1246
    log_fn_time(cx.ccx, "glue " + name + " " + ty_to_short_str(cx.ccx.tcx, t),
1247 1248 1249 1250
                start, end);
    ret llval;
}

1251
fn emit_tydescs(ccx: @crate_ctxt) {
1252
    for each pair: @{key: ty::t, val: @tydesc_info} in ccx.tydescs.items() {
M
Marijn Haverbeke 已提交
1253 1254 1255
        let glue_fn_ty = T_ptr(T_glue_fn(*ccx));
        let cmp_fn_ty = T_ptr(T_cmp_glue_fn(*ccx));
        let ti = pair.val;
1256
        let take_glue =
1257
            alt ti.take_glue {
M
Marijn Haverbeke 已提交
1258 1259
              none. { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
              some(v) { ccx.stats.n_real_glues += 1u; v }
1260
            };
M
Marijn Haverbeke 已提交
1261
        let drop_glue =
1262
            alt ti.drop_glue {
M
Marijn Haverbeke 已提交
1263 1264
              none. { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
              some(v) { ccx.stats.n_real_glues += 1u; v }
1265
            };
M
Marijn Haverbeke 已提交
1266
        let free_glue =
1267
            alt ti.free_glue {
M
Marijn Haverbeke 已提交
1268 1269
              none. { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
              some(v) { ccx.stats.n_real_glues += 1u; v }
1270
            };
M
Marijn Haverbeke 已提交
1271
        let cmp_glue =
1272
            alt ti.cmp_glue {
M
Marijn Haverbeke 已提交
1273 1274
              none. { ccx.stats.n_null_glues += 1u; C_null(cmp_fn_ty) }
              some(v) { ccx.stats.n_real_glues += 1u; v }
1275
            };
P
Patrick Walton 已提交
1276

1277 1278
        let shape = shape::shape_of(ccx, pair.key, ti.ty_params,
                                    ti.is_obj_body);
P
Patrick Walton 已提交
1279 1280 1281 1282 1283
        let shape_tables =
            llvm::LLVMConstPointerCast(ccx.shape_cx.llshapetables,
                                       T_ptr(T_i8()));

        let tydesc =
1284
            C_named_struct(ccx.tydesc_type,
B
Brian Anderson 已提交
1285 1286 1287
                           [C_null(T_ptr(T_ptr(ccx.tydesc_type))),
                            ti.size, // size
                            ti.align, // align
1288
                            take_glue, // take_glue
B
Brian Anderson 已提交
1289 1290
                            drop_glue, // drop_glue
                            free_glue, // free_glue
M
Marijn Haverbeke 已提交
1291
                            C_null(T_ptr(T_i8())), // unused
B
Brian Anderson 已提交
1292 1293
                            C_null(glue_fn_ty), // sever_glue
                            C_null(glue_fn_ty), // mark_glue
1294
                            C_null(glue_fn_ty), // unused
B
Brian Anderson 已提交
1295 1296 1297
                            cmp_glue, // cmp_glue
                            C_shape(ccx, shape), // shape
                            shape_tables, // shape_tables
B
Brian Anderson 已提交
1298
                            C_int(0), // n_params
1299
                            C_int(0)]); // n_obj_params
M
Marijn Haverbeke 已提交
1300 1301

        let gvar = ti.tydesc;
1302 1303
        llvm::LLVMSetInitializer(gvar, tydesc);
        llvm::LLVMSetGlobalConstant(gvar, True);
1304 1305
        llvm::LLVMSetLinkage(gvar,
                             lib::llvm::LLVMInternalLinkage as llvm::Linkage);
1306 1307 1308
    }
}

1309
fn make_take_glue(cx: @block_ctxt, v: ValueRef, t: ty::t) {
M
Marijn Haverbeke 已提交
1310
    let bcx = cx;
1311
    // NB: v is an *alias* of type t here, not a direct value.
M
Marijn Haverbeke 已提交
1312
    if ty::type_is_boxed(bcx_tcx(bcx), t) {
1313
        bcx = incr_refcnt_of_boxed(bcx, Load(bcx, v));
B
Brian Anderson 已提交
1314 1315 1316
    } else if ty::type_is_unique_box(bcx_tcx(bcx), t) {
        check trans_uniq::type_is_unique_box(bcx, t);
        bcx = trans_uniq::duplicate(bcx, v, t);
M
Marijn Haverbeke 已提交
1317
    } else if ty::type_is_structural(bcx_tcx(bcx), t) {
1318
        bcx = iter_structural_ty(bcx, v, t, take_ty);
1319 1320 1321
    } else if ty::type_is_vec(bcx_tcx(bcx), t) {
        bcx = tvec::duplicate(bcx, v);
        bcx = tvec::iter_vec(bcx, v, t, take_ty);
M
Marijn Haverbeke 已提交
1322
    }
1323

1324
    build_return(bcx);
1325 1326
}

1327
fn incr_refcnt_of_boxed(cx: @block_ctxt, box_ptr: ValueRef) -> @block_ctxt {
M
Marijn Haverbeke 已提交
1328
    let rc_ptr =
1329 1330
        GEP(cx, box_ptr, [C_int(0), C_int(abi::box_rc_field_refcnt)]);
    let rc = Load(cx, rc_ptr);
1331 1332 1333
    rc = Add(cx, rc, C_int(1));
    Store(cx, rc, rc_ptr);
    ret cx;
1334 1335
}

1336
fn make_free_glue(bcx: @block_ctxt, v0: ValueRef, t: ty::t) {
1337
    // NB: v is an *alias* of type t here, not a direct value.
B
Brian Anderson 已提交
1338 1339 1340 1341 1342 1343 1344 1345 1346 1347
    let bcx =
        alt ty::struct(bcx_tcx(bcx), t) {
          ty::ty_box(body_mt) {
            let v = Load(bcx, v0);
            let body = GEP(bcx, v, [C_int(0), C_int(abi::box_rc_field_body)]);
            let bcx = drop_ty(bcx, body, body_mt.ty);
            if !bcx_ccx(bcx).sess.get_opts().do_gc {
                trans_non_gc_free(bcx, v)
            } else { bcx }
          }
1348
          ty::ty_uniq(content_mt) {
1349
            check trans_uniq::type_is_unique_box(bcx, t);
1350
            trans_uniq::make_free_glue(bcx, v0, t)
1351
          }
B
Brian Anderson 已提交
1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390
          ty::ty_obj(_) {
            // Call through the obj's own fields-drop glue first.
            // Then free the body.
            let box_cell =
                GEP(bcx, v0, [C_int(0), C_int(abi::obj_field_box)]);
            let b = Load(bcx, box_cell);
            let ccx = bcx_ccx(bcx);
            let llbox_ty = T_opaque_obj_ptr(*ccx);
            b = PointerCast(bcx, b, llbox_ty);
            let body = GEP(bcx, b, [C_int(0), C_int(abi::box_rc_field_body)]);
            let tydescptr =
                GEP(bcx, body, [C_int(0), C_int(abi::obj_body_elt_tydesc)]);
            let tydesc = Load(bcx, tydescptr);
            let ti = none;
            call_tydesc_glue_full(bcx, body, tydesc,
                                  abi::tydesc_field_drop_glue, ti);
            if !bcx_ccx(bcx).sess.get_opts().do_gc {
                trans_non_gc_free(bcx, b)
            } else { bcx }
          }
          ty::ty_fn(_, _, _, _, _) {
            // Call through the closure's own fields-drop glue first.
            // Then free the body.
            let box_cell = GEP(bcx, v0, [C_int(0), C_int(abi::fn_field_box)]);
            let v = Load(bcx, box_cell);
            let body = GEP(bcx, v, [C_int(0), C_int(abi::box_rc_field_body)]);
            let bindings =
                GEP(bcx, body, [C_int(0), C_int(abi::closure_elt_bindings)]);
            let tydescptr =
                GEP(bcx, body, [C_int(0), C_int(abi::closure_elt_tydesc)]);
            let ti = none;
            call_tydesc_glue_full(bcx, bindings, Load(bcx, tydescptr),
                                  abi::tydesc_field_drop_glue, ti);
            if !bcx_ccx(bcx).sess.get_opts().do_gc {
                trans_non_gc_free(bcx, v)
            } else { bcx }
          }
          _ { bcx }
        };
1391

1392
    build_return(bcx);
1393 1394
}

1395
fn make_drop_glue(bcx: @block_ctxt, v0: ValueRef, t: ty::t) {
1396
    // NB: v0 is an *alias* of type t here, not a direct value.
1397
    let ccx = bcx_ccx(bcx);
1398 1399 1400 1401 1402 1403
    let bcx =
        alt ty::struct(ccx.tcx, t) {
          ty::ty_vec(_) { tvec::make_drop_glue(bcx, v0, t) }
          ty::ty_str. { tvec::make_drop_glue(bcx, v0, t) }
          ty::ty_box(_) { decr_refcnt_maybe_free(bcx, v0, v0, t) }
          ty::ty_uniq(_) {
1404
            free_ty(bcx, v0, t)
1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424
          }
          ty::ty_obj(_) {
            let box_cell =
                GEP(bcx, v0, [C_int(0), C_int(abi::obj_field_box)]);
            decr_refcnt_maybe_free(bcx, box_cell, v0, t)
          }
          ty::ty_res(did, inner, tps) {
            trans_res_drop(bcx, v0, did, inner, tps)
          }
          ty::ty_fn(_, _, _, _, _) {
            let box_cell = GEP(bcx, v0, [C_int(0), C_int(abi::fn_field_box)]);
            decr_refcnt_maybe_free(bcx, box_cell, v0, t)
          }
          _ {
            if ty::type_has_pointers(ccx.tcx, t) &&
                   ty::type_is_structural(ccx.tcx, t) {
                iter_structural_ty(bcx, v0, t, drop_ty)
            } else { bcx }
          }
        };
1425
    build_return(bcx);
1426 1427
}

1428 1429
fn trans_res_drop(cx: @block_ctxt, rs: ValueRef, did: ast::def_id,
                  inner_t: ty::t, tps: [ty::t]) -> @block_ctxt {
M
Marijn Haverbeke 已提交
1430 1431
    let ccx = bcx_ccx(cx);
    let inner_t_s = ty::substitute_type_params(ccx.tcx, tps, inner_t);
B
Brian Anderson 已提交
1432
    let tup_ty = ty::mk_tup(ccx.tcx, [ty::mk_int(ccx.tcx), inner_t_s]);
B
Brian Anderson 已提交
1433 1434
    let drop_cx = new_sub_block_ctxt(cx, "drop res");
    let next_cx = new_sub_block_ctxt(cx, "next");
1435

1436 1437
    // Silly check
    check type_is_tup_like(cx, tup_ty);
B
Brian Anderson 已提交
1438
    let drop_flag = GEP_tup_like(cx, tup_ty, rs, [0, 0]);
1439
    cx = drop_flag.bcx;
1440 1441
    let null_test = IsNull(cx, Load(cx, drop_flag.val));
    CondBr(cx, null_test, next_cx.llbb, drop_cx.llbb);
1442
    cx = drop_cx;
1443

1444
    check type_is_tup_like(cx, tup_ty);
B
Brian Anderson 已提交
1445
    let val = GEP_tup_like(cx, tup_ty, rs, [0, 1]);
1446
    cx = val.bcx;
1447
    // Find and call the actual destructor.
1448 1449
    let dtor_addr = trans_common::get_res_dtor(ccx, cx.sp, did, inner_t);
    let args = [cx.fcx.llretptr, cx.fcx.lltaskptr, null_env_ptr(cx)];
B
Brian Anderson 已提交
1450
    for tp: ty::t in tps {
1451
        let ti: option::t<@tydesc_info> = none;
1452
        let td = get_tydesc(cx, tp, false, tps_normal, ti).result;
B
Brian Anderson 已提交
1453
        args += [td.val];
1454 1455 1456 1457 1458
        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.
1459
    let val_llty = lib::llvm::fn_ty_param_tys
1460 1461
        (llvm::LLVMGetElementType
         (llvm::LLVMTypeOf(dtor_addr)))[std::vec::len(args)];
1462
    let val_cast = BitCast(cx, val.val, val_llty);
1463
    Call(cx, dtor_addr, args + [val_cast]);
1464

1465
    cx = drop_ty(cx, val.val, inner_t_s);
1466 1467
    Store(cx, C_int(0), drop_flag.val);
    Br(cx, next_cx.llbb);
1468
    ret next_cx;
1469 1470
}

1471
fn decr_refcnt_maybe_free(cx: @block_ctxt, box_ptr_alias: ValueRef,
1472
                          full_alias: ValueRef, t: ty::t) -> @block_ctxt {
M
Marijn Haverbeke 已提交
1473
    let ccx = bcx_ccx(cx);
B
Brian Anderson 已提交
1474 1475 1476
    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");
1477
    let box_ptr = Load(cx, box_ptr_alias);
M
Marijn Haverbeke 已提交
1478
    let llbox_ty = T_opaque_obj_ptr(*ccx);
1479 1480
    box_ptr = PointerCast(cx, box_ptr, llbox_ty);
    let null_test = IsNull(cx, box_ptr);
1481
    CondBr(cx, null_test, next_cx.llbb, rc_adj_cx.llbb);
M
Marijn Haverbeke 已提交
1482
    let rc_ptr =
B
Brian Anderson 已提交
1483
        GEP(rc_adj_cx, box_ptr, [C_int(0), C_int(abi::box_rc_field_refcnt)]);
1484
    let rc = Load(rc_adj_cx, rc_ptr);
1485 1486 1487 1488
    rc = Sub(rc_adj_cx, rc, C_int(1));
    Store(rc_adj_cx, rc, rc_ptr);
    let zero_test = ICmp(rc_adj_cx, lib::llvm::LLVMIntEQ, C_int(0), rc);
    CondBr(rc_adj_cx, zero_test, free_cx.llbb, next_cx.llbb);
1489 1490 1491
    let free_cx = free_ty(free_cx, full_alias, t);
    Br(free_cx, next_cx.llbb);
    ret next_cx;
1492 1493
}

1494

1495
// Structural comparison: a rather involved form of glue.
1496
fn maybe_name_value(cx: @crate_ctxt, v: ValueRef, s: str) {
M
Marijn Haverbeke 已提交
1497
    if cx.sess.get_opts().save_temps {
B
Brian Anderson 已提交
1498
        let _: () = str::as_buf(s, {|buf| llvm::LLVMSetValueName(v, buf) });
1499 1500 1501
    }
}

1502

L
Lindsey Kuper 已提交
1503
// Used only for creating scalar comparison glue.
1504
tag scalar_type { nil_type; signed_int; unsigned_int; floating_point; }
1505

1506

M
Marijn Haverbeke 已提交
1507
fn compare_scalar_types(cx: @block_ctxt, lhs: ValueRef, rhs: ValueRef,
1508
                        t: ty::t, llop: ValueRef) -> result {
M
Marijn Haverbeke 已提交
1509 1510 1511 1512
    let f = bind compare_scalar_values(cx, lhs, rhs, _, llop);

    alt ty::struct(bcx_tcx(cx), t) {
      ty::ty_nil. { ret f(nil_type); }
B
Brian Anderson 已提交
1513 1514 1515
      ty::ty_bool. | ty::ty_uint. | ty::ty_ptr(_) | ty::ty_char. {
        ret f(unsigned_int);
      }
M
Marijn Haverbeke 已提交
1516 1517 1518 1519 1520 1521
      ty::ty_int. { ret f(signed_int); }
      ty::ty_float. { ret f(floating_point); }
      ty::ty_machine(_) {
        if ty::type_is_fp(bcx_tcx(cx), t) {
            // Floating point machine types
            ret f(floating_point);
B
Brian Anderson 已提交
1522
        } else if ty::type_is_signed(bcx_tcx(cx), t) {
M
Marijn Haverbeke 已提交
1523 1524 1525 1526
            // Signed, integral machine types
            ret f(signed_int);
        } else {
            // Unsigned, integral machine types
1527
            ret f(unsigned_int);
1528
        }
M
Marijn Haverbeke 已提交
1529 1530
      }
      ty::ty_type. {
1531 1532 1533
        ret rslt(trans_fail(cx, none,
                            "attempt to compare values of type type"),
                 C_nil());
M
Marijn Haverbeke 已提交
1534 1535
      }
      ty::ty_native(_) {
1536 1537 1538
        let cx = trans_fail(cx, none::<span>,
                            "attempt to compare values of type native");
        ret rslt(cx, C_nil());
M
Marijn Haverbeke 已提交
1539 1540 1541
      }
      _ {
        // Should never get here, because t is scalar.
B
Brian Anderson 已提交
1542
        bcx_ccx(cx).sess.bug("non-scalar type passed to \
1543
                                 compare_scalar_types");
M
Marijn Haverbeke 已提交
1544
      }
1545 1546 1547
    }
}

1548

1549
// A helper function to do the actual comparison of scalar values.
1550
fn compare_scalar_values(cx: @block_ctxt, lhs: ValueRef, rhs: ValueRef,
M
Marijn Haverbeke 已提交
1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577
                         nt: scalar_type, llop: ValueRef) -> result {
    let eq_cmp;
    let lt_cmp;
    let le_cmp;
    alt nt {
      nil_type. {
        // We don't need to do actual comparisons for nil.
        // () == () holds but () < () does not.
        eq_cmp = 1u;
        lt_cmp = 0u;
        le_cmp = 1u;
      }
      floating_point. {
        eq_cmp = lib::llvm::LLVMRealUEQ;
        lt_cmp = lib::llvm::LLVMRealULT;
        le_cmp = lib::llvm::LLVMRealULE;
      }
      signed_int. {
        eq_cmp = lib::llvm::LLVMIntEQ;
        lt_cmp = lib::llvm::LLVMIntSLT;
        le_cmp = lib::llvm::LLVMIntSLE;
      }
      unsigned_int. {
        eq_cmp = lib::llvm::LLVMIntEQ;
        lt_cmp = lib::llvm::LLVMIntULT;
        le_cmp = lib::llvm::LLVMIntULE;
      }
1578 1579 1580
    }
    // FIXME: This wouldn't be necessary if we could bind methods off of
    // objects and therefore abstract over FCmp and ICmp (issue #435).  Then
1581
    // we could just write, e.g., "cmp_fn = bind FCmp(cx, _, _, _);" in
1582 1583
    // the above, and "auto eq_result = cmp_fn(eq_cmp, lhs, rhs);" in the
    // below.
1584

1585
    fn generic_cmp(cx: @block_ctxt, nt: scalar_type, op: uint, lhs: ValueRef,
M
Marijn Haverbeke 已提交
1586 1587 1588
                   rhs: ValueRef) -> ValueRef {
        let r: ValueRef;
        if nt == nil_type {
1589
            r = C_bool(op != 0u);
B
Brian Anderson 已提交
1590
        } else if nt == floating_point {
1591 1592
            r = FCmp(cx, op, lhs, rhs);
        } else { r = ICmp(cx, op, lhs, rhs); }
1593
        ret r;
1594
    }
B
Brian Anderson 已提交
1595 1596
    let last_cx = new_sub_block_ctxt(cx, "last");
    let eq_cx = new_sub_block_ctxt(cx, "eq");
M
Marijn Haverbeke 已提交
1597
    let eq_result = generic_cmp(eq_cx, nt, eq_cmp, lhs, rhs);
1598
    Br(eq_cx, last_cx.llbb);
B
Brian Anderson 已提交
1599
    let lt_cx = new_sub_block_ctxt(cx, "lt");
M
Marijn Haverbeke 已提交
1600
    let lt_result = generic_cmp(lt_cx, nt, lt_cmp, lhs, rhs);
1601
    Br(lt_cx, last_cx.llbb);
B
Brian Anderson 已提交
1602
    let le_cx = new_sub_block_ctxt(cx, "le");
M
Marijn Haverbeke 已提交
1603
    let le_result = generic_cmp(le_cx, nt, le_cmp, lhs, rhs);
1604
    Br(le_cx, last_cx.llbb);
B
Brian Anderson 已提交
1605
    let unreach_cx = new_sub_block_ctxt(cx, "unreach");
1606 1607
    Unreachable(unreach_cx);
    let llswitch = Switch(cx, llop, unreach_cx.llbb, 3u);
1608 1609 1610
    AddCase(llswitch, C_u8(abi::cmp_glue_op_eq), eq_cx.llbb);
    AddCase(llswitch, C_u8(abi::cmp_glue_op_lt), lt_cx.llbb);
    AddCase(llswitch, C_u8(abi::cmp_glue_op_le), le_cx.llbb);
M
Marijn Haverbeke 已提交
1611
    let last_result =
1612
        Phi(last_cx, T_i1(), [eq_result, lt_result, le_result],
B
Brian Anderson 已提交
1613
            [eq_cx.llbb, lt_cx.llbb, le_cx.llbb]);
1614
    ret rslt(last_cx, last_result);
1615 1616
}

1617 1618
type val_pair_fn = fn(@block_ctxt, ValueRef, ValueRef) -> @block_ctxt;
type val_and_ty_fn = fn(@block_ctxt, ValueRef, ty::t) -> @block_ctxt;
1619

1620
fn load_inbounds(cx: @block_ctxt, p: ValueRef, idxs: [ValueRef]) -> ValueRef {
1621
    ret Load(cx, InBoundsGEP(cx, p, idxs));
G
Graydon Hoare 已提交
1622 1623
}

1624 1625
fn store_inbounds(cx: @block_ctxt, v: ValueRef, p: ValueRef,
                  idxs: [ValueRef]) {
1626
    Store(cx, v, InBoundsGEP(cx, p, idxs));
G
Graydon Hoare 已提交
1627 1628
}

1629
// Iterates through the elements of a structural type.
1630
fn iter_structural_ty(cx: @block_ctxt, av: ValueRef, t: ty::t,
1631 1632
                      f: val_and_ty_fn) -> @block_ctxt {
    fn iter_boxpp(cx: @block_ctxt, box_cell: ValueRef, f: val_and_ty_fn) ->
B
Brian Anderson 已提交
1633
       @block_ctxt {
1634
        let box_ptr = Load(cx, box_cell);
M
Marijn Haverbeke 已提交
1635 1636
        let tnil = ty::mk_nil(bcx_tcx(cx));
        let tbox = ty::mk_imm_box(bcx_tcx(cx), tnil);
B
Brian Anderson 已提交
1637 1638
        let inner_cx = new_sub_block_ctxt(cx, "iter box");
        let next_cx = new_sub_block_ctxt(cx, "next");
1639 1640
        let null_test = IsNull(cx, box_ptr);
        CondBr(cx, null_test, next_cx.llbb, inner_cx.llbb);
1641 1642 1643
        let inner_cx = f(inner_cx, box_cell, tbox);
        Br(inner_cx, next_cx.llbb);
        ret next_cx;
1644
    }
1645

1646
    fn iter_variant(cx: @block_ctxt, a_tup: ValueRef,
1647 1648
                    variant: ty::variant_info, tps: [ty::t], tid: ast::def_id,
                    f: val_and_ty_fn) -> @block_ctxt {
1649
        if std::vec::len::<ty::t>(variant.args) == 0u { ret cx; }
M
Marijn Haverbeke 已提交
1650 1651 1652 1653
        let fn_ty = variant.ctor_ty;
        let ccx = bcx_ccx(cx);
        alt ty::struct(ccx.tcx, fn_ty) {
          ty::ty_fn(_, args, _, _, _) {
1654
            let j = 0u;
T
Tim Chevalier 已提交
1655
            let v_id = variant.id;
1656
            for a: ty::arg in args {
B
Brian Anderson 已提交
1657
                check (valid_variant_index(j, cx, tid, v_id));
T
Tim Chevalier 已提交
1658
                let rslt = GEP_tag(cx, a_tup, tid, v_id, tps, j);
M
Marijn Haverbeke 已提交
1659 1660 1661
                let llfldp_a = rslt.val;
                cx = rslt.bcx;
                let ty_subst = ty::substitute_type_params(ccx.tcx, tps, a.ty);
1662
                cx = f(cx, llfldp_a, ty_subst);
1663
                j += 1u;
1664
            }
M
Marijn Haverbeke 已提交
1665
          }
1666
        }
1667
        ret cx;
1668
    }
1669

1670 1671 1672
    /*
    Typestate constraint that shows the unimpl case doesn't happen?
    */
M
Marijn Haverbeke 已提交
1673 1674 1675
    alt ty::struct(bcx_tcx(cx), t) {
      ty::ty_rec(fields) {
        let i: int = 0;
1676
        for fld: ty::field in fields {
1677 1678
            // Silly check
            check type_is_tup_like(cx, t);
B
Brian Anderson 已提交
1679
            let {bcx: bcx, val: llfld_a} = GEP_tup_like(cx, t, av, [0, i]);
1680
            cx = f(bcx, llfld_a, fld.mt.ty);
M
Marijn Haverbeke 已提交
1681
            i += 1;
1682
        }
M
Marijn Haverbeke 已提交
1683
      }
1684 1685 1686
      ty::ty_tup(args) {
        let i = 0;
        for arg in args {
1687 1688
            // Silly check
            check type_is_tup_like(cx, t);
B
Brian Anderson 已提交
1689
            let {bcx: bcx, val: llfld_a} = GEP_tup_like(cx, t, av, [0, i]);
1690
            cx = f(bcx, llfld_a, arg);
1691 1692 1693
            i += 1;
        }
      }
M
Marijn Haverbeke 已提交
1694
      ty::ty_res(_, inner, tps) {
1695 1696 1697
        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);
B
Brian Anderson 已提交
1698
        let tup_t = ty::mk_tup(tcx, [ty::mk_int(tcx), inner_t_s]);
1699 1700
        // Silly check
        check type_is_tup_like(cx, tup_t);
B
Brian Anderson 已提交
1701
        let {bcx: bcx, val: llfld_a} = GEP_tup_like(cx, tup_t, av, [0, 1]);
1702
        ret f(bcx, llfld_a, inner1);
M
Marijn Haverbeke 已提交
1703 1704 1705
      }
      ty::ty_tag(tid, tps) {
        let variants = ty::tag_variants(bcx_tcx(cx), tid);
B
Brian Anderson 已提交
1706
        let n_variants = std::vec::len(variants);
M
Marijn Haverbeke 已提交
1707 1708 1709

        // Cast the tags to types we can GEP into.
        if n_variants == 1u {
B
Brian Anderson 已提交
1710
            ret iter_variant(cx, av, variants[0], tps, tid, f);
M
Marijn Haverbeke 已提交
1711 1712 1713
        }

        let lltagty = T_opaque_tag_ptr(bcx_ccx(cx).tn);
1714 1715 1716 1717
        let av_tag = PointerCast(cx, av, lltagty);
        let lldiscrim_a_ptr = GEP(cx, av_tag, [C_int(0), C_int(0)]);
        let llunion_a_ptr = GEP(cx, av_tag, [C_int(0), C_int(1)]);
        let lldiscrim_a = Load(cx, lldiscrim_a_ptr);
M
Marijn Haverbeke 已提交
1718 1719 1720

        // NB: we must hit the discriminant first so that structural
        // comparison know not to proceed when the discriminants differ.
1721
        cx = f(cx, lldiscrim_a_ptr, ty::mk_int(bcx_tcx(cx)));
B
Brian Anderson 已提交
1722
        let unr_cx = new_sub_block_ctxt(cx, "tag-iter-unr");
1723
        Unreachable(unr_cx);
1724
        let llswitch = Switch(cx, lldiscrim_a, unr_cx.llbb, n_variants);
B
Brian Anderson 已提交
1725
        let next_cx = new_sub_block_ctxt(cx, "tag-iter-next");
M
Marijn Haverbeke 已提交
1726
        let i = 0u;
1727
        for variant: ty::variant_info in variants {
M
Marijn Haverbeke 已提交
1728
            let variant_cx =
B
Brian Anderson 已提交
1729 1730 1731
                new_sub_block_ctxt(cx,
                                   "tag-iter-variant-" +
                                       uint::to_str(i, 10u));
1732
            AddCase(llswitch, C_int(i as int), variant_cx.llbb);
B
Brian Anderson 已提交
1733 1734
            variant_cx =
                iter_variant(variant_cx, llunion_a_ptr, variant, tps, tid, f);
1735
            Br(variant_cx, next_cx.llbb);
M
Marijn Haverbeke 已提交
1736
            i += 1u;
1737
        }
1738
        ret next_cx;
M
Marijn Haverbeke 已提交
1739
      }
1740
      ty::ty_fn(_, _, _, _, _) | ty::ty_native_fn(_, _, _) {
B
Brian Anderson 已提交
1741
        let box_cell_a = GEP(cx, av, [C_int(0), C_int(abi::fn_field_box)]);
1742
        ret iter_boxpp(cx, box_cell_a, f);
M
Marijn Haverbeke 已提交
1743 1744
      }
      ty::ty_obj(_) {
B
Brian Anderson 已提交
1745
        let box_cell_a = GEP(cx, av, [C_int(0), C_int(abi::obj_field_box)]);
1746
        ret iter_boxpp(cx, box_cell_a, f);
M
Marijn Haverbeke 已提交
1747
      }
B
Brian Anderson 已提交
1748
      _ { bcx_ccx(cx).sess.unimpl("type in iter_structural_ty"); }
1749
    }
1750
    ret cx;
1751 1752
}

1753 1754
fn lazily_emit_all_tydesc_glue(cx: @block_ctxt,
                               static_ti: option::t<@tydesc_info>) {
1755
    lazily_emit_tydesc_glue(cx, abi::tydesc_field_take_glue, static_ti);
1756
    lazily_emit_tydesc_glue(cx, abi::tydesc_field_drop_glue, static_ti);
1757
    lazily_emit_tydesc_glue(cx, abi::tydesc_field_free_glue, static_ti);
1758 1759 1760
    lazily_emit_tydesc_glue(cx, abi::tydesc_field_cmp_glue, static_ti);
}

1761 1762
fn lazily_emit_all_generic_info_tydesc_glues(cx: @block_ctxt,
                                             gi: generic_info) {
1763
    for ti: option::t<@tydesc_info> in gi.static_tis {
1764 1765 1766 1767
        lazily_emit_all_tydesc_glue(cx, ti);
    }
}

1768 1769
fn lazily_emit_tydesc_glue(cx: @block_ctxt, field: int,
                           static_ti: option::t<@tydesc_info>) {
M
Marijn Haverbeke 已提交
1770 1771 1772
    alt static_ti {
      none. { }
      some(ti) {
1773
        if field == abi::tydesc_field_take_glue {
1774
            alt ti.take_glue {
M
Marijn Haverbeke 已提交
1775 1776
              some(_) { }
              none. {
1777
                log #fmt["+++ lazily_emit_tydesc_glue TAKE %s",
1778
                         ty_to_str(bcx_tcx(cx), ti.ty)];
M
Marijn Haverbeke 已提交
1779 1780 1781
                let lcx = cx.fcx.lcx;
                let glue_fn =
                    declare_generic_glue(lcx, ti.ty, T_glue_fn(*lcx.ccx),
B
Brian Anderson 已提交
1782
                                         "take");
1783
                ti.take_glue = some::<ValueRef>(glue_fn);
1784 1785
                make_generic_glue(lcx, cx.sp, ti.ty, glue_fn,
                                  default_helper(make_take_glue),
B
Brian Anderson 已提交
1786
                                  ti.ty_params, "take");
1787
                log #fmt["--- lazily_emit_tydesc_glue TAKE %s",
1788
                         ty_to_str(bcx_tcx(cx), ti.ty)];
M
Marijn Haverbeke 已提交
1789 1790
              }
            }
B
Brian Anderson 已提交
1791
        } else if field == abi::tydesc_field_drop_glue {
1792
            alt ti.drop_glue {
M
Marijn Haverbeke 已提交
1793 1794
              some(_) { }
              none. {
1795
                log #fmt["+++ lazily_emit_tydesc_glue DROP %s",
1796
                         ty_to_str(bcx_tcx(cx), ti.ty)];
M
Marijn Haverbeke 已提交
1797 1798 1799
                let lcx = cx.fcx.lcx;
                let glue_fn =
                    declare_generic_glue(lcx, ti.ty, T_glue_fn(*lcx.ccx),
B
Brian Anderson 已提交
1800
                                         "drop");
1801
                ti.drop_glue = some::<ValueRef>(glue_fn);
1802 1803
                make_generic_glue(lcx, cx.sp, ti.ty, glue_fn,
                                  default_helper(make_drop_glue),
B
Brian Anderson 已提交
1804
                                  ti.ty_params, "drop");
1805
                log #fmt["--- lazily_emit_tydesc_glue DROP %s",
1806
                         ty_to_str(bcx_tcx(cx), ti.ty)];
M
Marijn Haverbeke 已提交
1807 1808
              }
            }
B
Brian Anderson 已提交
1809
        } else if field == abi::tydesc_field_free_glue {
1810
            alt ti.free_glue {
M
Marijn Haverbeke 已提交
1811 1812
              some(_) { }
              none. {
1813
                log #fmt["+++ lazily_emit_tydesc_glue FREE %s",
1814
                         ty_to_str(bcx_tcx(cx), ti.ty)];
M
Marijn Haverbeke 已提交
1815 1816 1817
                let lcx = cx.fcx.lcx;
                let glue_fn =
                    declare_generic_glue(lcx, ti.ty, T_glue_fn(*lcx.ccx),
B
Brian Anderson 已提交
1818
                                         "free");
1819
                ti.free_glue = some::<ValueRef>(glue_fn);
1820 1821
                make_generic_glue(lcx, cx.sp, ti.ty, glue_fn,
                                  default_helper(make_free_glue),
B
Brian Anderson 已提交
1822
                                  ti.ty_params, "free");
1823
                log #fmt["--- lazily_emit_tydesc_glue FREE %s",
1824
                         ty_to_str(bcx_tcx(cx), ti.ty)];
M
Marijn Haverbeke 已提交
1825 1826
              }
            }
B
Brian Anderson 已提交
1827
        } else if field == abi::tydesc_field_cmp_glue {
1828
            alt ti.cmp_glue {
M
Marijn Haverbeke 已提交
1829 1830
              some(_) { }
              none. {
1831
                log #fmt["+++ lazily_emit_tydesc_glue CMP %s",
1832
                         ty_to_str(bcx_tcx(cx), ti.ty)];
1833
                ti.cmp_glue = some(bcx_ccx(cx).upcalls.cmp_type);
1834
                log #fmt["--- lazily_emit_tydesc_glue CMP %s",
1835
                         ty_to_str(bcx_tcx(cx), ti.ty)];
M
Marijn Haverbeke 已提交
1836
              }
1837 1838
            }
        }
M
Marijn Haverbeke 已提交
1839
      }
1840 1841 1842
    }
}

1843 1844
fn call_tydesc_glue_full(cx: @block_ctxt, v: ValueRef, tydesc: ValueRef,
                         field: int, static_ti: option::t<@tydesc_info>) {
1845
    lazily_emit_tydesc_glue(cx, field, static_ti);
1846

M
Marijn Haverbeke 已提交
1847 1848 1849 1850
    let static_glue_fn = none;
    alt static_ti {
      none. {/* no-op */ }
      some(sti) {
1851 1852
        if field == abi::tydesc_field_take_glue {
            static_glue_fn = sti.take_glue;
B
Brian Anderson 已提交
1853
        } else if field == abi::tydesc_field_drop_glue {
1854
            static_glue_fn = sti.drop_glue;
B
Brian Anderson 已提交
1855
        } else if field == abi::tydesc_field_free_glue {
1856 1857 1858 1859 1860
            static_glue_fn = sti.free_glue;
        }
      }
    }

1861
    let llrawptr = PointerCast(cx, v, T_ptr(T_i8()));
M
Marijn Haverbeke 已提交
1862
    let lltydescs =
B
Brian Anderson 已提交
1863
        GEP(cx, tydesc, [C_int(0), C_int(abi::tydesc_field_first_param)]);
1864
    lltydescs = Load(cx, lltydescs);
1865

M
Marijn Haverbeke 已提交
1866 1867 1868
    let llfn;
    alt static_glue_fn {
      none. {
1869 1870
        let llfnptr = GEP(cx, tydesc, [C_int(0), C_int(field)]);
        llfn = Load(cx, llfnptr);
1871
      }
M
Marijn Haverbeke 已提交
1872
      some(sgf) { llfn = sgf; }
1873 1874
    }

1875
    Call(cx, llfn,
B
Brian Anderson 已提交
1876 1877
         [C_null(T_ptr(T_nil())), cx.fcx.lltaskptr, C_null(T_ptr(T_nil())),
          lltydescs, llrawptr]);
1878 1879
}

1880
fn call_tydesc_glue(cx: @block_ctxt, v: ValueRef, t: ty::t, field: int) ->
B
Brian Anderson 已提交
1881
   @block_ctxt {
1882
    let ti: option::t<@tydesc_info> = none::<@tydesc_info>;
B
Brian Anderson 已提交
1883
    let {bcx: bcx, val: td} = get_tydesc(cx, t, false, tps_normal, ti).result;
1884 1885
    call_tydesc_glue_full(bcx, v, td, field, ti);
    ret bcx;
1886 1887
}

1888
fn call_cmp_glue(cx: @block_ctxt, lhs: ValueRef, rhs: ValueRef, t: ty::t,
M
Marijn Haverbeke 已提交
1889
                 llop: ValueRef) -> result {
1890 1891 1892
    // We can't use call_tydesc_glue_full() and friends here because compare
    // glue has a special signature.

1893 1894 1895
    let bcx = cx;

    let r = spill_if_immediate(bcx, lhs, t);
B
Brian Anderson 已提交
1896 1897
    let lllhs = r.val;
    bcx = r.bcx;
1898
    r = spill_if_immediate(bcx, rhs, t);
B
Brian Anderson 已提交
1899 1900
    let llrhs = r.val;
    bcx = r.bcx;
1901 1902 1903

    let llrawlhsptr = BitCast(bcx, lllhs, T_ptr(T_i8()));
    let llrawrhsptr = BitCast(bcx, llrhs, T_ptr(T_i8()));
1904
    let ti = none::<@tydesc_info>;
1905
    r = get_tydesc(bcx, t, false, tps_normal, ti).result;
B
Brian Anderson 已提交
1906 1907
    let lltydesc = r.val;
    bcx = r.bcx;
1908
    lazily_emit_tydesc_glue(bcx, abi::tydesc_field_cmp_glue, ti);
B
Brian Anderson 已提交
1909 1910
    let lltydescs =
        GEP(bcx, lltydesc, [C_int(0), C_int(abi::tydesc_field_first_param)]);
1911
    lltydescs = Load(bcx, lltydescs);
1912

M
Marijn Haverbeke 已提交
1913 1914 1915
    let llfn;
    alt ti {
      none. {
B
Brian Anderson 已提交
1916 1917
        let llfnptr =
            GEP(bcx, lltydesc, [C_int(0), C_int(abi::tydesc_field_cmp_glue)]);
1918
        llfn = Load(bcx, llfnptr);
1919
      }
M
Marijn Haverbeke 已提交
1920
      some(sti) { llfn = option::get(sti.cmp_glue); }
1921 1922
    }

1923
    let llcmpresultptr = alloca(bcx, T_i1());
1924
    let llargs: [ValueRef] =
B
Brian Anderson 已提交
1925 1926
        [llcmpresultptr, bcx.fcx.lltaskptr, lltydesc, lltydescs, llrawlhsptr,
         llrawrhsptr, llop];
1927 1928
    Call(bcx, llfn, llargs);
    ret rslt(bcx, Load(bcx, llcmpresultptr));
1929 1930
}

1931 1932
// Compares two values. Performs the simple scalar comparison if the types are
// scalar and calls to comparison glue otherwise.
1933
fn compare(cx: @block_ctxt, lhs: ValueRef, rhs: ValueRef, t: ty::t,
M
Marijn Haverbeke 已提交
1934 1935
           llop: ValueRef) -> result {
    if ty::type_is_scalar(bcx_tcx(cx), t) {
1936 1937 1938 1939 1940
        ret compare_scalar_types(cx, lhs, rhs, t, llop);
    }
    ret call_cmp_glue(cx, lhs, rhs, t, llop);
}

1941
fn take_ty(cx: @block_ctxt, v: ValueRef, t: ty::t) -> @block_ctxt {
M
Marijn Haverbeke 已提交
1942
    if ty::type_has_pointers(bcx_tcx(cx), t) {
1943
        ret call_tydesc_glue(cx, v, t, abi::tydesc_field_take_glue);
1944
    }
1945
    ret cx;
1946 1947
}

1948
fn drop_ty(cx: @block_ctxt, v: ValueRef, t: ty::t) -> @block_ctxt {
1949
    if ty::type_needs_drop(bcx_tcx(cx), t) {
1950
        ret call_tydesc_glue(cx, v, t, abi::tydesc_field_drop_glue);
1951
    }
1952
    ret cx;
1953 1954
}

1955
fn free_ty(cx: @block_ctxt, v: ValueRef, t: ty::t) -> @block_ctxt {
M
Marijn Haverbeke 已提交
1956
    if ty::type_has_pointers(bcx_tcx(cx), t) {
1957
        ret call_tydesc_glue(cx, v, t, abi::tydesc_field_free_glue);
1958
    }
1959
    ret cx;
1960 1961
}

1962
fn call_memmove(cx: @block_ctxt, dst: ValueRef, src: ValueRef,
M
Marijn Haverbeke 已提交
1963
                n_bytes: ValueRef) -> result {
1964
    // FIXME: switch to the 64-bit variant when on such a platform.
1965 1966 1967
    // 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).
1968

M
Marijn Haverbeke 已提交
1969
    let i = bcx_ccx(cx).intrinsics;
B
Brian Anderson 已提交
1970 1971
    assert (i.contains_key("llvm.memmove.p0i8.p0i8.i32"));
    let memmove = i.get("llvm.memmove.p0i8.p0i8.i32");
1972 1973 1974
    let src_ptr = PointerCast(cx, src, T_ptr(T_i8()));
    let dst_ptr = PointerCast(cx, dst, T_ptr(T_i8()));
    let size = IntCast(cx, n_bytes, T_i32());
1975
    let align = C_int(1);
M
Marijn Haverbeke 已提交
1976
    let volatile = C_bool(false);
1977
    ret rslt(cx,
B
Brian Anderson 已提交
1978
             Call(cx, memmove, [dst_ptr, src_ptr, size, align, volatile]));
1979 1980
}

1981
fn call_bzero(cx: @block_ctxt, dst: ValueRef, n_bytes: ValueRef,
M
Marijn Haverbeke 已提交
1982
              align_bytes: ValueRef) -> result {
1983
    // FIXME: switch to the 64-bit variant when on such a platform.
1984

M
Marijn Haverbeke 已提交
1985
    let i = bcx_ccx(cx).intrinsics;
B
Brian Anderson 已提交
1986 1987
    assert (i.contains_key("llvm.memset.p0i8.i32"));
    let memset = i.get("llvm.memset.p0i8.i32");
1988 1989
    let dst_ptr = PointerCast(cx, dst, T_ptr(T_i8()));
    let size = IntCast(cx, n_bytes, T_i32());
M
Marijn Haverbeke 已提交
1990 1991
    let align =
        if lib::llvm::llvm::LLVMIsConstant(align_bytes) == True {
1992 1993
            IntCast(cx, align_bytes, T_i32())
        } else { IntCast(cx, C_int(0), T_i32()) };
M
Marijn Haverbeke 已提交
1994
    let volatile = C_bool(false);
1995
    ret rslt(cx,
B
Brian Anderson 已提交
1996
             Call(cx, memset, [dst_ptr, C_u8(0u), size, align, volatile]));
1997 1998
}

1999
fn memmove_ty(cx: @block_ctxt, dst: ValueRef, src: ValueRef, t: ty::t) ->
2000
    @block_ctxt {
2001 2002 2003 2004 2005
    let ccx = bcx_ccx(cx);
    if check type_has_static_size(ccx, t) {
        if ty::type_is_structural(bcx_tcx(cx), t) {
            let sp = cx.sp;
            let llsz = llsize_of(type_of(ccx, sp, t));
2006
            ret call_memmove(cx, dst, src, llsz).bcx;
2007
        }
2008 2009
        Store(cx, Load(cx, src), dst);
        ret cx;
2010
    }
2011 2012

    let llsz = size_of(cx, t);
2013
    ret call_memmove(llsz.bcx, dst, src, llsz.val).bcx;
2014 2015
}

2016
tag copy_action { INIT; DROP_EXISTING; }
2017

2018
// These are the types that are passed by pointer.
2019
fn type_is_structural_or_param(tcx: ty::ctxt, t: ty::t) -> bool {
2020 2021 2022 2023 2024 2025 2026
    if ty::type_is_structural(tcx, t) { ret true; }
    alt ty::struct(tcx, t) {
      ty::ty_param(_, _) { ret true; }
      _ { ret false; }
    }
}

2027
fn copy_val(cx: @block_ctxt, action: copy_action, dst: ValueRef,
2028
            src: ValueRef, t: ty::t) -> @block_ctxt {
2029 2030 2031
    if action == DROP_EXISTING &&
        (type_is_structural_or_param(bcx_tcx(cx), t) ||
         ty::type_is_unique(bcx_tcx(cx), t)) {
B
Brian Anderson 已提交
2032 2033
        let do_copy_cx = new_sub_block_ctxt(cx, "do_copy");
        let next_cx = new_sub_block_ctxt(cx, "next");
2034
        let dstcmp = load_if_immediate(cx, dst, t);
2035
        let self_assigning =
2036 2037
            ICmp(cx, lib::llvm::LLVMIntNE,
                 PointerCast(cx, dstcmp, val_ty(src)), src);
2038
        CondBr(cx, self_assigning, do_copy_cx.llbb, next_cx.llbb);
2039
        do_copy_cx = copy_val_no_check(do_copy_cx, action, dst, src, t);
2040
        Br(do_copy_cx, next_cx.llbb);
2041 2042 2043 2044 2045
        ret next_cx;
    }
    ret copy_val_no_check(cx, action, dst, src, t);
}

2046
fn copy_val_no_check(cx: @block_ctxt, action: copy_action, dst: ValueRef,
2047
                     src: ValueRef, t: ty::t) -> @block_ctxt {
M
Marijn Haverbeke 已提交
2048 2049
    let ccx = bcx_ccx(cx);
    if ty::type_is_scalar(ccx.tcx, t) || ty::type_is_native(ccx.tcx, t) {
2050
        Store(cx, src, dst);
2051
        ret cx;
2052 2053 2054 2055 2056
    }
    if ty::type_is_nil(ccx.tcx, t) || ty::type_is_bot(ccx.tcx, t) { ret cx; }
    if ty::type_is_boxed(ccx.tcx, t) {
        let bcx = cx;
        if action == DROP_EXISTING { bcx = drop_ty(cx, dst, t); }
2057
        Store(bcx, src, dst);
2058 2059
        ret take_ty(bcx, dst, t);
    }
2060
    if ty::type_is_unique_box(ccx.tcx, t) {
2061
        let bcx = cx;
2062
        if action == DROP_EXISTING { bcx = drop_ty(cx, dst, t); }
2063 2064
        check trans_uniq::type_is_unique_box(bcx, t);
        ret trans_uniq::copy_val(bcx, dst, src, t);
2065
    }
2066
    if type_is_structural_or_param(ccx.tcx, t) || ty::type_is_vec(ccx.tcx, t)
2067
        {
2068 2069
        let bcx = cx;
        if action == DROP_EXISTING { bcx = drop_ty(cx, dst, t); }
2070
        bcx = memmove_ty(bcx, dst, src, t);
2071
        ret take_ty(bcx, dst, t);
2072
    }
B
Brian Anderson 已提交
2073 2074
    ccx.sess.bug("unexpected type in trans::copy_val_no_check: " +
                     ty_to_str(ccx.tcx, t));
2075 2076
}

2077

M
Michael Sullivan 已提交
2078 2079 2080 2081 2082
// 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.
M
Marijn Haverbeke 已提交
2083
fn move_val(cx: @block_ctxt, action: copy_action, dst: ValueRef,
2084
            src: lval_result, t: ty::t) -> @block_ctxt {
2085
    let src_val = src.val;
2086
    let tcx = bcx_tcx(cx);
B
Brian Anderson 已提交
2087
    if ty::type_is_scalar(tcx, t) || ty::type_is_native(tcx, t) {
2088 2089
        if src.is_mem { src_val = Load(cx, src_val); }
        Store(cx, src_val, dst);
2090
        ret cx;
2091
    } else if ty::type_is_nil(tcx, t) || ty::type_is_bot(tcx, t) {
2092
        ret cx;
2093
    } else if ty::type_is_boxed(tcx, t) || ty::type_is_unique_box(tcx, t) {
2094
        if src.is_mem { src_val = Load(cx, src_val); }
B
Brian Anderson 已提交
2095
        if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); }
2096
        Store(cx, src_val, dst);
2097
        if src.is_mem { ret zero_alloca(cx, src.val, t); }
2098 2099

        // If we're here, it must be a temporary.
2100
        ret revoke_clean(cx, src_val);
2101
    } else if ty::type_is_unique(tcx, t) ||
2102
                  type_is_structural_or_param(tcx, t) {
2103
        if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); }
2104
        cx = memmove_ty(cx, dst, src_val, t);
2105
        if src.is_mem { ret zero_alloca(cx, src_val, t); }
2106 2107

        // If we're here, it must be a temporary.
2108
        ret revoke_clean(cx, src_val);
M
Michael Sullivan 已提交
2109
    }
2110
    /* FIXME: suggests a type constraint */
B
Brian Anderson 已提交
2111 2112
    bcx_ccx(cx).sess.bug("unexpected type in trans::move_val: " +
                             ty_to_str(tcx, t));
2113 2114
}

M
Marijn Haverbeke 已提交
2115
fn move_val_if_temp(cx: @block_ctxt, action: copy_action, dst: ValueRef,
2116
                    src: lval_result, t: ty::t) -> @block_ctxt {
2117
    // Lvals in memory are not temporaries. Copy them.
M
Marijn Haverbeke 已提交
2118
    if src.is_mem {
2119
        ret copy_val(cx, action, dst, load_if_immediate(cx, src.val, t),
M
Marijn Haverbeke 已提交
2120
                     t);
2121 2122
    }
    ret move_val(cx, action, dst, src, t);
M
Michael Sullivan 已提交
2123 2124
}

2125
fn trans_crate_lit(cx: @crate_ctxt, lit: ast::lit) -> ValueRef {
M
Marijn Haverbeke 已提交
2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147
    alt lit.node {
      ast::lit_int(i) { ret C_int(i); }
      ast::lit_uint(u) { ret C_int(u as int); }
      ast::lit_mach_int(tm, i) {
        // FIXME: the entire handling of mach types falls apart
        // if target int width is larger than host, at the moment;
        // re-do the mach-int types using 'big' when that works.

        let t = T_int();
        let s = True;
        alt tm {
          ast::ty_u8. { t = T_i8(); s = False; }
          ast::ty_u16. { t = T_i16(); s = False; }
          ast::ty_u32. { t = T_i32(); s = False; }
          ast::ty_u64. { t = T_i64(); s = False; }
          ast::ty_i8. { t = T_i8(); }
          ast::ty_i16. { t = T_i16(); }
          ast::ty_i32. { t = T_i32(); }
          ast::ty_i64. { t = T_i64(); }
        }
        ret C_integral(t, i as uint, s);
      }
2148
      ast::lit_float(fs) { ret C_float(fs); }
M
Marijn Haverbeke 已提交
2149 2150 2151
      ast::lit_mach_float(tm, s) {
        let t = T_float();
        alt tm { ast::ty_f32. { t = T_f32(); } ast::ty_f64. { t = T_f64(); } }
2152
        ret C_floating(s, t);
M
Marijn Haverbeke 已提交
2153 2154 2155 2156
      }
      ast::lit_char(c) { ret C_integral(T_char(), c as uint, False); }
      ast::lit_bool(b) { ret C_bool(b); }
      ast::lit_nil. { ret C_nil(); }
2157
      ast::lit_str(s) {
B
Brian Anderson 已提交
2158
        cx.sess.span_unimpl(lit.span, "unique string in this context");
M
Marijn Haverbeke 已提交
2159
      }
2160 2161 2162
    }
}

2163 2164
fn trans_lit(cx: @block_ctxt, lit: ast::lit, dest: dest) -> @block_ctxt {
    if dest == ignore { ret cx; }
M
Marijn Haverbeke 已提交
2165
    alt lit.node {
2166 2167
      ast::lit_str(s) { ret tvec::trans_str(cx, s, dest); }
      _ {
2168
        ret store_in_dest(cx, trans_crate_lit(bcx_ccx(cx), lit), dest);
2169
      }
2170 2171 2172
    }
}

2173

2174
// Converts an annotation to a type
2175
fn node_id_type(cx: @crate_ctxt, id: ast::node_id) -> ty::t {
2176
    ret ty::node_id_to_monotype(cx.tcx, id);
2177 2178
}

2179
fn node_type(cx: @crate_ctxt, sp: span, id: ast::node_id) -> TypeRef {
2180 2181 2182 2183
    let ty = node_id_type(cx, id);
    // How to make this a precondition?
    // FIXME (again, would require a predicate that implies
    // another predicate)
2184
    check (type_has_static_size(cx, ty));
2185
    type_of(cx, sp, ty)
2186 2187
}

M
Marijn Haverbeke 已提交
2188 2189 2190 2191
fn trans_unary(bcx: @block_ctxt, op: ast::unop, e: @ast::expr,
               id: ast::node_id, dest: dest) -> @block_ctxt {
    if dest == ignore { ret trans_expr_dps(bcx, e, ignore); }
    let e_ty = ty::expr_ty(bcx_tcx(bcx), e);
M
Marijn Haverbeke 已提交
2192 2193
    alt op {
      ast::not. {
M
Marijn Haverbeke 已提交
2194 2195
        let {bcx, val} = trans_expr(bcx, e);
        ret store_in_dest(bcx, Not(bcx, val), dest);
M
Marijn Haverbeke 已提交
2196 2197
      }
      ast::neg. {
M
Marijn Haverbeke 已提交
2198 2199 2200 2201 2202
        let {bcx, val} = trans_expr(bcx, e);
        let neg = if ty::struct(bcx_tcx(bcx), e_ty) == ty::ty_float {
            FNeg(bcx, val)
        } else { Neg(bcx, val) };
        ret store_in_dest(bcx, neg, dest);
M
Marijn Haverbeke 已提交
2203 2204
      }
      ast::box(_) {
M
Marijn Haverbeke 已提交
2205 2206
        let {bcx, box, body} = trans_malloc_boxed(bcx, e_ty);
        add_clean_free(bcx, box, false);
M
Marijn Haverbeke 已提交
2207 2208 2209
        // Cast the body type to the type of the value. This is needed to
        // make tags work, since tags have a different LLVM type depending
        // on whether they're boxed or not.
M
Marijn Haverbeke 已提交
2210 2211
        let ccx = bcx_ccx(bcx);
        if check type_has_static_size(ccx, e_ty) {
2212
            let e_sp = e.span;
M
Marijn Haverbeke 已提交
2213 2214 2215
            let llety = T_ptr(type_of(ccx, e_sp, e_ty));
            body = PointerCast(bcx, body, llety);
        }
2216
        bcx = trans_expr_save_in(bcx, e, body, INIT);
M
Marijn Haverbeke 已提交
2217 2218
        revoke_clean(bcx, box);
        ret store_in_dest(bcx, box, dest);
M
Marijn Haverbeke 已提交
2219
      }
2220
      ast::uniq(_) {
M
Marijn Haverbeke 已提交
2221
        ret trans_uniq::trans_uniq(bcx, e, id, dest);
2222
      }
M
Marijn Haverbeke 已提交
2223
      ast::deref. {
M
Marijn Haverbeke 已提交
2224 2225 2226
        bcx_ccx(bcx).sess.bug("deref expressions should have been \
                               translated using trans_lval(), not \
                               trans_unary()");
M
Marijn Haverbeke 已提交
2227
      }
2228 2229 2230
    }
}

2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257
fn trans_expr_fn(bcx: @block_ctxt, f: ast::_fn, sp: span,
                 id: ast::node_id, dest: dest) -> @block_ctxt {
    if dest == ignore { ret bcx; }
    let ccx = bcx_ccx(bcx);
    let fty = node_id_type(ccx, id);
    check returns_non_ty_var(ccx, fty);
    let llfnty = type_of_fn_from_ty(ccx, sp, fty, 0u);
    let sub_cx = extend_path(bcx.fcx.lcx, ccx.names.next("anon"));
    let s = mangle_internal_name_by_path(ccx, sub_cx.path);
    let llfn = decl_internal_cdecl_fn(ccx.llmod, s, llfnty);

    let copying = f.proto == ast::proto_closure;
    let env;
    alt f.proto {
      ast::proto_block. | ast::proto_closure. {
        let upvars = get_freevars(ccx.tcx, id);
        let env_r = build_closure(bcx, upvars, copying);
        env = env_r.ptr;
        trans_closure(sub_cx, sp, f, llfn, none, [], id, {|fcx|
            load_environment(bcx, fcx, env_r.ptrty, upvars, copying);
        });
      }
      _ {
        env = C_null(T_opaque_closure_ptr(*bcx_ccx(bcx)));
        trans_closure(sub_cx, sp, f, llfn, none, [], id, {|_fcx|});
      }
    };
2258 2259
    let {bcx, val: addr} = get_dest_addr(bcx, dest);
    fill_fn_pair(bcx, addr, llfn, env);
2260 2261 2262
    ret bcx;
}

2263
fn trans_compare(cx: @block_ctxt, op: ast::binop, lhs: ValueRef,
B
Brian Anderson 已提交
2264
                 _lhs_t: ty::t, rhs: ValueRef, rhs_t: ty::t) -> result {
2265
    // Determine the operation we need.
M
Marijn Haverbeke 已提交
2266 2267
    let llop;
    alt op {
2268 2269 2270
      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); }
2271
    }
M
Marijn Haverbeke 已提交
2272

2273
    let rs = compare(cx, lhs, rhs, rhs_t, llop);
2274

T
Tim Chevalier 已提交
2275 2276 2277 2278
    // Invert the result if necessary.
    alt op {
      ast::eq. | ast::lt. | ast::le. { ret rslt(rs.bcx, rs.val); }
      ast::ne. | ast::ge. | ast::gt. {
2279
        ret rslt(rs.bcx, Not(rs.bcx, rs.val));
T
Tim Chevalier 已提交
2280
      }
2281 2282 2283
    }
}

2284 2285
// Important to get types for both lhs and rhs, because one might be _|_
// and the other not.
2286
fn trans_eager_binop(cx: @block_ctxt, op: ast::binop, lhs: ValueRef,
2287 2288 2289
                     lhs_t: ty::t, rhs: ValueRef, rhs_t: ty::t, dest: dest)
    -> @block_ctxt {
    if dest == ignore { ret cx; }
M
Marijn Haverbeke 已提交
2290
    let is_float = false;
2291
    let intype = lhs_t;
B
Brian Anderson 已提交
2292
    if ty::type_is_bot(bcx_tcx(cx), intype) { intype = rhs_t; }
2293

M
Marijn Haverbeke 已提交
2294 2295 2296
    alt ty::struct(bcx_tcx(cx), intype) {
      ty::ty_float. { is_float = true; }
      _ { is_float = false; }
2297
    }
2298 2299 2300 2301
    if op == ast::add && ty::type_is_sequence(bcx_tcx(cx), intype) {
        ret tvec::trans_add(cx, intype, lhs, rhs, dest);
    }
    let val = alt op {
M
Marijn Haverbeke 已提交
2302
      ast::add. {
2303 2304
        if is_float { FAdd(cx, lhs, rhs) }
        else { Add(cx, lhs, rhs) }
M
Marijn Haverbeke 已提交
2305 2306
      }
      ast::sub. {
2307 2308
        if is_float { FSub(cx, lhs, rhs) }
        else { Sub(cx, lhs, rhs) }
M
Marijn Haverbeke 已提交
2309 2310
      }
      ast::mul. {
2311 2312
        if is_float { FMul(cx, lhs, rhs) }
        else { Mul(cx, lhs, rhs) }
M
Marijn Haverbeke 已提交
2313 2314
      }
      ast::div. {
2315 2316 2317 2318
        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) }
M
Marijn Haverbeke 已提交
2319 2320
      }
      ast::rem. {
2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338
        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) }
      }
      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) }
      _ {
        let cmpr = trans_compare(cx, op, lhs, lhs_t, rhs, rhs_t);
        cx = cmpr.bcx;
        cmpr.val
      }
    };
    ret store_in_dest(cx, val, dest);
M
Marijn Haverbeke 已提交
2339 2340
}

2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359
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);
    assert (lhs_res.is_mem);
    // 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);
          }
          _ { }
        }
      }
      _ { }
    }
2360
    let rhs_res = trans_expr(lhs_res.bcx, src);
2361 2362 2363
    if ty::type_is_sequence(tcx, t) {
        alt op {
          ast::add. {
2364 2365
            ret tvec::trans_append(rhs_res.bcx, t, lhs_res.val,
                                   rhs_res.val);
2366 2367 2368 2369
          }
          _ { }
        }
    }
2370 2371 2372
    let lhs_val = load_if_immediate(rhs_res.bcx, lhs_res.val, t);
    ret trans_eager_binop(rhs_res.bcx, op, lhs_val, t, rhs_res.val, t,
                          overwrite(lhs_res.val, t));
2373 2374
}

2375
fn autoderef(cx: @block_ctxt, v: ValueRef, t: ty::t) -> result_t {
M
Marijn Haverbeke 已提交
2376 2377 2378
    let v1: ValueRef = v;
    let t1: ty::t = t;
    let ccx = bcx_ccx(cx);
2379
    let sp = cx.sp;
M
Marijn Haverbeke 已提交
2380 2381 2382
    while true {
        alt ty::struct(ccx.tcx, t1) {
          ty::ty_box(mt) {
B
Brian Anderson 已提交
2383
            let body = GEP(cx, v1, [C_int(0), C_int(abi::box_rc_field_body)]);
M
Marijn Haverbeke 已提交
2384 2385 2386 2387 2388 2389
            t1 = mt.ty;

            // Since we're changing levels of box indirection, we may have
            // to cast this pointer, since statically-sized tag types have
            // different types depending on whether they're behind a box
            // or not.
2390 2391
            if check type_has_static_size(ccx, t1) {
                let llty = type_of(ccx, sp, t1);
2392
                v1 = PointerCast(cx, body, T_ptr(llty));
M
Marijn Haverbeke 已提交
2393 2394
            } else { v1 = body; }
          }
2395 2396 2397 2398 2399 2400
          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;
          }
M
Marijn Haverbeke 已提交
2401 2402
          ty::ty_res(did, inner, tps) {
            t1 = ty::substitute_type_params(ccx.tcx, tps, inner);
2403
            v1 = GEP(cx, v1, [C_int(0), C_int(1)]);
M
Marijn Haverbeke 已提交
2404 2405 2406
          }
          ty::ty_tag(did, tps) {
            let variants = ty::tag_variants(ccx.tcx, did);
B
Brian Anderson 已提交
2407
            if std::vec::len(variants) != 1u ||
B
Brian Anderson 已提交
2408
                   std::vec::len(variants[0].args) != 1u {
M
Marijn Haverbeke 已提交
2409
                break;
2410
            }
M
Marijn Haverbeke 已提交
2411
            t1 =
B
Brian Anderson 已提交
2412
                ty::substitute_type_params(ccx.tcx, tps, variants[0].args[0]);
2413 2414
            if check type_has_static_size(ccx, t1) {
                v1 = PointerCast(cx, v1, T_ptr(type_of(ccx, sp, t1)));
2415
            } else { } // FIXME: typestate hack
M
Marijn Haverbeke 已提交
2416 2417
          }
          _ { break; }
2418
        }
2419
        v1 = load_if_immediate(cx, v1, t1);
2420
    }
M
Marijn Haverbeke 已提交
2421
    ret {bcx: cx, val: v1, ty: t1};
2422 2423
}

2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453
fn trans_lazy_binop(bcx: @block_ctxt, op: ast::binop, a: @ast::expr,
                    b: @ast::expr, dest: dest) -> @block_ctxt {
    let is_and = alt op { ast::and. { true } ast::or. { false } };
    let lhs_res = trans_expr(bcx, a);
    if lhs_res.bcx.unreachable { ret lhs_res.bcx; }
    let rhs_cx = new_scope_block_ctxt(lhs_res.bcx, "rhs");
    let rhs_res = trans_expr(rhs_cx, b);

    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);
}
B
Brian Anderson 已提交
2454

2455 2456
fn trans_binary(cx: @block_ctxt, op: ast::binop, a: @ast::expr, b: @ast::expr,
                dest: dest) -> @block_ctxt {
2457
    // First couple cases are lazy:
M
Marijn Haverbeke 已提交
2458
    alt op {
2459 2460
      ast::and. | ast::or. {
        ret trans_lazy_binop(cx, op, a, b, dest);
M
Marijn Haverbeke 已提交
2461 2462 2463
      }
      _ {
        // Remaining cases are eager:
2464 2465
        let lhs = trans_expr(cx, a);
        let rhs = trans_expr(lhs.bcx, b);
B
Brian Anderson 已提交
2466 2467
        ret trans_eager_binop(rhs.bcx, op, lhs.val,
                              ty::expr_ty(bcx_tcx(cx), a), rhs.val,
2468
                              ty::expr_ty(bcx_tcx(cx), b), dest);
M
Marijn Haverbeke 已提交
2469
      }
2470 2471 2472
    }
}

2473
// FIXME remove once all uses have been converted to join_returns
2474
fn join_branches(parent_cx: @block_ctxt, ins: [result]) -> @block_ctxt {
B
Brian Anderson 已提交
2475
    let out = new_sub_block_ctxt(parent_cx, "join");
2476 2477 2478 2479 2480
    let branched = false;
    for r: result in ins {
        if !r.bcx.unreachable { Br(r.bcx, out.llbb); branched = true; }
    }
    if !branched { Unreachable(out); }
2481 2482 2483
    ret out;
}

2484 2485 2486 2487
tag dest {
    by_val(@mutable ValueRef);
    by_ref(@mutable ValueRef);
    save_in(ValueRef);
2488
    overwrite(ValueRef, ty::t);
2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516
    ignore;
}

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()) }
      by_ref(_) { by_ref(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] {
              by_val(cell) | by_ref(cell) {
                if option::is_none(phi) {
                    phi = some(EmptyPhi(out, val_ty(*cell)));
                }
2517
                AddIncomingToPhi(option::get(phi), *cell, cx.llbb);
2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534
              }
              _ {}
            }
        }
        i += 1u;
    }
    if !reachable {
        Unreachable(out);
    } else {
        alt out_dest {
          by_val(cell) | by_ref(cell) { *cell = option::get(phi); }
          _ {}
        }
    }
    ret out;
}

M
Marijn Haverbeke 已提交
2535
// Used to put an immediate value in a dest.
2536 2537 2538 2539 2540
fn store_in_dest(bcx: @block_ctxt, val: ValueRef, dest: dest) -> @block_ctxt {
    alt dest {
      ignore. {}
      by_val(cell) { *cell = val; }
      save_in(addr) { Store(bcx, val, addr); }
2541 2542 2543 2544
      overwrite(addr, tp) {
        bcx = drop_ty(bcx, addr, tp);
        Store(bcx, val, addr);
      }
2545 2546 2547 2548
    }
    ret bcx;
}

2549 2550 2551 2552 2553
fn get_dest_addr(bcx: @block_ctxt, dest: dest) -> result {
    alt dest {
      save_in(a) { rslt(bcx, a) }
      overwrite(a, t) { rslt(drop_ty(bcx, a, t), a) }
    }
2554 2555
}

2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575
// Wrapper through which legacy non-DPS code can use DPS functions
fn dps_to_result(bcx: @block_ctxt,
                 work: block(@block_ctxt, dest) -> @block_ctxt,
                 ty: ty::t) -> result {
    let tcx = bcx_tcx(bcx);
    if ty::type_is_nil(tcx, ty) || ty::type_is_bot(tcx, ty) {
        ret rslt(work(bcx, ignore), C_nil());
    } else if type_is_immediate(bcx_ccx(bcx), ty) {
        let cell = empty_dest_cell();
        bcx = work(bcx, by_val(cell));
        add_clean_temp(bcx, *cell, ty);
        ret rslt(bcx, *cell);
    } else {
        let {bcx, val: alloca} = alloc_ty(bcx, ty);
        bcx = zero_alloca(bcx, alloca, ty);
        bcx = work(bcx, save_in(alloca));
        add_clean_temp(bcx, alloca, ty);
        ret rslt(bcx, alloca);
    }
}
2576

2577
fn trans_if(cx: @block_ctxt, cond: @ast::expr, thn: ast::blk,
2578 2579
            els: option::t<@ast::expr>, dest: dest)
    -> @block_ctxt {
2580
    let {bcx, val: cond_val} = trans_expr(cx, cond);
2581

2582 2583
    let then_dest = dup_for_join(dest);
    let else_dest = dup_for_join(dest);
2584 2585
    let then_cx = new_scope_block_ctxt(bcx, "then");
    let else_cx = new_scope_block_ctxt(bcx, "else");
2586 2587
    CondBr(bcx, cond_val, then_cx.llbb, else_cx.llbb);
    then_cx = trans_block_dps(then_cx, thn, then_dest);
2588 2589 2590 2591
    // 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
2592 2593 2594 2595 2596 2597
    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);
M
Marijn Haverbeke 已提交
2598
          }
2599 2600 2601 2602 2603 2604 2605 2606
          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);
2607 2608
}

2609
fn trans_for(cx: @block_ctxt, local: @ast::local, seq: @ast::expr,
2610
             body: ast::blk) -> @block_ctxt {
M
Marijn Haverbeke 已提交
2611
    fn inner(bcx: @block_ctxt, local: @ast::local, curr: ValueRef, t: ty::t,
2612
             body: ast::blk, outer_next_cx: @block_ctxt) -> @block_ctxt {
M
Marijn Haverbeke 已提交
2613
        let next_cx = new_sub_block_ctxt(bcx, "next");
2614
        let scope_cx =
M
Marijn Haverbeke 已提交
2615
            new_loop_scope_block_ctxt(bcx, option::some(next_cx),
2616
                                      outer_next_cx, "for loop scope");
M
Marijn Haverbeke 已提交
2617 2618 2619 2620
        Br(bcx, scope_cx.llbb);
        curr = PointerCast(bcx, curr, T_ptr(type_of_or_i8(bcx, t)));
        bcx = trans_alt::bind_irrefutable_pat(scope_cx, local.node.pat, curr,
                                              bcx.fcx.lllocals, false);
2621
        bcx = trans_block_dps(bcx, body, ignore);
2622
        Br(bcx, next_cx.llbb);
2623
        ret next_cx;
G
Graydon Hoare 已提交
2624
    }
B
Brian Anderson 已提交
2625
    let next_cx = new_sub_block_ctxt(cx, "next");
M
Marijn Haverbeke 已提交
2626
    let seq_ty = ty::expr_ty(bcx_tcx(cx), seq);
2627
    let {bcx: bcx, val: seq} = trans_expr(cx, seq);
2628 2629 2630 2631 2632
    let seq = PointerCast(bcx, seq, T_ptr(T_ptr(T_opaque_vec())));
    let fill = tvec::get_fill(bcx, seq);
    if ty::type_is_str(bcx_tcx(bcx), seq_ty) {
        fill = Sub(bcx, fill, C_int(1));
    }
2633 2634 2635
    let bcx =
        tvec::iter_vec_raw(bcx, seq, seq_ty, fill,
                           bind inner(_, local, _, _, body, next_cx));
2636
    Br(bcx, next_cx.llbb);
2637
    ret next_cx;
G
Graydon Hoare 已提交
2638 2639
}

2640 2641 2642

// Iterator translation

2643 2644 2645 2646 2647
tag environment_value {
    env_expr(@ast::expr);
    env_direct(ValueRef, ty::t);
}

2648 2649 2650 2651
// Given a block context and a list of tydescs and values to bind
// construct a closure out of them. If copying is true, it is a
// heap allocated closure that copies the upvars into environment.
// Otherwise, it is stack allocated and copies pointers to the upvars.
2652
fn build_environment(bcx: @block_ctxt, lltydescs: [ValueRef],
2653
                     bound_values: [environment_value],
B
Brian Anderson 已提交
2654 2655
                     copying: bool) ->
   {ptr: ValueRef, ptrty: ty::t, bcx: @block_ctxt} {
2656
    let tcx = bcx_tcx(bcx);
2657 2658 2659 2660
    // Synthesize a closure type.

    // First, synthesize a tuple type containing the types of all the
    // bound expressions.
2661
    // bindings_ty = [bound_ty1, bound_ty2, ...]
2662 2663 2664 2665 2666 2667 2668 2669
    let bound_tys = [];
    for bv in bound_values {
        bound_tys += [alt bv {
          env_direct(_, t) { t }
          env_expr(e) { ty::expr_ty(tcx, e) }
        }];
    }
    let bindings_ty: ty::t = ty::mk_tup(tcx, bound_tys);
2670 2671 2672 2673 2674 2675 2676

    // NB: keep this in sync with T_closure_ptr; we're making
    // a ty::t structure that has the same "shape" as the LLVM type
    // it constructs.

    // Make a vector that contains ty_param_count copies of tydesc_ty.
    // (We'll need room for that many tydescs in the closure.)
B
Brian Anderson 已提交
2677
    let ty_param_count = std::vec::len(lltydescs);
2678
    let tydesc_ty: ty::t = ty::mk_type(tcx);
B
Brian Anderson 已提交
2679
    let captured_tys: [ty::t] = std::vec::init_elt(tydesc_ty, ty_param_count);
2680 2681 2682 2683 2684

    // Get all the types we've got (some of which we synthesized
    // ourselves) into a vector.  The whole things ends up looking
    // like:

2685 2686
    // closure_tys = [tydesc_ty, [bound_ty1, bound_ty2, ...], [tydesc_ty,
    // tydesc_ty, ...]]
2687
    let closure_tys: [ty::t] =
2688
        [tydesc_ty, bindings_ty, ty::mk_tup(tcx, captured_tys)];
2689 2690

    // Finally, synthesize a type for that whole vector.
2691
    let closure_ty: ty::t = ty::mk_tup(tcx, closure_tys);
2692

2693
    let temp_cleanups = [];
2694
    // Allocate a box that can hold something closure-sized.
2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709
    let (closure, box) = if copying {
        let r = trans_malloc_boxed(bcx, closure_ty);
        add_clean_free(bcx, r.box, false);
        temp_cleanups += [r.box];
        bcx = r.bcx;
        (r.body, r.box)
    } else {
        // We need to dummy up a box on the stack
        let ty = ty::mk_tup(tcx, [ty::mk_int(tcx), closure_ty]);
        let r = alloc_ty(bcx, ty);
        bcx = r.bcx;
        // Prevent glue from trying to free this.
        Store(bcx, C_int(2), GEPi(bcx, r.val, [0, abi::box_rc_field_refcnt]));
        (GEPi(bcx, r.val, [0, abi::box_rc_field_body]), r.val)
    };
2710 2711

    // Store bindings tydesc.
2712
    if copying {
B
Brian Anderson 已提交
2713
        let bound_tydesc = GEPi(bcx, closure, [0, abi::closure_elt_tydesc]);
2714
        let ti = none;
2715 2716
        let bindings_tydesc =
            get_tydesc(bcx, bindings_ty, true, tps_normal, ti).result;
2717 2718 2719
        lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
        lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
        bcx = bindings_tydesc.bcx;
2720
        Store(bcx, bindings_tydesc.val, bound_tydesc);
2721
    }
2722 2723

    // Copy expr values into boxed bindings.
2724 2725
    // Silly check
    check type_is_tup_like(bcx, closure_ty);
2726 2727
    let bindings = GEP_tup_like(bcx, closure_ty, closure,
                                [0, abi::closure_elt_bindings]);
2728
    bcx = bindings.bcx;
2729 2730
    let i = 0u;
    for bv in bound_values {
B
Brian Anderson 已提交
2731
        let bound =
2732
            GEP_tup_like_1(bcx, bindings_ty, bindings.val, [0, i as int]);
2733
        bcx = bound.bcx;
2734 2735
        alt bv {
          env_expr(e) {
2736
            bcx = trans_expr_save_in(bcx, e, bound.val, INIT);
2737 2738 2739 2740 2741 2742 2743 2744 2745 2746
            add_clean_temp_mem(bcx, bound.val, bound_tys[i]);
            temp_cleanups += [bound.val];
          }
          env_direct(val, ty) {
            if copying {
                bcx = copy_val(bcx, INIT, bound.val,
                               load_if_immediate(bcx, val, ty), ty);
            } else { Store(bcx, val, bound.val); }
          }
        }
2747 2748
        i += 1u;
    }
2749
    for cleanup in temp_cleanups { revoke_clean(bcx, cleanup); }
2750 2751 2752

    // If necessary, copy tydescs describing type parameters into the
    // appropriate slot in the closure.
2753 2754
    // Silly check as well
    check type_is_tup_like(bcx, closure_ty);
2755
    let ty_params_slot =
2756
        GEP_tup_like(bcx, closure_ty, closure,
B
Brian Anderson 已提交
2757
                     [0, abi::closure_elt_ty_params]);
2758
    bcx = ty_params_slot.bcx;
2759
    i = 0u;
2760
    for td: ValueRef in lltydescs {
B
Brian Anderson 已提交
2761
        let ty_param_slot = GEPi(bcx, ty_params_slot.val, [0, i as int]);
2762
        Store(bcx, td, ty_param_slot);
2763 2764 2765
        i += 1u;
    }

2766
    ret {ptr: box, ptrty: closure_ty, bcx: bcx};
2767 2768
}

2769 2770
// Given a context and a list of upvars, build a closure. This just
// collects the upvars and packages them up for build_environment.
2771
fn build_closure(cx: @block_ctxt, upvars: @[ast::def], copying: bool) ->
B
Brian Anderson 已提交
2772
   {ptr: ValueRef, ptrty: ty::t, bcx: @block_ctxt} {
B
Brian Anderson 已提交
2773
    // If we need to, package up the iterator body to call
2774 2775 2776 2777 2778 2779
    let env_vals = alt cx.fcx.lliterbody {
      some(body) when !copying {
        [env_direct(body, option::get(cx.fcx.iterbodyty))]
      }
      _ { [] }
    };
B
Brian Anderson 已提交
2780
    // Package up the upvars
M
Marijn Haverbeke 已提交
2781
    for def in *upvars {
2782
        let val = trans_local_var(cx, def).val;
M
Marijn Haverbeke 已提交
2783
        let nid = ast_util::def_id_of_def(def).node;
B
Brian Anderson 已提交
2784 2785
        let ty = ty::node_id_to_monotype(bcx_tcx(cx), nid);
        if !copying { ty = ty::mk_mut_ptr(bcx_tcx(cx), ty); }
2786
        env_vals += [env_direct(val, ty)];
B
Brian Anderson 已提交
2787
    }
2788
    ret build_environment(cx, copy cx.fcx.lltydescs, env_vals, copying);
2789 2790
}

2791 2792 2793 2794 2795
// Return a pointer to the stored typarams in a closure.
// This is awful. Since the size of the bindings stored in the closure might
// be dynamically sized, we can't skip past them to get to the tydescs until
// we have loaded the tydescs. Thus we use the stored size of the bindings
// in the tydesc for the closure to skip over them. Ugh.
2796 2797
fn find_environment_tydescs(bcx: @block_ctxt, envty: ty::t, closure: ValueRef)
   -> ValueRef {
2798 2799
    ret if !ty::type_has_dynamic_size(bcx_tcx(bcx), envty) {

B
Brian Anderson 已提交
2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811
            // If we can find the typarams statically, do it
            GEPi(bcx, closure,
                 [0, abi::box_rc_field_body, abi::closure_elt_ty_params])
        } else {
            // Ugh. We need to load the size of the bindings out of the
            // closure's tydesc and use that to skip over the bindings.
            let descsty =
                ty::get_element_type(bcx_tcx(bcx), envty,
                                     abi::closure_elt_ty_params as uint);
            let llenv = GEPi(bcx, closure, [0, abi::box_rc_field_body]);
            // Load the tydesc and find the size of the body
            let lldesc =
B
Brian Anderson 已提交
2812
                Load(bcx, GEPi(bcx, llenv, [0, abi::closure_elt_tydesc]));
B
Brian Anderson 已提交
2813
            let llsz =
B
Brian Anderson 已提交
2814
                Load(bcx, GEPi(bcx, lldesc, [0, abi::tydesc_field_size]));
B
Brian Anderson 已提交
2815 2816 2817 2818 2819

            // Get the bindings pointer and add the size to it
            let llbinds = GEPi(bcx, llenv, [0, abi::closure_elt_bindings]);
            bump_ptr(bcx, descsty, llbinds, llsz)
        }
2820 2821
}

2822 2823 2824
// Given an enclosing block context, a new function context, a closure type,
// and a list of upvars, generate code to load and populate the environment
// with the upvars and type descriptors.
2825 2826
fn load_environment(enclosing_cx: @block_ctxt, fcx: @fn_ctxt, envty: ty::t,
                    upvars: @[ast::def], copying: bool) {
2827
    let bcx = new_raw_block_ctxt(fcx, fcx.llloadenv);
2828

2829
    let ty = ty::mk_imm_box(bcx_tcx(bcx), envty);
2830 2831 2832 2833 2834

    let ccx = bcx_ccx(bcx);
    let sp = bcx.sp;
    // FIXME: should have postcondition on mk_imm_box,
    // so this check won't be necessary
2835
    check (type_has_static_size(ccx, ty));
2836
    let llty = type_of(ccx, sp, ty);
2837
    let llclosure = PointerCast(bcx, fcx.llenv, llty);
2838

2839 2840 2841
    // Populate the type parameters from the environment. We need to
    // do this first because the tydescs are needed to index into
    // the bindings if they are dynamically sized.
B
Brian Anderson 已提交
2842
    let tydesc_count = std::vec::len(enclosing_cx.fcx.lltydescs);
2843 2844 2845
    let lltydescs = find_environment_tydescs(bcx, envty, llclosure);
    let i = 0u;
    while i < tydesc_count {
B
Brian Anderson 已提交
2846
        let lltydescptr = GEPi(bcx, lltydescs, [0, i as int]);
2847
        fcx.lltydescs += [Load(bcx, lltydescptr)];
2848 2849
        i += 1u;
    }
2850 2851

    // Populate the upvars from the environment.
B
Brian Anderson 已提交
2852
    let path = [0, abi::box_rc_field_body, abi::closure_elt_bindings];
2853
    i = 0u;
2854 2855 2856
    // If this is an aliasing closure/for-each body, we need to load
    // the iterbody.
    if !copying && !option::is_none(enclosing_cx.fcx.lliterbody) {
2857 2858
        // Silly check
        check type_is_tup_like(bcx, ty);
B
Brian Anderson 已提交
2859
        let iterbodyptr = GEP_tup_like(bcx, ty, llclosure, path + [0]);
2860
        fcx.lliterbody = some(Load(bcx, iterbodyptr.val));
2861
        bcx = iterbodyptr.bcx;
2862 2863
        i += 1u;
    }
B
Brian Anderson 已提交
2864

M
Marijn Haverbeke 已提交
2865 2866
    // Load the actual upvars.
    for upvar_def in *upvars {
2867 2868
        // Silly check
        check type_is_tup_like(bcx, ty);
B
Brian Anderson 已提交
2869
        let upvarptr = GEP_tup_like(bcx, ty, llclosure, path + [i as int]);
2870 2871
        bcx = upvarptr.bcx;
        let llupvarptr = upvarptr.val;
2872
        if !copying { llupvarptr = Load(bcx, llupvarptr); }
M
Marijn Haverbeke 已提交
2873
        let def_id = ast_util::def_id_of_def(upvar_def);
2874
        fcx.llupvars.insert(def_id.node, llupvarptr);
2875 2876 2877 2878
        i += 1u;
    }
}

2879
fn trans_for_each(cx: @block_ctxt, local: @ast::local, seq: @ast::expr,
2880
                  body: ast::blk) -> @block_ctxt {
2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902
    /*
     * The translation is a little .. complex here. Code like:
     *
     *    let ty1 p = ...;
     *
     *    let ty1 q = ...;
     *
     *    foreach (ty v in foo(a,b)) { body(p,q,v) }
     *
     *
     * Turns into a something like so (C/Rust mishmash):
     *
     *    type env = { *ty1 p, *ty2 q, ... };
     *
     *    let env e = { &p, &q, ... };
     *
     *    fn foreach123_body(env* e, ty v) { body(*(e->p),*(e->q),v) }
     *
     *    foo([foreach123_body, env*], a, b);
     *
     */

2903 2904
    // Step 1: Generate code to build an environment containing pointers
    // to all of the upvars
M
Marijn Haverbeke 已提交
2905
    let lcx = cx.fcx.lcx;
2906
    let ccx = lcx.ccx;
2907 2908

    // FIXME: possibly support alias-mode here?
2909 2910
    let decl_ty = node_id_type(ccx, local.node.id);
    let upvars = get_freevars(ccx.tcx, body.node.id);
2911

2912
    let llenv = build_closure(cx, upvars, false);
2913 2914

    // Step 2: Declare foreach body function.
B
Brian Anderson 已提交
2915
    let s: str =
2916
        mangle_internal_name_by_path_and_seq(ccx, lcx.path, "foreach");
2917

2918 2919 2920 2921 2922
    // The 'env' arg entering the body function is a fake env member (as in
    // the env-part of the normal rust calling convention) that actually
    // points to a stack allocated env in this frame. We bundle that env
    // pointer along with the foreach-body-fn pointer into a 'normal' fn pair
    // and pass it in as a first class fn-arg to the iterator.
2923 2924 2925
    let iter_body_fn = ty::mk_iter_body_fn(ccx.tcx, decl_ty);
    // FIXME: should be a postcondition on mk_iter_body_fn
    check returns_non_ty_var(ccx, iter_body_fn);
M
Marijn Haverbeke 已提交
2926
    let iter_body_llty =
2927
        type_of_fn_from_ty(ccx, cx.sp, iter_body_fn, 0u);
M
Marijn Haverbeke 已提交
2928
    let lliterbody: ValueRef =
2929
        decl_internal_cdecl_fn(ccx.llmod, s, iter_body_llty);
2930 2931
    let fcx = new_fn_ctxt_w_id(lcx, cx.sp, lliterbody, body.node.id,
                               ast::return_val);
2932
    fcx.iterbodyty = cx.fcx.iterbodyty;
2933

2934 2935
    // Generate code to load the environment out of the
    // environment pointer.
2936
    load_environment(cx, fcx, llenv.ptrty, upvars, false);
2937

M
Marijn Haverbeke 已提交
2938
    let bcx = new_top_block_ctxt(fcx);
2939
    // Add bindings for the loop variable alias.
B
Brian Anderson 已提交
2940 2941 2942 2943
    bcx =
        trans_alt::bind_irrefutable_pat(bcx, local.node.pat,
                                        llvm::LLVMGetParam(fcx.llfn, 3u),
                                        bcx.fcx.lllocals, false);
M
Marijn Haverbeke 已提交
2944
    let lltop = bcx.llbb;
2945
    let r = trans_block(bcx, body);
2946
    finish_fn(fcx, lltop);
2947

2948
    build_return(r.bcx);
2949

2950
    // Step 3: Call iter passing [lliterbody, llenv], plus other args.
M
Marijn Haverbeke 已提交
2951 2952 2953 2954
    alt seq.node {
      ast::expr_call(f, args) {
        let pair =
            create_real_fn_pair(cx, iter_body_llty, lliterbody, llenv.ptr);
2955 2956
        let r = trans_call(cx, f, some(pair), args, seq.id);
        ret r.res.bcx;
M
Marijn Haverbeke 已提交
2957
      }
2958
    }
2959 2960
}

2961 2962
fn trans_while(cx: @block_ctxt, cond: @ast::expr, body: ast::blk)
    -> @block_ctxt {
B
Brian Anderson 已提交
2963 2964 2965 2966 2967
    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");
2968
    let body_res = trans_block(body_cx, body);
M
Marijn Haverbeke 已提交
2969
    let cond_res = trans_expr(cond_cx, cond);
2970
    Br(body_res.bcx, cond_cx.llbb);
M
Marijn Haverbeke 已提交
2971
    let cond_bcx = trans_block_cleanups(cond_res.bcx, cond_cx);
2972 2973
    CondBr(cond_bcx, cond_res.val, body_cx.llbb, next_cx.llbb);
    Br(cx, cond_cx.llbb);
2974
    ret next_cx;
2975 2976
}

2977
fn trans_do_while(cx: @block_ctxt, body: ast::blk, cond: @ast::expr) ->
2978
    @block_ctxt {
B
Brian Anderson 已提交
2979
    let next_cx = new_sub_block_ctxt(cx, "next");
M
Marijn Haverbeke 已提交
2980
    let body_cx =
2981
        new_loop_scope_block_ctxt(cx, option::none::<@block_ctxt>, next_cx,
B
Brian Anderson 已提交
2982
                                  "do-while loop body");
2983
    let body_res = trans_block(body_cx, body);
M
Marijn Haverbeke 已提交
2984
    let cond_res = trans_expr(body_res.bcx, cond);
2985 2986
    CondBr(cond_res.bcx, cond_res.val, body_cx.llbb, next_cx.llbb);
    Br(cx, body_cx.llbb);
2987
    ret next_cx;
2988 2989
}

2990
type generic_info =
M
Marijn Haverbeke 已提交
2991
    {item_type: ty::t,
2992
     static_tis: [option::t<@tydesc_info>],
2993
     tydescs: [ValueRef]};
2994

2995 2996 2997
type lval_result = {bcx: @block_ctxt,
                    val: ValueRef,
                    is_mem: bool};
2998
tag callee_env { obj_env(ValueRef); null_env; is_closure; }
2999 3000 3001 3002 3003
type lval_maybe_callee = {bcx: @block_ctxt,
                          val: ValueRef,
                          is_mem: bool,
                          env: callee_env,
                          generic: option::t<generic_info>};
M
Marijn Haverbeke 已提交
3004

3005 3006 3007 3008
fn null_env_ptr(bcx: @block_ctxt) -> ValueRef {
    C_null(T_opaque_closure_ptr(*bcx_ccx(bcx)))
}

3009 3010 3011 3012 3013
fn lval_mem(bcx: @block_ctxt, val: ValueRef) -> lval_result {
    ret {bcx: bcx, val: val, is_mem: true};
}
fn lval_val(bcx: @block_ctxt, val: ValueRef) -> lval_result {
    ret {bcx: bcx, val: val, is_mem: false};
M
Marijn Haverbeke 已提交
3014 3015
}

3016 3017 3018
fn lval_no_env(bcx: @block_ctxt, val: ValueRef, is_mem: bool)
    -> lval_maybe_callee {
    ret {bcx: bcx, val: val, is_mem: is_mem, env: is_closure, generic: none};
M
Marijn Haverbeke 已提交
3019 3020
}

3021 3022
fn trans_external_path(cx: @block_ctxt, did: ast::def_id,
                       tpt: ty::ty_param_kinds_and_ty) -> ValueRef {
M
Marijn Haverbeke 已提交
3023 3024
    let lcx = cx.fcx.lcx;
    let name = csearch::get_symbol(lcx.ccx.sess.get_cstore(), did);
B
Brian Anderson 已提交
3025
    ret get_extern_const(lcx.ccx.externs, lcx.ccx.llmod, name,
3026
                         type_of_ty_param_kinds_and_ty(lcx, cx.sp, tpt));
3027 3028
}

3029 3030 3031
fn lval_static_fn(bcx: @block_ctxt, tpt: ty::ty_param_kinds_and_ty,
                  fn_id: ast::def_id, id: ast::node_id) -> lval_maybe_callee {
    let val = if fn_id.crate == ast::local_crate {
3032
        // Internal reference.
3033 3034
        assert (bcx_ccx(bcx).item_ids.contains_key(fn_id.node));
        bcx_ccx(bcx).item_ids.get(fn_id.node)
3035 3036
    } else {
        // External reference.
3037 3038 3039 3040
        trans_external_path(bcx, fn_id, tpt)
    };
    let tys = ty::node_id_to_type_params(bcx_tcx(bcx), id);
    let gen = none;
3041
    if std::vec::len::<ty::t>(tys) != 0u {
3042 3043
        let tydescs = [], tis = [];
        for t in tys {
3044
            // TODO: Doesn't always escape.
3045
            let ti = none;
3046
            let td = get_tydesc(bcx, t, true, tps_normal, ti).result;
B
Brian Anderson 已提交
3047
            tis += [ti];
3048
            bcx = td.bcx;
B
Brian Anderson 已提交
3049
            tydescs += [td.val];
3050
        }
3051
        gen = some({item_type: tpt.ty, static_tis: tis, tydescs: tydescs});
3052
    }
3053
    ret {bcx: bcx, val: val, is_mem: true, env: null_env, generic: gen};
3054 3055
}

3056
fn lookup_discriminant(lcx: @local_ctxt, vid: ast::def_id) -> ValueRef {
M
Marijn Haverbeke 已提交
3057 3058 3059 3060 3061
    alt lcx.ccx.discrims.find(vid.node) {
      none. {
        // It's an external discriminant that we haven't seen yet.
        assert (vid.crate != ast::local_crate);
        let sym = csearch::get_symbol(lcx.ccx.sess.get_cstore(), vid);
B
Brian Anderson 已提交
3062 3063 3064 3065 3066
        let gvar =
            str::as_buf(sym,
                        {|buf|
                            llvm::LLVMAddGlobal(lcx.ccx.llmod, T_int(), buf)
                        });
M
Marijn Haverbeke 已提交
3067 3068 3069 3070 3071 3072 3073
        llvm::LLVMSetLinkage(gvar,
                             lib::llvm::LLVMExternalLinkage as llvm::Linkage);
        llvm::LLVMSetGlobalConstant(gvar, True);
        lcx.ccx.discrims.insert(vid.node, gvar);
        ret gvar;
      }
      some(llval) { ret llval; }
3074 3075 3076
    }
}

3077
fn trans_local_var(cx: @block_ctxt, def: ast::def) -> lval_result {
M
Marijn Haverbeke 已提交
3078 3079
    alt def {
      ast::def_upvar(did, _, _) {
3080 3081 3082
        assert (cx.fcx.llupvars.contains_key(did.node));
        ret lval_mem(cx, cx.fcx.llupvars.get(did.node));
      }
M
Marijn Haverbeke 已提交
3083
      ast::def_arg(did, _) {
3084 3085
        assert (cx.fcx.llargs.contains_key(did.node));
        ret lval_mem(cx, cx.fcx.llargs.get(did.node));
M
Marijn Haverbeke 已提交
3086
      }
3087
      ast::def_local(did, _) {
3088 3089
        assert (cx.fcx.lllocals.contains_key(did.node));
        ret lval_mem(cx, cx.fcx.lllocals.get(did.node));
M
Marijn Haverbeke 已提交
3090
      }
M
Marijn Haverbeke 已提交
3091
      ast::def_binding(did) {
3092 3093
        assert (cx.fcx.lllocals.contains_key(did.node));
        ret lval_mem(cx, cx.fcx.lllocals.get(did.node));
M
Marijn Haverbeke 已提交
3094
      }
M
Marijn Haverbeke 已提交
3095
      ast::def_obj_field(did, _) {
M
Marijn Haverbeke 已提交
3096 3097 3098
        assert (cx.fcx.llobjfields.contains_key(did.node));
        ret lval_mem(cx, cx.fcx.llobjfields.get(did.node));
      }
M
Marijn Haverbeke 已提交
3099
      _ {
3100 3101
        bcx_ccx(cx).sess.span_unimpl
            (cx.sp, "unsupported def type in trans_local_def");
M
Marijn Haverbeke 已提交
3102 3103 3104 3105
      }
    }
}

3106 3107 3108 3109 3110 3111 3112
fn trans_path(cx: @block_ctxt, p: ast::path, id: ast::node_id)
    -> 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 {
M
Marijn Haverbeke 已提交
3113 3114
    let ccx = bcx_ccx(cx);
    alt def {
3115
      ast::def_fn(did, _) | ast::def_native_fn(did) {
M
Marijn Haverbeke 已提交
3116
        let tyt = ty::lookup_item_type(ccx.tcx, did);
3117
        ret lval_static_fn(cx, tyt, did, id);
M
Marijn Haverbeke 已提交
3118
      }
M
Marijn Haverbeke 已提交
3119
      ast::def_variant(tid, vid) {
M
Marijn Haverbeke 已提交
3120 3121 3122 3123
        let v_tyt = ty::lookup_item_type(ccx.tcx, vid);
        alt ty::struct(ccx.tcx, v_tyt.ty) {
          ty::ty_fn(_, _, _, _, _) {
            // N-ary variant.
3124
            ret lval_static_fn(cx, v_tyt, vid, id);
M
Marijn Haverbeke 已提交
3125 3126 3127 3128 3129 3130
          }
          _ {
            // Nullary variant.
            let tag_ty = node_id_type(ccx, id);
            let alloc_result = alloc_ty(cx, tag_ty);
            let lltagblob = alloc_result.val;
3131
            let lltagty = type_of_tag(ccx, sp, tid, tag_ty);
M
Marijn Haverbeke 已提交
3132
            let bcx = alloc_result.bcx;
3133
            let lltagptr = PointerCast(bcx, lltagblob, T_ptr(lltagty));
B
Brian Anderson 已提交
3134
            if std::vec::len(ty::tag_variants(ccx.tcx, tid)) != 1u {
3135
                let lldiscrim_gv = lookup_discriminant(bcx.fcx.lcx, vid);
3136
                let lldiscrim = Load(bcx, lldiscrim_gv);
B
Brian Anderson 已提交
3137
                let lldiscrimptr = GEP(bcx, lltagptr, [C_int(0), C_int(0)]);
3138
                Store(bcx, lldiscrim, lldiscrimptr);
G
Graydon Hoare 已提交
3139
            }
3140
            ret lval_no_env(bcx, lltagptr, false);
3141
          }
3142
        }
M
Marijn Haverbeke 已提交
3143
      }
M
Marijn Haverbeke 已提交
3144
      ast::def_const(did) {
M
Marijn Haverbeke 已提交
3145 3146
        if did.crate == ast::local_crate {
            assert (ccx.consts.contains_key(did.node));
3147
            ret lval_no_env(cx, ccx.consts.get(did.node), true);
M
Marijn Haverbeke 已提交
3148 3149
        } else {
            let tp = ty::node_id_to_monotype(ccx.tcx, id);
B
Brian Anderson 已提交
3150
            let k: [ast::kind] = [];
3151 3152
            let val = trans_external_path(cx, did, {kinds: k, ty: tp});
            ret lval_no_env(cx, load_if_immediate(cx, val, tp), false);
3153
        }
M
Marijn Haverbeke 已提交
3154
      }
3155 3156 3157 3158
      _ {
        let loc = trans_local_var(cx, def);
        ret lval_no_env(loc.bcx, loc.val, loc.is_mem);
      }
3159 3160 3161
    }
}

3162 3163 3164 3165 3166
fn trans_field(cx: @block_ctxt, sp: span, base: @ast::expr,
               field: ast::ident) -> lval_maybe_callee {
    let {bcx, val} = trans_expr(cx, base);
    ret trans_field_inner(bcx, sp, val, ty::expr_ty(bcx_tcx(cx), base),
                          field);
3167 3168
}

3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185
fn trans_field_inner(cx: @block_ctxt, sp: span, v: ValueRef, t0: ty::t,
                     field: ast::ident) -> lval_maybe_callee {
    let r = autoderef(cx, v, t0);
    let t = r.ty;
    alt ty::struct(bcx_tcx(cx), t) {
      ty::ty_rec(fields) {
        let ix: uint = ty::field_idx(bcx_ccx(cx).sess, sp, field, fields);
        let r_bcx = r.bcx;
        // Silly check
        check type_is_tup_like(r_bcx, t);
        let v = GEP_tup_like(r_bcx, t, r.val, [0, ix as int]);
        ret lval_no_env(v.bcx, v.val, true);
      }
      ty::ty_obj(methods) {
        let ix: uint = ty::method_idx(bcx_ccx(cx).sess, sp, field, methods);
        let vtbl = GEP(r.bcx, r.val, [C_int(0), C_int(abi::obj_field_vtbl)]);
        vtbl = Load(r.bcx, vtbl);
3186

3187 3188
        let vtbl_type = T_ptr(T_array(T_ptr(T_nil()), ix + 1u));
        vtbl = PointerCast(cx, vtbl, vtbl_type);
3189

3190 3191 3192
        let v = GEP(r.bcx, vtbl, [C_int(0), C_int(ix as int)]);
        let tcx = bcx_tcx(cx);
        let ccx = bcx_ccx(cx);
3193

3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209
        let fn_ty: ty::t = ty::method_ty_to_fn_ty(tcx, methods[ix]);
        let ret_ty = ty::ty_fn_ret(tcx, fn_ty);
        let ret_ref = ast_util::ret_by_ref(ty::ty_fn_ret_style(tcx, fn_ty));
        // FIXME: constrain ty_obj?
        check non_ty_var(ccx, ret_ty);

        let ll_fn_ty =
            type_of_fn(ccx, sp, ty::ty_fn_proto(tcx, fn_ty),
                       true, ret_ref, ty::ty_fn_args(tcx, fn_ty),
                       ret_ty, 0u);
        v = Load(r.bcx, PointerCast(r.bcx, v, T_ptr(T_ptr(ll_fn_ty))));
        ret {bcx: r.bcx, val: v, is_mem: true,
             env: obj_env(r.val), generic: none};
      }
      _ { bcx_ccx(cx).sess.unimpl("field variant in trans_field"); }
    }
3210 3211
}

3212 3213
fn trans_index(cx: @block_ctxt, sp: span, base: @ast::expr, idx: @ast::expr,
               id: ast::node_id) -> lval_result {
3214
    // Is this an interior vector?
3215

M
Marijn Haverbeke 已提交
3216 3217 3218 3219 3220 3221
    let base_ty = ty::expr_ty(bcx_tcx(cx), base);
    let exp = trans_expr(cx, base);
    let lv = autoderef(exp.bcx, exp.val, base_ty);
    let ix = trans_expr(lv.bcx, idx);
    let v = lv.val;
    let bcx = ix.bcx;
3222
    // Cast to an LLVM integer. Rust is less strict than LLVM in this regard.
3223

M
Marijn Haverbeke 已提交
3224 3225 3226 3227
    let ix_val;
    let ix_size = llsize_of_real(bcx_ccx(cx), val_ty(ix.val));
    let int_size = llsize_of_real(bcx_ccx(cx), T_int());
    if ix_size < int_size {
3228
        ix_val = ZExt(bcx, ix.val, T_int());
B
Brian Anderson 已提交
3229
    } else if ix_size > int_size {
3230
        ix_val = Trunc(bcx, ix.val, T_int());
3231
    } else { ix_val = ix.val; }
M
Marijn Haverbeke 已提交
3232 3233
    let unit_ty = node_id_type(bcx_ccx(cx), id);
    let unit_sz = size_of(bcx, unit_ty);
3234
    bcx = unit_sz.bcx;
B
Brian Anderson 已提交
3235
    maybe_name_value(bcx_ccx(cx), unit_sz.val, "unit_sz");
3236
    let scaled_ix = Mul(bcx, ix_val, unit_sz.val);
B
Brian Anderson 已提交
3237
    maybe_name_value(bcx_ccx(cx), scaled_ix, "scaled_ix");
3238 3239
    let lim = tvec::get_fill(bcx, v);
    let body = tvec::get_dataptr(bcx, v, type_of_or_i8(bcx, unit_ty));
3240
    let bounds_check = ICmp(bcx, lib::llvm::LLVMIntULT, scaled_ix, lim);
B
Brian Anderson 已提交
3241 3242
    let fail_cx = new_sub_block_ctxt(bcx, "fail");
    let next_cx = new_sub_block_ctxt(bcx, "next");
3243
    let ncx = bcx_ccx(next_cx);
3244
    CondBr(bcx, bounds_check, next_cx.llbb, fail_cx.llbb);
3245 3246
    // fail: bad bounds check.

B
Brian Anderson 已提交
3247
    trans_fail(fail_cx, some::<span>(sp), "bounds check");
3248 3249 3250 3251 3252 3253 3254 3255 3256
    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])
        };
3257

3258
    ret lval_mem(next_cx, elt);
3259 3260
}

3261
fn trans_callee(cx: @block_ctxt, e: @ast::expr) -> lval_maybe_callee {
3262
    alt e.node {
3263
      ast::expr_path(p) { ret trans_path(cx, p, e.id); }
3264
      ast::expr_field(base, ident) {
3265
        ret trans_field(cx, e.span, base, ident);
3266 3267
      }
      ast::expr_self_method(ident) {
3268
        alt cx.fcx.llself {
3269
          some(pair) {
3270
            ret trans_field_inner(cx, e.span, pair.v, pair.t, ident);
3271 3272 3273
          }
        }
      }
3274 3275 3276 3277
      _ {
        let lv = trans_lval(cx, e);
        ret lval_no_env(lv.bcx, lv.val, lv.is_mem);
      }
3278 3279 3280
    }
}

3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299
fn expr_is_lval(tcx: ty::ctxt, e: @ast::expr) -> bool {
    alt e.node {
      ast::expr_path(_) | ast::expr_index(_, _) |
      ast::expr_unary(ast::deref., _) { true }
      ast::expr_field(base, ident) {
        let basety = ty::type_autoderef(tcx, ty::expr_ty(tcx, base));
        alt ty::struct(tcx, basety) {
          ty::ty_obj(_) { false }
          ty::ty_rec(_) { true }
        }
      }
      ast::expr_call(f, _) {
          let fty = ty::expr_ty(tcx, f);
          ast_util::ret_by_ref(ty::ty_fn_ret_style(tcx, fty))
      }
      _ { false }
    }
}

3300 3301 3302
// 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).
3303
fn trans_lval(cx: @block_ctxt, e: @ast::expr) -> lval_result {
M
Marijn Haverbeke 已提交
3304
    alt e.node {
3305 3306 3307 3308
      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));
      }
M
Marijn Haverbeke 已提交
3309
      ast::expr_field(base, ident) {
3310 3311
        let f = trans_field(cx, e.span, base, ident);
        ret lval_maybe_callee_to_lval(f, ty::expr_ty(bcx_tcx(cx), e));
M
Marijn Haverbeke 已提交
3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322
      }
      ast::expr_index(base, idx) {
        ret trans_index(cx, e.span, base, idx, e.id);
      }
      ast::expr_unary(ast::deref., base) {
        let ccx = bcx_ccx(cx);
        let sub = trans_expr(cx, base);
        let t = ty::expr_ty(ccx.tcx, base);
        let val =
            alt ty::struct(ccx.tcx, t) {
              ty::ty_box(_) {
3323
                InBoundsGEP(sub.bcx, sub.val,
B
Brian Anderson 已提交
3324
                            [C_int(0), C_int(abi::box_rc_field_body)])
M
Marijn Haverbeke 已提交
3325 3326
              }
              ty::ty_res(_, _, _) {
3327
                InBoundsGEP(sub.bcx, sub.val, [C_int(0), C_int(1)])
M
Marijn Haverbeke 已提交
3328 3329 3330
              }
              ty::ty_tag(_, _) {
                let ety = ty::expr_ty(ccx.tcx, e);
3331
                let sp = e.span;
3332 3333 3334 3335
                let ellty =
                    if check type_has_static_size(ccx, ety) {
                        T_ptr(type_of(ccx, sp, ety))
                    } else { T_typaram_ptr(ccx.tn) };
3336
                PointerCast(sub.bcx, sub.val, ellty)
M
Marijn Haverbeke 已提交
3337
              }
3338
              ty::ty_ptr(_) | ty::ty_uniq(_) { sub.val }
3339
            };
M
Marijn Haverbeke 已提交
3340 3341
        ret lval_mem(sub.bcx, val);
      }
3342
      ast::expr_call(f, args) {
3343 3344 3345 3346
        let {res: {bcx, val}, by_ref} =
            trans_call(cx, f, none, args, e.id);
        if by_ref { ret lval_mem(bcx, val); }
        else { ret lval_val(bcx, val); }
3347
      }
M
Marijn Haverbeke 已提交
3348
      _ {
3349 3350
        let res = trans_expr(cx, e);
        ret lval_val(res.bcx, res.val);
M
Marijn Haverbeke 已提交
3351
      }
3352 3353 3354
    }
}

3355 3356
fn maybe_add_env(bcx: @block_ctxt, c: lval_maybe_callee)
    -> (bool, ValueRef) {
3357 3358 3359 3360 3361 3362
    alt c.env {
      is_closure. { (c.is_mem, c.val) }
      obj_env(_) {
        fail "Taking the value of a method does not work yet (issue #435)";
      }
      null_env. {
3363
        let llfnty = llvm::LLVMGetElementType(val_ty(c.val));
3364 3365
        (false, create_real_fn_pair(bcx, llfnty, c.val, null_env_ptr(bcx)))
      }
3366 3367 3368 3369 3370
    }
}

fn lval_maybe_callee_to_lval(c: lval_maybe_callee, ty: ty::t) -> lval_result {
    alt c.generic {
M
Marijn Haverbeke 已提交
3371
      some(gi) {
3372
        let n_args = std::vec::len(ty::ty_fn_args(bcx_tcx(c.bcx), ty));
3373
        let args = std::vec::init_elt(none::<@ast::expr>, n_args);
3374 3375 3376 3377 3378
        let space = alloc_ty(c.bcx, ty);
        let bcx = trans_bind_1(space.bcx, ty, c, args, ty,
                               save_in(space.val));
        add_clean_temp(bcx, space.val, ty);
        ret lval_val(bcx, space.val);
3379 3380 3381 3382
      }
      none. {
        let (is_mem, val) = maybe_add_env(c.bcx, c);
        ret {bcx: c.bcx, val: val, is_mem: is_mem};
M
Marijn Haverbeke 已提交
3383 3384 3385 3386
      }
    }
}

3387
fn int_cast(bcx: @block_ctxt, lldsttype: TypeRef, llsrctype: TypeRef,
M
Marijn Haverbeke 已提交
3388 3389 3390 3391
            llsrc: ValueRef, signed: bool) -> ValueRef {
    let srcsz = llvm::LLVMGetIntTypeWidth(llsrctype);
    let dstsz = llvm::LLVMGetIntTypeWidth(lldsttype);
    ret if dstsz == srcsz {
3392
            BitCast(bcx, llsrc, lldsttype)
B
Brian Anderson 已提交
3393
        } else if srcsz > dstsz {
3394
            TruncOrBitCast(bcx, llsrc, lldsttype)
B
Brian Anderson 已提交
3395
        } else if signed {
3396 3397
            SExtOrBitCast(bcx, llsrc, lldsttype)
        } else { ZExtOrBitCast(bcx, llsrc, lldsttype) };
M
Marijn Haverbeke 已提交
3398 3399
}

3400
fn float_cast(bcx: @block_ctxt, lldsttype: TypeRef, llsrctype: TypeRef,
M
Marijn Haverbeke 已提交
3401 3402 3403 3404
              llsrc: ValueRef) -> ValueRef {
    let srcsz = lib::llvm::float_width(llsrctype);
    let dstsz = lib::llvm::float_width(lldsttype);
    ret if dstsz > srcsz {
3405
            FPExt(bcx, llsrc, lldsttype)
B
Brian Anderson 已提交
3406
        } else if srcsz > dstsz {
3407
            FPTrunc(bcx, llsrc, lldsttype)
M
Marijn Haverbeke 已提交
3408 3409 3410
        } else { llsrc };
}

3411 3412
fn trans_cast(cx: @block_ctxt, e: @ast::expr, id: ast::node_id,
              dest: dest) -> @block_ctxt {
M
Marijn Haverbeke 已提交
3413 3414 3415 3416 3417
    let ccx = bcx_ccx(cx);
    let e_res = trans_expr(cx, e);
    let ll_t_in = val_ty(e_res.val);
    let t_in = ty::expr_ty(ccx.tcx, e);
    let t_out = node_id_type(ccx, id);
3418 3419
    // Check should be avoidable because it's a cast.
    // FIXME: Constrain types so as to avoid this check.
3420
    check (type_has_static_size(ccx, t_out));
M
Marijn Haverbeke 已提交
3421
    let ll_t_out = type_of(ccx, e.span, t_out);
3422 3423

    tag kind { native_; integral; float; other; }
3424
    fn t_kind(tcx: ty::ctxt, t: ty::t) -> kind {
M
Marijn Haverbeke 已提交
3425 3426
        ret if ty::type_is_fp(tcx, t) {
                float
B
Brian Anderson 已提交
3427
            } else if ty::type_is_native(tcx, t) {
M
Marijn Haverbeke 已提交
3428
                native_
B
Brian Anderson 已提交
3429
            } else if ty::type_is_integral(tcx, t) {
M
Marijn Haverbeke 已提交
3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446
                integral
            } 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} {
          {in: integral., out: integral.} {
            int_cast(e_res.bcx, ll_t_out, ll_t_in, e_res.val, s_in)
          }
          {in: float., out: float.} {
            float_cast(e_res.bcx, ll_t_out, ll_t_in, e_res.val)
          }
          {in: integral., out: float.} {
            if s_in {
3447 3448
                SIToFP(e_res.bcx, e_res.val, ll_t_out)
            } else { UIToFP(e_res.bcx, e_res.val, ll_t_out) }
M
Marijn Haverbeke 已提交
3449 3450 3451
          }
          {in: float., out: integral.} {
            if ty::type_is_signed(ccx.tcx, t_out) {
3452 3453
                FPToSI(e_res.bcx, e_res.val, ll_t_out)
            } else { FPToUI(e_res.bcx, e_res.val, ll_t_out) }
M
Marijn Haverbeke 已提交
3454 3455
          }
          {in: integral., out: native_.} {
3456
            IntToPtr(e_res.bcx, e_res.val, ll_t_out)
M
Marijn Haverbeke 已提交
3457 3458
          }
          {in: native_., out: integral.} {
3459
            PtrToInt(e_res.bcx, e_res.val, ll_t_out)
M
Marijn Haverbeke 已提交
3460 3461
          }
          {in: native_., out: native_.} {
3462
            PointerCast(e_res.bcx, e_res.val, ll_t_out)
M
Marijn Haverbeke 已提交
3463
          }
B
Brian Anderson 已提交
3464
          _ { ccx.sess.bug("Translating unsupported cast.") }
M
Marijn Haverbeke 已提交
3465
        };
3466
    ret store_in_dest(e_res.bcx, newval, dest);
3467 3468
}

3469
// pth is cx.path
3470 3471
fn trans_bind_thunk(cx: @local_ctxt, sp: span, incoming_fty: ty::t,
                    outgoing_fty: ty::t, args: [option::t<@ast::expr>],
3472
                    env_ty: ty::t, ty_param_count: uint,
3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483
                    target_fn: option::t<ValueRef>)
    -> {val: ValueRef, ty: TypeRef} {
// If we supported constraints on record fields, we could make the
// constraints for this function:
/*
    : returns_non_ty_var(ccx, outgoing_fty),
      type_has_static_size(ccx, incoming_fty) ->
*/
// but since we don't, we have to do the checks at the beginning.
          let ccx = cx.ccx;
          check type_has_static_size(ccx, incoming_fty);
3484

L
Lindsey Kuper 已提交
3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506
    // Here we're not necessarily constructing a thunk in the sense of
    // "function with no arguments".  The result of compiling 'bind f(foo,
    // bar, baz)' would be a thunk that, when called, applies f to those
    // arguments and returns the result.  But we're stretching the meaning of
    // the word "thunk" here to also mean the result of compiling, say, 'bind
    // f(foo, _, baz)', or any other bind expression that binds f and leaves
    // some (or all) of the arguments unbound.

    // Here, 'incoming_fty' is the type of the entire bind expression, while
    // 'outgoing_fty' is the type of the function that is having some of its
    // arguments bound.  If f is a function that takes three arguments of type
    // int and returns int, and we're translating, say, 'bind f(3, _, 5)',
    // then outgoing_fty is the type of f, which is (int, int, int) -> int,
    // and incoming_fty is the type of 'bind f(3, _, 5)', which is int -> int.

    // Once translated, the entire bind expression will be the call f(foo,
    // bar, baz) wrapped in a (so-called) thunk that takes 'bar' as its
    // argument and that has bindings of 'foo' to 3 and 'baz' to 5 and a
    // pointer to 'f' all saved in its environment.  So, our job is to
    // construct and return that thunk.

    // Give the thunk a name, type, and value.
3507 3508
    let s: str = mangle_internal_name_by_path_and_seq(ccx, cx.path, "thunk");
    let llthunk_ty: TypeRef = get_pair_fn_ty(type_of(ccx, sp, incoming_fty));
3509
    let llthunk: ValueRef = decl_internal_cdecl_fn(ccx.llmod, s, llthunk_ty);
L
Lindsey Kuper 已提交
3510 3511 3512

    // Create a new function context and block context for the thunk, and hold
    // onto a pointer to the first block in the function for later use.
M
Marijn Haverbeke 已提交
3513 3514 3515
    let fcx = new_fn_ctxt(cx, sp, llthunk);
    let bcx = new_top_block_ctxt(fcx);
    let lltop = bcx.llbb;
3516 3517 3518
    // Since we might need to construct derived tydescs that depend on
    // our bound tydescs, we need to load tydescs out of the environment
    // before derived tydescs are constructed. To do this, we load them
3519 3520
    // in the load_env block.
    let load_env_bcx = new_raw_block_ctxt(fcx, fcx.llloadenv);
L
Lindsey Kuper 已提交
3521 3522 3523 3524 3525 3526 3527

    // The 'llenv' that will arrive in the thunk we're creating is an
    // environment that will contain the values of its arguments and a pointer
    // to the original function.  So, let's create one of those:

    // The llenv pointer needs to be the correct size.  That size is
    // 'closure_ty', which was determined by trans_bind.
3528 3529 3530
    let closure_ty = ty::mk_imm_box(ccx.tcx, env_ty);
    // FIXME: would be nice to have a postcondition on mk_imm_box
    // (Issue #586)
3531
    check (type_has_static_size(ccx, closure_ty));
3532
    let llclosure_ptr_ty = type_of(ccx, sp, closure_ty);
3533
    let llclosure = PointerCast(load_env_bcx, fcx.llenv, llclosure_ptr_ty);
L
Lindsey Kuper 已提交
3534 3535 3536 3537

    // "target", in this context, means the function that's having some of its
    // arguments bound and that will be called inside the thunk we're
    // creating.  (In our running example, target is the function f.)  Pick
3538 3539
    // out the pointer to the target function from the environment. The
    // target function lives in the first binding spot.
3540
    let (lltargetfn, lltargetenv, starting_idx) = alt target_fn {
3541
      some(fptr) { (fptr, llvm::LLVMGetUndef(T_opaque_closure_ptr(*ccx)), 0) }
3542
      none. {
3543 3544
        // Silly check
        check type_is_tup_like(bcx, closure_ty);
3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556
        let {bcx: cx, val: pair} =
            GEP_tup_like(bcx, closure_ty, llclosure,
                         [0, abi::box_rc_field_body,
                          abi::closure_elt_bindings, 0]);
        let lltargetenv =
            Load(cx, GEP(cx, pair, [C_int(0), C_int(abi::fn_field_box)]));
        let lltargetfn = Load
            (cx, GEP(cx, pair, [C_int(0), C_int(abi::fn_field_code)]));
        bcx = cx;
        (lltargetfn, lltargetenv, 1)
      }
    };
L
Lindsey Kuper 已提交
3557 3558 3559 3560 3561 3562

    // And then, pick out the target function's own environment.  That's what
    // we'll use as the environment the thunk gets.

    // Get f's return type, which will also be the return type of the entire
    // bind expression.
M
Marijn Haverbeke 已提交
3563
    let outgoing_ret_ty = ty::ty_fn_ret(cx.ccx.tcx, outgoing_fty);
L
Lindsey Kuper 已提交
3564 3565

    // Get the types of the arguments to f.
M
Marijn Haverbeke 已提交
3566
    let outgoing_args = ty::ty_fn_args(cx.ccx.tcx, outgoing_fty);
L
Lindsey Kuper 已提交
3567 3568

    // The 'llretptr' that will arrive in the thunk we're creating also needs
3569
    // to be the correct type.  Cast it to f's return type, if necessary.
M
Marijn Haverbeke 已提交
3570
    let llretptr = fcx.llretptr;
3571 3572 3573 3574
    let ccx = cx.ccx;
    if ty::type_contains_params(ccx.tcx, outgoing_ret_ty) {
        check non_ty_var(ccx, outgoing_ret_ty);
        let llretty = type_of_inner(ccx, sp, outgoing_ret_ty);
3575
        llretptr = PointerCast(bcx, llretptr, T_ptr(llretty));
3576
    }
L
Lindsey Kuper 已提交
3577 3578

    // Set up the three implicit arguments to the thunk.
3579
    let llargs: [ValueRef] = [llretptr, fcx.lltaskptr, lltargetenv];
3580

L
Lindsey Kuper 已提交
3581
    // Copy in the type parameters.
M
Marijn Haverbeke 已提交
3582 3583
    let i: uint = 0u;
    while i < ty_param_count {
3584
        // Silly check
3585
        check type_is_tup_like(load_env_bcx, closure_ty);
M
Marijn Haverbeke 已提交
3586
        let lltyparam_ptr =
3587
            GEP_tup_like(load_env_bcx, closure_ty, llclosure,
B
Brian Anderson 已提交
3588 3589
                         [0, abi::box_rc_field_body,
                          abi::closure_elt_ty_params, i as int]);
3590 3591
        load_env_bcx = lltyparam_ptr.bcx;
        let td = Load(load_env_bcx, lltyparam_ptr.val);
B
Brian Anderson 已提交
3592 3593
        llargs += [td];
        fcx.lltydescs += [td];
3594 3595
        i += 1u;
    }
L
Lindsey Kuper 已提交
3596

M
Marijn Haverbeke 已提交
3597
    let a: uint = 3u; // retptr, task ptr, env come first
3598
    let b: int = starting_idx;
M
Marijn Haverbeke 已提交
3599
    let outgoing_arg_index: uint = 0u;
3600
    let llout_arg_tys: [TypeRef] =
3601
        type_of_explicit_args(cx.ccx, sp, outgoing_args);
3602
    for arg: option::t<@ast::expr> in args {
B
Brian Anderson 已提交
3603 3604
        let out_arg = outgoing_args[outgoing_arg_index];
        let llout_arg_ty = llout_arg_tys[outgoing_arg_index];
M
Marijn Haverbeke 已提交
3605 3606 3607 3608
        alt arg {
          // Arg provided at binding time; thunk copies it from
          // closure.
          some(e) {
3609 3610
            // Silly check
            check type_is_tup_like(bcx, closure_ty);
M
Marijn Haverbeke 已提交
3611 3612
            let bound_arg =
                GEP_tup_like(bcx, closure_ty, llclosure,
B
Brian Anderson 已提交
3613 3614
                             [0, abi::box_rc_field_body,
                              abi::closure_elt_bindings, b]);
M
Marijn Haverbeke 已提交
3615 3616
            bcx = bound_arg.bcx;
            let val = bound_arg.val;
3617 3618 3619
            // If the type is parameterized, then we need to cast the
            // type we actually have to the parameterized out type.
            if ty::type_contains_params(cx.ccx.tcx, out_arg.ty) {
3620
                val = PointerCast(bcx, val, llout_arg_ty);
3621
            }
B
Brian Anderson 已提交
3622
            llargs += [val];
M
Marijn Haverbeke 已提交
3623 3624 3625 3626 3627
            b += 1;
          }

          // Arg will be provided when the thunk is invoked.
          none. {
3628
            let arg: ValueRef = llvm::LLVMGetParam(llthunk, a);
M
Marijn Haverbeke 已提交
3629
            if ty::type_contains_params(cx.ccx.tcx, out_arg.ty) {
3630
                arg = PointerCast(bcx, arg, llout_arg_ty);
M
Marijn Haverbeke 已提交
3631
            }
B
Brian Anderson 已提交
3632
            llargs += [arg];
M
Marijn Haverbeke 已提交
3633 3634
            a += 1u;
          }
3635
        }
3636
        outgoing_arg_index += 1u;
3637
    }
3638

3639 3640 3641 3642
    // Cast the outgoing function to the appropriate type.
    // This is necessary because the type of the function that we have
    // in the closure does not know how many type descriptors the function
    // needs to take.
3643 3644 3645
    let ccx = bcx_ccx(bcx);

    check returns_non_ty_var(ccx, outgoing_fty);
M
Marijn Haverbeke 已提交
3646
    let lltargetty =
3647
        type_of_fn_from_ty(ccx, sp, outgoing_fty, ty_param_count);
3648
    lltargetfn = PointerCast(bcx, lltargetfn, T_ptr(lltargetty));
3649
    Call(bcx, lltargetfn, llargs);
3650
    build_return(bcx);
3651
    finish_fn(fcx, lltop);
3652
    ret {val: llthunk, ty: llthunk_ty};
3653 3654
}

3655
fn trans_bind(cx: @block_ctxt, f: @ast::expr, args: [option::t<@ast::expr>],
3656
              id: ast::node_id, dest: dest) -> @block_ctxt {
3657 3658
    let f_res = trans_callee(cx, f);
    ret trans_bind_1(cx, ty::expr_ty(bcx_tcx(cx), f), f_res, args,
3659
                     ty::node_id_to_type(bcx_tcx(cx), id), dest);
3660 3661
}

3662 3663
fn trans_bind_1(cx: @block_ctxt, outgoing_fty: ty::t,
                f_res: lval_maybe_callee,
3664 3665
                args: [option::t<@ast::expr>], pair_ty: ty::t,
                dest: dest) -> @block_ctxt {
B
Brian Anderson 已提交
3666
    let bound: [@ast::expr] = [];
3667
    for argopt: option::t<@ast::expr> in args {
B
Brian Anderson 已提交
3668
        alt argopt { none. { } some(e) { bound += [e]; } }
3669
    }
3670 3671 3672 3673 3674
    let bcx = f_res.bcx;
    if dest == ignore {
        for ex in bound { bcx = trans_expr_dps(bcx, ex, ignore); }
        ret bcx;
    }
3675

3676
    // Figure out which tydescs we need to pass, if any.
3677
    let outgoing_fty_real; // the type with typarams still in it
3678
    let lltydescs: [ValueRef];
M
Marijn Haverbeke 已提交
3679
    alt f_res.generic {
B
Brian Anderson 已提交
3680
      none. { outgoing_fty_real = outgoing_fty; lltydescs = []; }
M
Marijn Haverbeke 已提交
3681
      some(ginfo) {
3682
        lazily_emit_all_generic_info_tydesc_glues(cx, ginfo);
3683
        outgoing_fty_real = ginfo.item_type;
3684 3685 3686
        lltydescs = ginfo.tydescs;
      }
    }
L
Lindsey Kuper 已提交
3687

B
Brian Anderson 已提交
3688 3689
    let ty_param_count = std::vec::len(lltydescs);
    if std::vec::len(bound) == 0u && ty_param_count == 0u {
3690 3691
        // Trivial 'binding': just return the closure
        let lv = lval_maybe_callee_to_lval(f_res, pair_ty);
3692 3693
        bcx = lv.bcx;
        // FIXME[DPS] factor this out
3694 3695
        let {bcx, val: addr} = get_dest_addr(bcx, dest);
        ret memmove_ty(bcx, addr, lv.val, pair_ty);
3696
    }
3697 3698 3699
    let closure = alt f_res.env {
      null_env. { none }
      _ { let (_, cl) = maybe_add_env(cx, f_res); some(cl) }
3700
    };
3701

3702 3703
    // FIXME: should follow from a precondition on trans_bind_1
    let ccx = bcx_ccx(cx);
3704
    check (type_has_static_size(ccx, outgoing_fty));
3705

3706 3707
    // Arrange for the bound function to live in the first binding spot
    // if the function is not statically known.
3708
    let (env_vals, target_res) = alt closure {
3709 3710 3711 3712 3713 3714 3715
      some(cl) {
        // Cast the function we are binding to be the type that the
        // closure will expect it to have. The type the closure knows
        // about has the type parameters substituted with the real types.
        let sp = cx.sp;
        let llclosurety = T_ptr(type_of(ccx, sp, outgoing_fty));
        let src_loc = PointerCast(bcx, cl, llclosurety);
3716
        ([env_direct(src_loc, pair_ty)], none)
3717
      }
3718
      none. { ([], some(f_res.val)) }
3719
    };
3720

3721
    // Actually construct the closure
3722 3723
    let closure = build_environment
        (bcx, lltydescs, env_vals + vec::map(env_expr, bound), true);
3724
    bcx = closure.bcx;
3725

3726 3727
    // Make thunk
    let llthunk =
B
Brian Anderson 已提交
3728 3729
        trans_bind_thunk(cx.fcx.lcx, cx.sp, pair_ty, outgoing_fty_real, args,
                         closure.ptrty, ty_param_count, target_res);
3730

3731
    // Fill the function pair
3732 3733
    let {bcx, val: addr} = get_dest_addr(bcx, dest);
    fill_fn_pair(bcx, addr, llthunk.val, closure.ptr);
3734
    ret bcx;
3735 3736
}

3737
fn trans_arg_expr(cx: @block_ctxt, arg: ty::arg, lldestty0: TypeRef,
3738 3739 3740
                  &to_zero: [{v: ValueRef, t: ty::t}],
                  &to_revoke: [{v: ValueRef, t: ty::t}], e: @ast::expr) ->
   result {
M
Marijn Haverbeke 已提交
3741 3742 3743 3744
    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);
    let lv = trans_lval(cx, e);
3745 3746
    let bcx = lv.bcx;
    let val = lv.val;
M
Marijn Haverbeke 已提交
3747
    if is_bot {
3748 3749 3750 3751 3752
        // For values of type _|_, we generate an
        // "undef" value, as such a value should never
        // be inspected. It's important for the value
        // to have type lldestty0 (the callee's expected type).
        val = llvm::LLVMGetUndef(lldestty0);
3753
    } else if arg.mode == ast::by_ref {
3754 3755 3756 3757 3758 3759 3760 3761
        let copied = false;
        if !lv.is_mem && type_is_immediate(ccx, e_ty) {
            val = do_spill_noroot(bcx, val);
            copied = true;
        }
        if ccx.copy_map.contains_key(e.id) && lv.is_mem {
            if !copied {
                let alloc = alloc_ty(bcx, e_ty);
3762 3763 3764
                bcx =
                    copy_val(alloc.bcx, INIT, alloc.val,
                             load_if_immediate(alloc.bcx, val, e_ty), e_ty);
3765
                val = alloc.val;
3766
            } else { bcx = take_ty(bcx, val, e_ty); }
3767
            add_clean(bcx, val, e_ty);
M
Marijn Haverbeke 已提交
3768
        }
B
Brian Anderson 已提交
3769
    } else if type_is_immediate(ccx, e_ty) && !lv.is_mem {
3770
        let r = do_spill(bcx, val, e_ty);
B
Brian Anderson 已提交
3771 3772
        val = r.val;
        bcx = r.bcx;
M
Marijn Haverbeke 已提交
3773 3774
    }

M
Marijn Haverbeke 已提交
3775 3776
    if !is_bot && ty::type_contains_params(ccx.tcx, arg.ty) {
        let lldestty = lldestty0;
3777
        val = PointerCast(bcx, val, lldestty);
3778
    }
3779 3780

    // Collect arg for later if it happens to be one we've moving out.
3781
    if arg.mode == ast::by_move {
3782
        if lv.is_mem {
B
Brian Anderson 已提交
3783 3784
            // Use actual ty, not declared ty -- anything else doesn't make
            // sense if declared ty is a ty param
3785 3786
            to_zero += [{v: lv.val, t: e_ty}];
        } else { to_revoke += [{v: lv.val, t: e_ty}]; }
3787
    }
3788
    ret rslt(bcx, val);
3789 3790
}

3791

3792 3793
// NB: must keep 4 fns in sync:
//
3794
//  - type_of_fn
3795 3796 3797
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args
3798 3799
fn trans_args(cx: @block_ctxt, outer_cx: @block_ctxt, llenv: ValueRef,
              gen: option::t<generic_info>,
3800
              lliterbody: option::t<ValueRef>, es: [@ast::expr], fn_ty: ty::t)
3801
   -> {bcx: @block_ctxt,
3802
       outer_cx: @block_ctxt,
3803 3804 3805
       args: [ValueRef],
       retslot: ValueRef,
       to_zero: [{v: ValueRef, t: ty::t}],
3806
       to_revoke: [{v: ValueRef, t: ty::t}]} {
3807

3808
    let args: [ty::arg] = ty::ty_fn_args(bcx_tcx(cx), fn_ty);
B
Brian Anderson 已提交
3809 3810 3811 3812
    let llargs: [ValueRef] = [];
    let lltydescs: [ValueRef] = [];
    let to_zero = [];
    let to_revoke = [];
3813

3814 3815
    let ccx = bcx_ccx(cx);
    let tcx = ccx.tcx;
3816
    let bcx: @block_ctxt = cx;
3817
    let ret_style = ty::ty_fn_ret_style(tcx, fn_ty);
3818
    let by_ref = ast_util::ret_by_ref(ret_style);
3819

3820
    let retty = ty::ty_fn_ret(tcx, fn_ty), full_retty = retty;
M
Marijn Haverbeke 已提交
3821 3822 3823 3824
    alt gen {
      some(g) {
        lazily_emit_all_generic_info_tydesc_glues(cx, g);
        lltydescs = g.tydescs;
3825 3826
        args = ty::ty_fn_args(tcx, g.item_type);
        retty = ty::ty_fn_ret(tcx, g.item_type);
M
Marijn Haverbeke 已提交
3827 3828
      }
      _ { }
3829
    }
3830
    // Arg 0: Output pointer.
3831 3832 3833 3834 3835 3836 3837
    let llretslot_res = if ty::type_is_nil(tcx, retty) {
        rslt(cx, llvm::LLVMGetUndef(T_ptr(T_nil())))
    } else if by_ref {
        rslt(cx, alloca(cx, T_ptr(type_of_or_i8(bcx, full_retty))))
    } else { alloc_ty(bcx, full_retty) };
    bcx = llretslot_res.bcx;
    let llretslot = llretslot_res.val;
3838
    if ty::type_contains_params(tcx, retty) {
3839 3840 3841 3842 3843
        // 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.
3844
        check non_ty_var(ccx, retty);
3845
        let llretty = T_ptr(type_of_inner(ccx, bcx.sp, retty));
3846
        if by_ref { llretty = T_ptr(llretty); }
3847
        llargs += [PointerCast(cx, llretslot, llretty)];
B
Brian Anderson 已提交
3848
    } else { llargs += [llretslot]; }
3849

3850
    // Arg 1: task pointer.
B
Brian Anderson 已提交
3851
    llargs += [bcx.fcx.lltaskptr];
3852

3853
    // Arg 2: Env (closure-bindings / self-obj)
B
Brian Anderson 已提交
3854
    llargs += [llenv];
3855

3856
    // Args >3: ty_params ...
3857 3858
    llargs += lltydescs;

3859
    // ... then possibly an lliterbody argument.
3860 3861 3862
    alt lliterbody {
      none. { }
      some(lli) {
B
Brian Anderson 已提交
3863
        let lli =
3864 3865
            if ty::type_contains_params(tcx, retty) {
                let body_ty = ty::mk_iter_body_fn(tcx, retty);
3866
                check non_ty_var(ccx, body_ty);
3867
                let body_llty = type_of_inner(ccx, cx.sp, body_ty);
3868
                PointerCast(bcx, lli, T_ptr(body_llty))
B
Brian Anderson 已提交
3869
            } else { lli };
3870
        llargs += [Load(cx, lli)];
3871 3872
      }
    }
3873

3874
    // ... then explicit args.
3875 3876 3877 3878

    // 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.
3879
    let arg_tys = type_of_explicit_args(ccx, cx.sp, args);
M
Marijn Haverbeke 已提交
3880
    let i = 0u;
3881
    for e: @ast::expr in es {
3882 3883 3884 3885 3886 3887 3888
        let is_referenced = alt ret_style {
          ast::return_ref(_, arg_n) { i + 1u == arg_n }
          _ { false }
        };
        let r = trans_arg_expr(is_referenced ? outer_cx : bcx,
                               args[i], arg_tys[i], to_zero, to_revoke, e);
        if is_referenced { outer_cx = r.bcx; } else { bcx = r.bcx; }
B
Brian Anderson 已提交
3889
        llargs += [r.val];
3890 3891
        i += 1u;
    }
B
Brian Anderson 已提交
3892
    ret {bcx: bcx,
3893
         outer_cx: outer_cx,
B
Brian Anderson 已提交
3894 3895 3896
         args: llargs,
         retslot: llretslot,
         to_zero: to_zero,
3897
         to_revoke: to_revoke};
3898 3899
}

3900 3901
fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
              lliterbody: option::t<ValueRef>, args: [@ast::expr],
3902
              id: ast::node_id) -> {res: result, by_ref: bool} {
3903 3904 3905
    // 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.
3906 3907
    let tcx = bcx_tcx(in_cx);
    let fn_expr_ty = ty::expr_ty(tcx, f);
3908 3909

    if check type_is_native_fn_on_c_stack(tcx, fn_expr_ty) {
3910
        ret trans_c_stack_native_call(in_cx, f, args);
3911 3912
    }

3913
    let by_ref = ast_util::ret_by_ref(ty::ty_fn_ret_style(tcx, fn_expr_ty));
3914
    let cx = new_scope_block_ctxt(in_cx, "call");
3915 3916 3917 3918
    let f_res = trans_callee(cx, f);
    let bcx = f_res.bcx;

    let faddr = f_res.val;
3919 3920
    let llenv;
    alt f_res.env {
3921 3922 3923
      null_env. {
        llenv = llvm::LLVMGetUndef(T_opaque_closure_ptr(*bcx_ccx(cx)));
      }
3924
      obj_env(e) { llenv = e; }
3925 3926
      is_closure. {
        // It's a closure. Have to fetch the elements
3927
        if f_res.is_mem { faddr = load_if_immediate(bcx, faddr, fn_expr_ty); }
M
Marijn Haverbeke 已提交
3928
        let pair = faddr;
3929 3930
        faddr = GEP(bcx, pair, [C_int(0), C_int(abi::fn_field_code)]);
        faddr = Load(bcx, faddr);
B
Brian Anderson 已提交
3931
        let llclosure = GEP(bcx, pair, [C_int(0), C_int(abi::fn_field_box)]);
3932
        llenv = Load(bcx, llclosure);
M
Marijn Haverbeke 已提交
3933
      }
3934
    }
3935

3936
    let ret_ty = ty::node_id_to_type(tcx, id);
M
Marijn Haverbeke 已提交
3937
    let args_res =
M
Marijn Haverbeke 已提交
3938
        trans_args(bcx, in_cx, llenv, f_res.generic, lliterbody, args,
3939
                   fn_expr_ty);
3940
    Br(args_res.outer_cx, cx.llbb);
3941
    bcx = args_res.bcx;
M
Marijn Haverbeke 已提交
3942 3943
    let llargs = args_res.args;
    let llretslot = args_res.retslot;
3944

3945 3946 3947 3948 3949 3950 3951 3952
    /*
    log_err "calling: " + val_str(bcx_ccx(cx).tn, faddr);

    for arg: ValueRef in llargs {
        log_err "arg: " + val_str(bcx_ccx(cx).tn, arg);
    }
    */

3953 3954 3955 3956
    /* 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. */
3957
    let retval = C_nil();
3958 3959
    bcx = invoke_full(bcx, faddr, llargs, args_res.to_zero,
                      args_res.to_revoke);
3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971
    alt lliterbody {
      none. {
        if !ty::type_is_nil(tcx, ret_ty) {
            if by_ref {
                retval = Load(bcx, llretslot);
            } else {
                retval = load_if_immediate(bcx, llretslot, ret_ty);
                // Retval doesn't correspond to anything really tangible
                // in the frame, but it's a ref all the same, so we put a
                // note here to drop it when we're done in this scope.
                add_clean_temp(in_cx, retval, ret_ty);
            }
3972
        }
3973
      }
3974 3975 3976 3977
      some(_) {
        // If there was an lliterbody, it means we were calling an
        // iter, and we are *not* the party using its 'output' value,
        // we should ignore llretslot.
3978 3979 3980 3981
      }
    }
    // Forget about anything we moved out.
    bcx = zero_and_revoke(bcx, args_res.to_zero, args_res.to_revoke);
3982

3983
    if !by_ref { bcx = trans_block_cleanups(bcx, cx); }
3984 3985 3986
    let next_cx = new_sub_block_ctxt(in_cx, "next");
    if bcx.unreachable || ty::type_is_bot(tcx, ret_ty) {
        Unreachable(next_cx);
3987
    }
3988
    Br(bcx, next_cx.llbb);
3989 3990
    bcx = next_cx;
    ret {res: rslt(bcx, retval), by_ref: by_ref};
3991 3992
}

3993 3994 3995
// Translates a native call on the C stack. Calls into the runtime to perform
// the stack switching operation.
fn trans_c_stack_native_call(bcx: @block_ctxt, f: @ast::expr,
3996 3997
                             args: [@ast::expr])
        -> {res: result, by_ref: bool} {
3998 3999 4000 4001 4002
    let ccx = bcx_ccx(bcx);
    let f_res = trans_callee(bcx, f);
    let llfn = f_res.val; bcx = f_res.bcx;

    // Translate the callee.
4003
    let { params: _, ty: fn_ty } = ty::expr_ty_params_and_ty(bcx_tcx(bcx), f);
4004 4005 4006 4007 4008 4009
    let fn_arg_tys = ty::ty_fn_args(bcx_tcx(bcx), fn_ty);

    // Translate arguments.
    let (to_zero, to_revoke) = ([], []);
    let llargs = vec::map2({ |ty_arg, arg|
        let arg_ty = ty_arg.ty;
4010 4011 4012 4013 4014 4015 4016 4017 4018 4019

        let static, llargty;
        if check type_has_static_size(ccx, arg_ty) {
            static = true;
            llargty = type_of(ccx, f.span, arg_ty);
        } else {
            static = false;
            llargty = T_ptr(T_i8());
        }

4020 4021
        let r = trans_arg_expr(bcx, ty_arg, llargty, to_zero, to_revoke, arg);
        let llargval = r.val; bcx = r.bcx;
4022
        { llval: llargval, llty: llargty, static: static }
4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033
    }, fn_arg_tys, args);

    // Allocate the argument bundle.
    let llargbundlety = T_struct(vec::map({ |r| r.llty }, llargs));
    let llargbundlesz = llsize_of(llargbundlety);
    let llrawargbundle = Call(bcx, ccx.upcalls.alloc_c_stack,
                              [llargbundlesz]);
    let llargbundle = PointerCast(bcx, llrawargbundle, T_ptr(llargbundlety));

    // Copy in arguments.
    vec::eachi({ |llarg, i|
4034 4035 4036 4037 4038 4039 4040 4041
        let llargval;
        if llarg.static {
            // FIXME: This load is unfortunate. It won't be necessary once we
            // have reference types again.
            llargval = Load(bcx, llarg.llval);
        } else {
            llargval = llarg.llval;
        }
4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053
        store_inbounds(bcx, llargval, llargbundle, [C_int(0), C_uint(i)]);
    }, llargs);

    // Call.
    // TODO: Invoke instead.
    let llrawretval = Call(bcx, ccx.upcalls.call_c_stack,
                           [llfn, llrawargbundle]);

    // Cast return type.
    let ret_ty = ty::ty_fn_ret(bcx_tcx(bcx), fn_ty);
    check type_has_static_size(ccx, ret_ty);
    let llretty = type_of(ccx, f.span, ret_ty);
4054 4055 4056 4057 4058 4059 4060

    let llretval;
    if lib::llvm::llvm::LLVMGetTypeKind(llretty) as int == 11 { // pointer
        llretval = IntToPtr(bcx, llrawretval, llretty);
    } else {
        llretval = TruncOrBitCast(bcx, llrawretval, llretty);
    }
4061 4062 4063

    // Forget about anything we moved out.
    bcx = zero_and_revoke(bcx, to_zero, to_revoke);
4064 4065

    ret {res: rslt(bcx, llretval), by_ref: false};
4066 4067
}

4068 4069 4070 4071 4072
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 {
4073
        bcx = zero_alloca(bcx, v, t);
4074
    }
4075 4076
    for {v, _} in to_revoke {
        bcx = revoke_clean(bcx, v);
4077 4078 4079 4080
    }
    ret bcx;
}

B
Brian Anderson 已提交
4081
fn invoke(bcx: @block_ctxt, llfn: ValueRef,
4082
          llargs: [ValueRef]) -> @block_ctxt {
4083
    ret invoke_(bcx, llfn, llargs, [], [], Invoke);
B
Brian Anderson 已提交
4084 4085
}

4086 4087 4088 4089
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);
B
Brian Anderson 已提交
4090
}
4091

4092 4093 4094
fn invoke_(bcx: @block_ctxt, llfn: ValueRef, llargs: [ValueRef],
           to_zero: [{v: ValueRef, t: ty::t}],
           to_revoke: [{v: ValueRef, t: ty::t}],
B
Brian Anderson 已提交
4095
           invoker: fn(@block_ctxt, ValueRef, [ValueRef],
4096
                       BasicBlockRef, BasicBlockRef)) -> @block_ctxt {
4097 4098
    // FIXME: May be worth turning this into a plain call when there are no
    // cleanups to run
4099
    if bcx.unreachable { ret bcx; }
4100
    let normal_bcx = new_sub_block_ctxt(bcx, "normal return");
4101 4102 4103 4104
    invoker(bcx, llfn, llargs,
            normal_bcx.llbb,
            get_landing_pad(bcx, to_zero, to_revoke));
    ret normal_bcx;
4105 4106
}

4107 4108 4109 4110 4111 4112 4113 4114
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 {
4115
        let unwind_bcx = new_sub_block_ctxt(bcx, "unwind");
4116
        let lpadbb = trans_landing_pad(unwind_bcx, to_zero, to_revoke);
4117
        scope_bcx.lpad = some(lpadbb);
4118
        scope_bcx.lpad_dirty = have_zero_or_revoke;
4119 4120 4121
    }
    assert option::is_some(scope_bcx.lpad);
    ret option::get(scope_bcx.lpad);
4122

4123 4124
    fn find_scope_for_lpad(bcx: @block_ctxt,
                           have_zero_or_revoke: bool) -> @block_ctxt {
4125 4126 4127
        let scope_bcx = bcx;
        while true {
            scope_bcx = find_scope_cx(scope_bcx);
4128 4129
            if vec::is_not_empty(scope_bcx.cleanups)
                || have_zero_or_revoke {
4130 4131 4132 4133 4134 4135 4136
                ret scope_bcx;
            } else {
                scope_bcx = alt scope_bcx.parent {
                  parent_some(b) { b }
                  parent_none. {
                    ret scope_bcx;
                  }
4137
                };
4138 4139 4140 4141
            }
        }
        fail;
    }
4142 4143
}

4144 4145
fn trans_landing_pad(bcx: @block_ctxt,
                     to_zero: [{v: ValueRef, t: ty::t}],
4146
                     to_revoke: [{v: ValueRef, t: ty::t}]) -> BasicBlockRef {
B
Brian Anderson 已提交
4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162
    // 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);
B
Brian Anderson 已提交
4163

4164 4165 4166
    // 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.
4167
    let bcx = zero_and_revoke(bcx, to_zero, to_revoke);
B
Brian Anderson 已提交
4168 4169 4170 4171 4172 4173 4174 4175 4176 4177
    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 }
          parent_none. { break; }
        };
    }

B
Brian Anderson 已提交
4178 4179
    // Continue unwinding
    Resume(bcx, llretval);
4180
    ret bcx.llbb;
4181 4182
}

4183 4184
fn trans_tup(bcx: @block_ctxt, elts: [@ast::expr], id: ast::node_id,
             dest: dest) -> @block_ctxt {
4185
    let t = node_id_type(bcx.fcx.lcx.ccx, id);
4186
    let (addr, overwrite) = alt dest {
4187 4188 4189 4190
      ignore. {
        for ex in elts { bcx = trans_expr_dps(bcx, ex, ignore); }
        ret bcx;
      }
4191 4192 4193 4194 4195
      save_in(pos) { (pos, none) }
      overwrite(pos, _) {
        let scratch = alloca(bcx, llvm::LLVMGetElementType(val_ty(pos)));
        (scratch, some(pos))
      }
4196
    };
4197
    let temp_cleanups = [], i = 0;
4198
    for e in elts {
4199 4200
        let dst = GEP_tup_like_1(bcx, t, addr, [0, i]);
        let e_ty = ty::expr_ty(bcx_tcx(bcx), e);
4201
        bcx = trans_expr_save_in(dst.bcx, e, dst.val, INIT);
4202 4203
        add_clean_temp_mem(bcx, dst.val, e_ty);
        temp_cleanups += [dst.val];
4204 4205
        i += 1;
    }
4206
    for cleanup in temp_cleanups { revoke_clean(bcx, cleanup); }
4207 4208 4209 4210 4211 4212 4213
    alt overwrite {
      some(pos) {
        bcx = drop_ty(bcx, pos, t);
        bcx = memmove_ty(bcx, pos, addr, t);
      }
      none. {}
    }
4214
    ret bcx;
4215 4216
}

4217 4218 4219
fn trans_rec(bcx: @block_ctxt, fields: [ast::field],
             base: option::t<@ast::expr>, id: ast::node_id,
             dest: dest) -> @block_ctxt {
M
Marijn Haverbeke 已提交
4220
    let t = node_id_type(bcx_ccx(bcx), id);
4221
    let (addr, overwrite) = alt dest {
4222 4223 4224 4225 4226 4227
      ignore. {
        for fld in fields {
            bcx = trans_expr_dps(bcx, fld.node.expr, ignore);
        }
        ret bcx;
      }
4228 4229 4230 4231 4232 4233 4234
      save_in(pos) { (pos, none) }
      // The expressions that populate the fields might still use the old
      // record, so we build the new on in a scratch area
      overwrite(pos, _) {
        let scratch = alloca(bcx, llvm::LLVMGetElementType(val_ty(pos)));
        (scratch, some(pos))
      }
4235
    };
4236 4237

    let base_val = alt base {
M
Marijn Haverbeke 已提交
4238 4239 4240
      some(bexp) {
        let base_res = trans_expr(bcx, bexp);
        bcx = base_res.bcx;
4241
        base_res.val
M
Marijn Haverbeke 已提交
4242
      }
4243 4244
      none. { C_nil() }
    };
4245

4246
    let ty_fields = alt ty::struct(bcx_tcx(bcx), t) { ty::ty_rec(f) { f } };
4247
    let temp_cleanups = [], i = 0;
4248
    for tf in ty_fields {
M
Marijn Haverbeke 已提交
4249 4250
        let dst = GEP_tup_like_1(bcx, t, addr, [0, i]);
        bcx = dst.bcx;
4251
        alt vec::find({|f| str::eq(f.node.ident, tf.ident)}, fields) {
4252
          some(f) {
4253
            bcx = trans_expr_save_in(bcx, f.node.expr, dst.val, INIT);
4254 4255
          }
          none. {
4256 4257
            let base = GEP_tup_like_1(bcx, t, base_val, [0, i]);
            let val = load_if_immediate(base.bcx, base.val, tf.mt.ty);
M
Marijn Haverbeke 已提交
4258
            bcx = copy_val(base.bcx, INIT, dst.val, val, tf.mt.ty);
4259 4260
          }
        }
M
Marijn Haverbeke 已提交
4261 4262
        add_clean_temp_mem(bcx, dst.val, tf.mt.ty);
        temp_cleanups += [dst.val];
4263
        i += 1;
4264
    }
4265 4266 4267
    // 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); }
4268 4269 4270 4271 4272 4273 4274
    alt overwrite {
      some(pos) {
        bcx = drop_ty(bcx, pos, t);
        bcx = memmove_ty(bcx, pos, addr, t);
      }
      none. {}
    }
4275
    ret bcx;
4276 4277
}

4278
// FIXME[DPS] remove this entirely, rename trans_expr_dps to trans_expr
4279
fn trans_expr(cx: @block_ctxt, e: @ast::expr) -> result {
4280
    if expr_is_lval(bcx_tcx(cx), e) {
4281 4282
        let t = ty::expr_ty(bcx_tcx(cx), e);
        let sub = trans_lval(cx, e);
4283 4284 4285
        let v = sub.val;
        if sub.is_mem { v = load_if_immediate(sub.bcx, v, t); }
        ret rslt(sub.bcx, v);
4286 4287
    } else {
        // Fall through to DPS-style
4288 4289
        ret dps_to_result(cx, {|bcx, dest| trans_expr_dps(bcx, e, dest)},
                          ty::expr_ty(bcx_tcx(cx), e));
4290 4291 4292
    }
}

4293 4294
fn trans_expr_save_in(bcx: @block_ctxt, e: @ast::expr, dest: ValueRef,
                      kind: copy_action) -> @block_ctxt {
4295
    let tcx = bcx_tcx(bcx), t = ty::expr_ty(tcx, e);
4296 4297
    let dst = if ty::type_is_bot(tcx, t) || ty::type_is_nil(tcx, t) {
        ignore
4298 4299
    } else if kind == INIT {
        save_in(dest)
4300
    } else {
4301 4302 4303
        overwrite(dest, t)
    };
    ret trans_expr_dps(bcx, e, dst);
4304 4305
}

4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316
fn trans_expr_by_ref(bcx: @block_ctxt, e: @ast::expr) -> result {
    let cell = empty_dest_cell();
    bcx = trans_expr_dps(bcx, e, by_ref(cell));
    ret rslt(bcx, *cell);
}

// Invariants:
// - things returning nil get dest=ignore
// - any lvalue expr may be given dest=by_ref
// - exprs returning an immediate get by_val (or by_ref when lval)
// - exprs returning non-immediates get save_in (or by_ref when lval)
4317 4318
fn trans_expr_dps(bcx: @block_ctxt, e: @ast::expr, dest: dest)
    -> @block_ctxt {
4319 4320 4321
    let tcx = bcx_tcx(bcx);
    if expr_is_lval(tcx, e) { ret lval_to_dps(bcx, e, dest); }

4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340
    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(_, _, _) {
        ret trans_expr_dps(bcx, ast_util::ternary_to_if(e), dest);
      }
      ast::expr_alt(expr, arms) {
        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;
      }
4341 4342 4343 4344
      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); }
4345 4346
      ast::expr_lit(lit) { ret trans_lit(bcx, *lit, dest); }
      ast::expr_vec(args, _) { ret tvec::trans_vec(bcx, args, e.id, dest); }
4347
      ast::expr_binary(op, x, y) { ret trans_binary(bcx, op, x, y, dest); }
M
Marijn Haverbeke 已提交
4348
      ast::expr_unary(op, x) {
4349
        assert op != ast::deref; // lvals are handled above
M
Marijn Haverbeke 已提交
4350 4351
        ret trans_unary(bcx, op, x, e.id, dest);
      }
4352 4353
      ast::expr_fn(f) { ret trans_expr_fn(bcx, f, e.span, e.id, dest); }
      ast::expr_bind(f, args) { ret trans_bind(bcx, f, args, e.id, dest); }
4354
      ast::expr_copy(a) {
4355 4356
        if !expr_is_lval(tcx, a) { ret trans_expr_dps(bcx, a, dest); }
        else { ret lval_to_dps(bcx, a, dest); }
4357 4358
      }
      ast::expr_cast(val, _) { ret trans_cast(bcx, val, e.id, dest); }
4359 4360 4361
      ast::expr_anon_obj(anon_obj) {
        ret trans_anon_obj(bcx, e.span, anon_obj, e.id, dest);
      }
4362 4363
      // FIXME[DPS] untangle non-lval calls and fields from trans_lval
      ast::expr_call(_, _) | ast::expr_field(_, _) {
4364
        ret lval_to_dps(bcx, e, dest);
4365
      }
4366

4367
      // These return nothing
4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427
      ast::expr_break. {
        assert dest == ignore;
        ret trans_break(e.span, bcx);
      }
      ast::expr_cont. {
        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) {
        // Ideally, the expr_be tag would have a precondition
        // that is_call_expr(ex) -- but we don't support that
        // yet
        // FIXME
        check (ast_util::is_call_expr(ex));
        ret trans_be(bcx, ex);
      }
      ast::expr_put(ex) {
        assert dest == ignore;
        ret trans_put(bcx, ex);
      }
      ast::expr_fail(expr) {
        assert dest == ignore;
        ret trans_fail_expr(bcx, some(e.span), expr);
      }
      ast::expr_log(lvl, a) {
        assert dest == ignore;
        ret trans_log(lvl, bcx, a);
      }
      ast::expr_assert(a) {
        assert dest == ignore;
        ret trans_check_expr(bcx, a, "Assertion");
      }
      ast::expr_check(ast::checked., a) {
        assert dest == ignore;
        ret trans_check_expr(bcx, a, "Predicate");
      }
      ast::expr_check(ast::unchecked., a) {
        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");
        let else_cx = new_scope_block_ctxt(bcx, "else");

        CondBr(bcx, cond, then_cx.llbb, else_cx.llbb);
        ret join_branches(bcx, [rslt(check_cx, C_nil()),
                                rslt(else_cx, C_nil())]);
      }
4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445
      ast::expr_for(decl, seq, body) {
        assert dest == ignore;
        ret trans_for(bcx, decl, seq, body);
      }
      ast::expr_for_each(decl, seq, body) {
        assert dest == ignore;
        ret trans_for_each(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;
4446
        let {bcx, val: lhs_addr, is_mem} = trans_lval(bcx, dst);
4447
        assert is_mem;
4448
        ret trans_expr_save_in(bcx, src, lhs_addr, DROP_EXISTING);
4449
      }
4450 4451
      ast::expr_move(dst, src) {
        assert dest == ignore;
4452
        let {bcx, val: addr, is_mem} = trans_lval(bcx, dst);
4453
        assert is_mem;
4454 4455 4456 4457 4458 4459 4460 4461
        // FIXME: calculate copy init-ness in typestate.
        if expr_is_lval(tcx, src) {
            ret trans_expr_save_in(bcx, src, addr, DROP_EXISTING);
        } else {
            let srclv = trans_lval(bcx, src);
            let t = ty::expr_ty(tcx, src);
            ret move_val(srclv.bcx, DROP_EXISTING, addr, srclv, t);
        }
4462
      }
4463 4464 4465 4466 4467
      ast::expr_swap(dst, src) {
        assert dest == ignore;
        let lhs_res = trans_lval(bcx, dst);
        assert (lhs_res.is_mem);
        let rhs_res = trans_lval(lhs_res.bcx, src);
4468
        let t = ty::expr_ty(tcx, src);
4469 4470 4471 4472 4473 4474 4475 4476 4477 4478
        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);
        ret move_val(bcx, INIT, rhs_res.val, lval_mem(bcx, tmp_alloc), t);
      }
      ast::expr_assign_op(op, dst, src) {
        assert dest == ignore;
        ret trans_assign_op(bcx, op, dst, src);
      }
M
Marijn Haverbeke 已提交
4479 4480 4481
    }
}

4482
fn lval_to_dps(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
M
Marijn Haverbeke 已提交
4483 4484 4485 4486 4487 4488 4489
    let lv = trans_lval(bcx, e);
    let {bcx, val, is_mem} = lv;
    let ty = ty::expr_ty(bcx_tcx(bcx), e);
    alt dest {
      by_val(cell) {
        if !is_mem {
            revoke_clean(bcx, val);
4490
            *cell = val;
M
Marijn Haverbeke 已提交
4491 4492 4493 4494 4495 4496 4497 4498 4499 4500
        } else if ty::type_is_unique(bcx_tcx(bcx), ty) {
            // Do a song and a dance to work around the fact that take_ty
            // for unique boxes overwrites the pointer.
            let oldval = Load(bcx, val);
            bcx = take_ty(bcx, val, ty);
            *cell = Load(bcx, val);
            Store(bcx, oldval, val);
        } else {
            bcx = take_ty(bcx, val, ty);
            *cell = Load(bcx, val);
4501 4502
        }
      }
M
Marijn Haverbeke 已提交
4503 4504 4505 4506 4507
      by_ref(cell) {
        assert is_mem;
        *cell = val;
      }
      save_in(loc) { bcx = move_val_if_temp(bcx, INIT, loc, lv, ty); }
4508 4509 4510
      overwrite(loc, _) {
        bcx = move_val_if_temp(bcx, DROP_EXISTING, loc, lv, ty);
      }
M
Marijn Haverbeke 已提交
4511
      ignore. {}
4512
    }
M
Marijn Haverbeke 已提交
4513
    ret bcx;
4514 4515
}

4516
// We pass structural values around the compiler "by pointer" and
4517 4518 4519 4520
// non-structural values (scalars, boxes, pointers) "by value". We call the
// latter group "immediates" and, in some circumstances when we know we have a
// pointer (or need one), perform load/store operations based on the
// immediate-ness of the type.
4521
fn type_is_immediate(ccx: @crate_ctxt, t: ty::t) -> bool {
4522
    ret ty::type_is_scalar(ccx.tcx, t) || ty::type_is_boxed(ccx.tcx, t) ||
4523
        ty::type_is_unique_box(ccx.tcx, t) || ty::type_is_native(ccx.tcx, t);
4524 4525
}

4526
fn do_spill(cx: @block_ctxt, v: ValueRef, t: ty::t) -> result {
4527 4528
    // We have a value but we have to spill it, and root it, to pass by alias.
    let bcx = cx;
4529 4530 4531 4532 4533

    if ty::type_is_bot(bcx_tcx(bcx), t) {
        ret rslt(bcx, C_null(T_ptr(T_i8())));
    }

4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544
    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.
4545
fn do_spill_noroot(cx: @block_ctxt, v: ValueRef) -> ValueRef {
M
Marijn Haverbeke 已提交
4546
    let llptr = alloca(cx, val_ty(v));
4547
    Store(cx, v, llptr);
4548 4549
    ret llptr;
}
4550

4551
fn spill_if_immediate(cx: @block_ctxt, v: ValueRef, t: ty::t) -> result {
4552 4553
    if type_is_immediate(bcx_ccx(cx), t) { ret do_spill(cx, v, t); }
    ret rslt(cx, v);
4554 4555
}

4556
fn load_if_immediate(cx: @block_ctxt, v: ValueRef, t: ty::t) -> ValueRef {
4557
    if type_is_immediate(bcx_ccx(cx), t) { ret Load(cx, v); }
4558
    ret v;
4559 4560
}

4561
fn trans_log(lvl: int, cx: @block_ctxt, e: @ast::expr) -> @block_ctxt {
M
Marijn Haverbeke 已提交
4562
    let lcx = cx.fcx.lcx;
B
Brian Anderson 已提交
4563
    let modname = str::connect(lcx.module_path, "::");
4564 4565
    let global = if lcx.ccx.module_data.contains_key(modname) {
        lcx.ccx.module_data.get(modname)
4566
    } else {
4567 4568 4569 4570 4571
        let s = link::mangle_internal_name_by_path_and_seq(
            lcx.ccx, lcx.module_path, "loglevel");
        let global = str::as_buf(s, {|buf|
            llvm::LLVMAddGlobal(lcx.ccx.llmod, T_int(), buf)
        });
4572 4573
        llvm::LLVMSetGlobalConstant(global, False);
        llvm::LLVMSetInitializer(global, C_null(T_int()));
4574 4575
        llvm::LLVMSetLinkage(global,
                             lib::llvm::LLVMInternalLinkage as llvm::Linkage);
4576
        lcx.ccx.module_data.insert(modname, global);
4577 4578
        global
    };
B
Brian Anderson 已提交
4579 4580
    let log_cx = new_scope_block_ctxt(cx, "log");
    let after_cx = new_sub_block_ctxt(cx, "after");
4581 4582 4583
    let load = Load(cx, global);
    let test = ICmp(cx, lib::llvm::LLVMIntSGE, load, C_int(lvl));
    CondBr(cx, test, log_cx.llbb, after_cx.llbb);
M
Marijn Haverbeke 已提交
4584 4585 4586
    let sub = trans_expr(log_cx, e);
    let e_ty = ty::expr_ty(bcx_tcx(cx), e);
    let log_bcx = sub.bcx;
4587

4588
    let ti = none::<@tydesc_info>;
4589
    let r = get_tydesc(log_bcx, e_ty, false, tps_normal, ti).result;
P
Patrick Walton 已提交
4590
    log_bcx = r.bcx;
4591
    let lltydesc = r.val;
P
Patrick Walton 已提交
4592 4593

    // Call the polymorphic log function.
4594 4595 4596
    r = spill_if_immediate(log_bcx, sub.val, e_ty);
    log_bcx = r.bcx;
    let llvalptr = r.val;
4597
    let llval_i8 = PointerCast(log_bcx, llvalptr, T_ptr(T_i8()));
P
Patrick Walton 已提交
4598

4599
    Call(log_bcx, bcx_ccx(log_bcx).upcalls.log_type,
4600
         [log_bcx.fcx.lltaskptr, lltydesc, llval_i8, C_int(lvl)]);
M
Marijn Haverbeke 已提交
4601

4602
    log_bcx = trans_block_cleanups(log_bcx, log_cx);
4603
    Br(log_bcx, after_cx.llbb);
4604
    ret after_cx;
4605 4606
}

4607
fn trans_check_expr(cx: @block_ctxt, e: @ast::expr, s: str) -> @block_ctxt {
M
Marijn Haverbeke 已提交
4608
    let cond_res = trans_expr(cx, e);
B
Brian Anderson 已提交
4609 4610
    let expr_str = s + " " + expr_to_str(e) + " failed";
    let fail_cx = new_sub_block_ctxt(cx, "fail");
4611
    trans_fail(fail_cx, some::<span>(e.span), expr_str);
B
Brian Anderson 已提交
4612
    let next_cx = new_sub_block_ctxt(cx, "next");
4613
    CondBr(cond_res.bcx, cond_res.val, next_cx.llbb, fail_cx.llbb);
4614
    ret next_cx;
4615 4616
}

4617 4618
fn trans_fail_expr(bcx: @block_ctxt, sp_opt: option::t<span>,
                   fail_expr: option::t<@ast::expr>) -> @block_ctxt {
M
Marijn Haverbeke 已提交
4619 4620 4621 4622 4623 4624
    alt fail_expr {
      some(expr) {
        let tcx = bcx_tcx(bcx);
        let expr_res = trans_expr(bcx, expr);
        let e_ty = ty::expr_ty(tcx, expr);
        bcx = expr_res.bcx;
4625

M
Marijn Haverbeke 已提交
4626
        if ty::type_is_str(tcx, e_ty) {
4627 4628 4629
            let data = tvec::get_dataptr(
                bcx, expr_res.val, type_of_or_i8(
                    bcx, ty::mk_mach(tcx, ast::ty_u8)));
4630
            ret trans_fail_value(bcx, sp_opt, data);
M
Marijn Haverbeke 已提交
4631
        } else if bcx.unreachable {
4632
            ret bcx;
M
Marijn Haverbeke 已提交
4633
        } else {
4634 4635 4636
            bcx_ccx(bcx).sess.span_bug(
                expr.span, "fail called with unsupported type " +
                ty_to_str(tcx, e_ty));
4637
        }
M
Marijn Haverbeke 已提交
4638
      }
B
Brian Anderson 已提交
4639
      _ { ret trans_fail(bcx, sp_opt, "explicit failure"); }
4640 4641
    }
}
4642

4643 4644 4645 4646
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);
4647 4648
}

4649 4650
fn trans_fail_value(bcx: @block_ctxt, sp_opt: option::t<span>,
                    V_fail_str: ValueRef) -> @block_ctxt {
M
Marijn Haverbeke 已提交
4651 4652 4653 4654
    let V_filename;
    let V_line;
    alt sp_opt {
      some(sp) {
4655 4656
        let loc = bcx_ccx(bcx).sess.lookup_pos(sp.lo);
        V_filename = C_cstr(bcx_ccx(bcx), loc.filename);
M
Marijn Haverbeke 已提交
4657 4658
        V_line = loc.line as int;
      }
4659
      none. { V_filename = C_cstr(bcx_ccx(bcx), "<runtime>"); V_line = 0; }
4660
    }
4661 4662 4663 4664 4665 4666
    let V_str = PointerCast(bcx, V_fail_str, T_ptr(T_i8()));
    V_filename = PointerCast(bcx, V_filename, T_ptr(T_i8()));
    let args = [bcx.fcx.lltaskptr, V_str, V_filename, C_int(V_line)];
    let bcx = invoke(bcx, bcx_ccx(bcx).upcalls._fail, args);
    Unreachable(bcx);
    ret bcx;
B
Brian Anderson 已提交
4667 4668
}

4669
fn trans_put(in_cx: @block_ctxt, e: option::t<@ast::expr>) -> @block_ctxt {
B
Brian Anderson 已提交
4670
    let cx = new_scope_block_ctxt(in_cx, "put");
4671
    Br(in_cx, cx.llbb);
M
Marijn Haverbeke 已提交
4672 4673
    let llcallee = C_nil();
    let llenv = C_nil();
4674
    alt cx.fcx.lliterbody {
M
Marijn Haverbeke 已提交
4675 4676
      some(lli) {
        let slot = alloca(cx, val_ty(lli));
4677 4678 4679 4680 4681
        Store(cx, lli, slot);
        llcallee = GEP(cx, slot, [C_int(0), C_int(abi::fn_field_code)]);
        llcallee = Load(cx, llcallee);
        llenv = GEP(cx, slot, [C_int(0), C_int(abi::fn_field_box)]);
        llenv = Load(cx, llenv);
M
Marijn Haverbeke 已提交
4682
      }
4683
    }
M
Marijn Haverbeke 已提交
4684 4685
    let bcx = cx;
    let dummy_retslot = alloca(bcx, T_nil());
B
Brian Anderson 已提交
4686
    let llargs: [ValueRef] = [dummy_retslot, cx.fcx.lltaskptr, llenv];
M
Marijn Haverbeke 已提交
4687
    alt e {
4688 4689 4690
      none. {
        llargs += [C_null(T_ptr(T_nil()))];
      }
M
Marijn Haverbeke 已提交
4691 4692
      some(x) {
        let e_ty = ty::expr_ty(bcx_tcx(cx), x);
4693
        let arg = {mode: ast::by_ref, ty: e_ty};
B
Brian Anderson 已提交
4694 4695 4696 4697
        let arg_tys = type_of_explicit_args(bcx_ccx(cx), x.span, [arg]);
        let z = [];
        let k = [];
        let r = trans_arg_expr(bcx, arg, arg_tys[0], z, k, x);
M
Marijn Haverbeke 已提交
4698
        bcx = r.bcx;
B
Brian Anderson 已提交
4699
        llargs += [r.val];
M
Marijn Haverbeke 已提交
4700
      }
4701
    }
4702
    bcx = invoke(bcx, llcallee, llargs);
4703
    bcx = trans_block_cleanups(bcx, cx);
B
Brian Anderson 已提交
4704
    let next_cx = new_sub_block_ctxt(in_cx, "next");
4705
    if bcx.unreachable { Unreachable(next_cx); }
4706
    Br(bcx, next_cx.llbb);
4707
    ret next_cx;
4708 4709
}

4710 4711
fn trans_break_cont(sp: span, bcx: @block_ctxt, to_end: bool)
    -> @block_ctxt {
4712
    // Locate closest loop block, outputting cleanup as we go.
4713
    let cleanup_cx = bcx;
M
Marijn Haverbeke 已提交
4714
    while true {
4715
        bcx = trans_block_cleanups(bcx, cleanup_cx);
4716
        alt copy cleanup_cx.kind {
M
Marijn Haverbeke 已提交
4717 4718
          LOOP_SCOPE_BLOCK(_cont, _break) {
            if to_end {
4719
                Br(bcx, _break.llbb);
M
Marijn Haverbeke 已提交
4720 4721
            } else {
                alt _cont {
4722 4723
                  option::some(_cont) { Br(bcx, _cont.llbb); }
                  _ { Br(bcx, cleanup_cx.llbb); }
4724 4725
                }
            }
4726
            Unreachable(bcx);
4727
            ret bcx;
M
Marijn Haverbeke 已提交
4728 4729
          }
          _ {
4730
            alt cleanup_cx.parent {
M
Marijn Haverbeke 已提交
4731 4732
              parent_some(cx) { cleanup_cx = cx; }
              parent_none. {
4733 4734 4735
                bcx_ccx(bcx).sess.span_fatal
                    (sp, if to_end { "Break" } else { "Cont" } +
                     " outside a loop");
M
Marijn Haverbeke 已提交
4736
              }
4737
            }
M
Marijn Haverbeke 已提交
4738
          }
4739 4740
        }
    }
4741
    // If we get here without returning, it's a bug
4742
    bcx_ccx(bcx).sess.bug("in trans::trans_break_cont()");
4743 4744
}

4745
fn trans_break(sp: span, cx: @block_ctxt) -> @block_ctxt {
4746
    ret trans_break_cont(sp, cx, true);
4747 4748
}

4749
fn trans_cont(sp: span, cx: @block_ctxt) -> @block_ctxt {
4750
    ret trans_break_cont(sp, cx, false);
4751 4752
}

4753 4754
fn trans_ret(bcx: @block_ctxt, e: option::t<@ast::expr>) -> @block_ctxt {
    let cleanup_cx = bcx;
M
Marijn Haverbeke 已提交
4755 4756
    alt e {
      some(x) {
4757 4758 4759 4760
        if ast_util::ret_by_ref(bcx.fcx.ret_style) {
            let {bcx: cx, val} = trans_expr_by_ref(bcx, x);
            Store(cx, val, bcx.fcx.llretptr);
            bcx = cx;
4761
        } else {
4762
            bcx = trans_expr_save_in(bcx, x, bcx.fcx.llretptr, INIT);
4763
        }
M
Marijn Haverbeke 已提交
4764
      }
4765
      _ {}
4766
    }
4767
    // run all cleanups and back out.
4768

M
Marijn Haverbeke 已提交
4769 4770
    let more_cleanups: bool = true;
    while more_cleanups {
4771
        bcx = trans_block_cleanups(bcx, cleanup_cx);
4772
        alt cleanup_cx.parent {
M
Marijn Haverbeke 已提交
4773 4774
          parent_some(b) { cleanup_cx = b; }
          parent_none. { more_cleanups = false; }
4775 4776
        }
    }
4777
    build_return(bcx);
4778
    Unreachable(bcx);
4779
    ret bcx;
4780 4781
}

4782
fn build_return(bcx: @block_ctxt) { Br(bcx, bcx_fcx(bcx).llreturn); }
4783

4784
// fn trans_be(cx: &@block_ctxt, e: &@ast::expr) -> result {
4785
fn trans_be(cx: @block_ctxt, e: @ast::expr) : ast_util::is_call_expr(e) ->
4786
   @block_ctxt {
4787 4788
    // FIXME: Turn this into a real tail call once
    // calling convention issues are settled
4789 4790 4791
    ret trans_ret(cx, some(e));
}

4792
fn init_local(bcx: @block_ctxt, local: @ast::local) -> @block_ctxt {
4793 4794
    let ty = node_id_type(bcx_ccx(bcx), local.node.id);
    let llptr = bcx.fcx.lllocals.get(local.node.id);
4795

M
Marijn Haverbeke 已提交
4796 4797
    alt local.node.init {
      some(init) {
4798 4799
        if init.op == ast::init_assign ||
           !expr_is_lval(bcx_tcx(bcx), init.expr) {
4800
            bcx = trans_expr_save_in(bcx, init.expr, llptr, INIT);
4801
        } else { // This is a move from an lval, must perform an actual move
M
Marijn Haverbeke 已提交
4802
            let sub = trans_lval(bcx, init.expr);
4803
            bcx = move_val(sub.bcx, INIT, llptr, sub, ty);
4804
        }
M
Marijn Haverbeke 已提交
4805
      }
4806
      _ { bcx = zero_alloca(bcx, llptr, ty); }
4807
    }
4808 4809
    // Make a note to drop this slot on the way out.
    add_clean(bcx, llptr, ty);
4810 4811
    ret trans_alt::bind_irrefutable_pat(bcx, local.node.pat, llptr,
                                        bcx.fcx.lllocals, false);
4812 4813
}

4814 4815 4816 4817
fn init_ref_local(bcx: @block_ctxt, local: @ast::local) -> @block_ctxt {
    let init_expr = option::get(local.node.init).expr;
    let val = trans_lval(bcx, init_expr);
    assert val.is_mem;
4818 4819
    ret trans_alt::bind_irrefutable_pat(val.bcx, local.node.pat,
                                        val.val, bcx.fcx.lllocals, false);
4820 4821
}

4822 4823
fn zero_alloca(cx: @block_ctxt, llptr: ValueRef, t: ty::t)
    -> @block_ctxt {
M
Marijn Haverbeke 已提交
4824
    let bcx = cx;
4825 4826 4827 4828 4829
    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);
4830
    } else {
M
Marijn Haverbeke 已提交
4831
        let llsz = size_of(bcx, t);
4832 4833 4834
        // FIXME passing in the align here is correct, but causes issue #843
        // let llalign = align_of(llsz.bcx, t);
        bcx = call_bzero(llsz.bcx, llptr, llsz.val, C_int(0)).bcx;
4835
    }
4836
    ret bcx;
4837
}
4838

4839
fn trans_stmt(cx: @block_ctxt, s: ast::stmt) -> @block_ctxt {
4840
    // FIXME Fill in cx.sp
4841

M
Marijn Haverbeke 已提交
4842 4843
    let bcx = cx;
    alt s.node {
4844
      ast::stmt_expr(e, _) { bcx = trans_expr_dps(cx, e, ignore); }
M
Marijn Haverbeke 已提交
4845 4846 4847
      ast::stmt_decl(d, _) {
        alt d.node {
          ast::decl_local(locals) {
4848 4849 4850 4851 4852 4853
            for (style, local) in locals {
                if style == ast::let_copy {
                    bcx = init_local(bcx, local);
                } else {
                    bcx = init_ref_local(bcx, local);
                }
4854
            }
M
Marijn Haverbeke 已提交
4855 4856
          }
          ast::decl_item(i) { trans_item(cx.fcx.lcx, *i); }
4857
        }
M
Marijn Haverbeke 已提交
4858
      }
B
Brian Anderson 已提交
4859
      _ { bcx_ccx(cx).sess.unimpl("stmt variant"); }
4860
    }
4861
    ret bcx;
4862 4863
}

4864 4865
// You probably don't want to use this one. See the
// next three functions instead.
4866 4867
fn new_block_ctxt(cx: @fn_ctxt, parent: block_parent, kind: block_kind,
                  name: str) -> @block_ctxt {
B
Brian Anderson 已提交
4868
    let s = "";
M
Marijn Haverbeke 已提交
4869 4870
    if cx.lcx.ccx.sess.get_opts().save_temps ||
           cx.lcx.ccx.sess.get_opts().debuginfo {
4871
        s = cx.lcx.ccx.names.next(name);
4872
    }
B
Brian Anderson 已提交
4873 4874
    let llbb: BasicBlockRef =
        str::as_buf(s, {|buf| llvm::LLVMAppendBasicBlock(cx.llfn, buf) });
4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891
    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,
                fcx: cx};
    alt parent {
      parent_some(cx) {
        if cx.unreachable { Unreachable(bcx); }
      }
      _ {}
    }
    ret bcx;
4892 4893
}

4894

4895
// Use this when you're at the top block of a function or the like.
4896
fn new_top_block_ctxt(fcx: @fn_ctxt) -> @block_ctxt {
B
Brian Anderson 已提交
4897
    ret new_block_ctxt(fcx, parent_none, SCOPE_BLOCK, "function top level");
4898
}
4899

4900

4901
// Use this when you're at a curly-brace or similar lexical scope.
4902
fn new_scope_block_ctxt(bcx: @block_ctxt, n: str) -> @block_ctxt {
4903
    ret new_block_ctxt(bcx.fcx, parent_some(bcx), SCOPE_BLOCK, n);
4904 4905
}

4906 4907
fn new_loop_scope_block_ctxt(bcx: @block_ctxt, _cont: option::t<@block_ctxt>,
                             _break: @block_ctxt, n: str) -> @block_ctxt {
4908 4909 4910 4911
    ret new_block_ctxt(bcx.fcx, parent_some(bcx),
                       LOOP_SCOPE_BLOCK(_cont, _break), n);
}

4912

4913
// Use this when you're making a general CFG BB within a scope.
4914
fn new_sub_block_ctxt(bcx: @block_ctxt, n: str) -> @block_ctxt {
4915
    ret new_block_ctxt(bcx.fcx, parent_some(bcx), NON_SCOPE_BLOCK, n);
4916
}
4917

4918
fn new_raw_block_ctxt(fcx: @fn_ctxt, llbb: BasicBlockRef) -> @block_ctxt {
M
Marijn Haverbeke 已提交
4919
    ret @{llbb: llbb,
4920
          mutable terminated: false,
4921
          mutable unreachable: false,
M
Marijn Haverbeke 已提交
4922 4923
          parent: parent_none,
          kind: NON_SCOPE_BLOCK,
4924
          mutable cleanups: [],
4925
          mutable lpad_dirty: true,
4926
          mutable lpad: option::none,
M
Marijn Haverbeke 已提交
4927 4928
          sp: fcx.sp,
          fcx: fcx};
4929 4930
}

4931

4932
// trans_block_cleanups: Go through all the cleanups attached to this
4933
// block_ctxt and execute them.
4934 4935 4936 4937 4938
//
// 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.
4939
fn trans_block_cleanups(bcx: @block_ctxt, cleanup_cx: @block_ctxt) ->
M
Marijn Haverbeke 已提交
4940
   @block_ctxt {
4941
    if bcx.unreachable { ret bcx; }
M
Marijn Haverbeke 已提交
4942
    if cleanup_cx.kind == NON_SCOPE_BLOCK {
4943
        assert (std::vec::len::<cleanup>(cleanup_cx.cleanups) == 0u);
4944
    }
4945
    let i = std::vec::len::<cleanup>(cleanup_cx.cleanups);
M
Marijn Haverbeke 已提交
4946
    while i > 0u {
4947
        i -= 1u;
B
Brian Anderson 已提交
4948
        let c = cleanup_cx.cleanups[i];
M
Marijn Haverbeke 已提交
4949
        alt c {
4950 4951
          clean(cfn) { bcx = cfn(bcx); }
          clean_temp(_, cfn) { bcx = cfn(bcx); }
4952
        }
4953
    }
4954 4955 4956
    ret bcx;
}

4957
fn trans_fn_cleanups(fcx: @fn_ctxt, cx: @block_ctxt) {
4958
    alt fcx.llobstacktoken {
B
Brian Anderson 已提交
4959 4960
      some(lltoken_) {
        let lltoken = lltoken_; // satisfy alias checker
4961
        Call(cx, fcx_ccx(fcx).upcalls.dynastack_free,
B
Brian Anderson 已提交
4962
             [fcx.lltaskptr, lltoken]);
B
Brian Anderson 已提交
4963 4964
      }
      none. {/* nothing to do */ }
4965
    }
4966 4967
}

4968
iter block_locals(b: ast::blk) -> @ast::local {
4969
    for s: @ast::stmt in b.node.stmts {
M
Marijn Haverbeke 已提交
4970 4971 4972 4973
        alt s.node {
          ast::stmt_decl(d, _) {
            alt d.node {
              ast::decl_local(locals) {
4974 4975 4976
                for (style, local) in locals {
                    if style == ast::let_copy { put local; }
                }
M
Marijn Haverbeke 已提交
4977 4978
              }
              _ {/* fall through */ }
4979
            }
M
Marijn Haverbeke 已提交
4980 4981
          }
          _ {/* fall through */ }
4982 4983 4984 4985
        }
    }
}

4986
fn llstaticallocas_block_ctxt(fcx: @fn_ctxt) -> @block_ctxt {
M
Marijn Haverbeke 已提交
4987
    ret @{llbb: fcx.llstaticallocas,
4988
          mutable terminated: false,
4989
          mutable unreachable: false,
M
Marijn Haverbeke 已提交
4990 4991
          parent: parent_none,
          kind: SCOPE_BLOCK,
4992
          mutable cleanups: [],
4993
          mutable lpad_dirty: true,
4994
          mutable lpad: option::none,
M
Marijn Haverbeke 已提交
4995 4996
          sp: fcx.sp,
          fcx: fcx};
4997 4998
}

4999
fn llderivedtydescs_block_ctxt(fcx: @fn_ctxt) -> @block_ctxt {
M
Marijn Haverbeke 已提交
5000
    ret @{llbb: fcx.llderivedtydescs,
5001
          mutable terminated: false,
5002
          mutable unreachable: false,
M
Marijn Haverbeke 已提交
5003 5004
          parent: parent_none,
          kind: SCOPE_BLOCK,
5005
          mutable cleanups: [],
5006
          mutable lpad_dirty: true,
5007
          mutable lpad: option::none,
M
Marijn Haverbeke 已提交
5008 5009
          sp: fcx.sp,
          fcx: fcx};
5010 5011 5012
}


5013
fn alloc_ty(cx: @block_ctxt, t: ty::t) -> result {
5014
    let bcx = cx;
5015
    let ccx = bcx_ccx(cx);
5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029
    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)
        };
5030

5031 5032 5033 5034 5035 5036
    // 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.
5037

B
Brian Anderson 已提交
5038
    if bcx_tcx(cx).sess.get_opts().do_gc {
5039 5040
        bcx = gc::add_gc_root(bcx, val, t);
    }
5041

5042
    ret rslt(cx, val);
5043 5044
}

5045
fn alloc_local(cx: @block_ctxt, local: @ast::local) -> result {
M
Marijn Haverbeke 已提交
5046 5047
    let t = node_id_type(bcx_ccx(cx), local.node.id);
    let r = alloc_ty(cx, t);
5048 5049 5050
    alt local.node.pat.node {
      ast::pat_bind(ident) {
        if bcx_ccx(cx).sess.get_opts().debuginfo {
B
Brian Anderson 已提交
5051 5052 5053
            let _: () =
                str::as_buf(ident,
                            {|buf| llvm::LLVMSetValueName(r.val, buf) });
5054 5055
        }
      }
B
Brian Anderson 已提交
5056
      _ { }
5057
    }
5058 5059 5060
    ret r;
}

5061 5062 5063 5064 5065 5066 5067
fn trans_block(bcx: @block_ctxt, b: ast::blk) -> result {
    dps_to_result(bcx, {|bcx, dest| trans_block_dps(bcx, b, dest)},
                  ty::node_id_to_type(bcx_tcx(bcx), b.node.id))
}

fn trans_block_dps(bcx: @block_ctxt, b: ast::blk, dest: dest)
    -> @block_ctxt {
5068
    for each local: @ast::local in block_locals(b) {
5069
        // FIXME Update bcx.sp
5070 5071 5072
        let r = alloc_local(bcx, local);
        bcx = r.bcx;
        bcx.fcx.lllocals.insert(local.node.id, r.val);
5073
    }
5074
    for s: @ast::stmt in b.node.stmts {
5075
        bcx = trans_stmt(bcx, *s);
M
Marijn Haverbeke 已提交
5076 5077
    }
    alt b.node.expr {
5078 5079 5080 5081
      some(e) {
        let bt = ty::type_is_bot(bcx_tcx(bcx), ty::expr_ty(bcx_tcx(bcx), e));
        bcx = trans_expr_dps(bcx, e, bt ? ignore : dest);
      }
5082
      _ { assert dest == ignore || bcx.unreachable; }
5083
    }
5084
    ret trans_block_cleanups(bcx, find_scope_cx(bcx));
5085 5086
}

5087
fn new_local_ctxt(ccx: @crate_ctxt) -> @local_ctxt {
B
Brian Anderson 已提交
5088
    let pth: [str] = [];
M
Marijn Haverbeke 已提交
5089
    ret @{path: pth,
5090
          module_path: [ccx.link_meta.name],
B
Brian Anderson 已提交
5091 5092
          obj_typarams: [],
          obj_fields: [],
M
Marijn Haverbeke 已提交
5093
          ccx: ccx};
5094 5095
}

5096

5097 5098
// Creates the standard quartet of basic blocks: static allocas, copy args,
// derived tydescs, and dynamic allocas.
M
Marijn Haverbeke 已提交
5099 5100 5101 5102
fn mk_standard_basic_blocks(llfn: ValueRef) ->
   {sa: BasicBlockRef,
    ca: BasicBlockRef,
    dt: BasicBlockRef,
5103 5104
    da: BasicBlockRef,
    rt: BasicBlockRef} {
B
Brian Anderson 已提交
5105
    ret {sa:
5106
             str::as_buf("static_allocas",
B
Brian Anderson 已提交
5107 5108
                         {|buf| llvm::LLVMAppendBasicBlock(llfn, buf) }),
         ca:
5109
             str::as_buf("load_env",
B
Brian Anderson 已提交
5110 5111 5112 5113 5114 5115 5116 5117 5118 5119
                         {|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) })};
5120 5121
}

5122

5123 5124
// NB: must keep 4 fns in sync:
//
5125
//  - type_of_fn
5126 5127 5128
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args
5129
fn new_fn_ctxt_w_id(cx: @local_ctxt, sp: span, llfndecl: ValueRef,
5130 5131
                    id: ast::node_id, rstyle: ast::ret_style)
    -> @fn_ctxt {
M
Marijn Haverbeke 已提交
5132 5133
    let llbbs = mk_standard_basic_blocks(llfndecl);
    ret @{llfn: llfndecl,
5134 5135 5136
          lltaskptr: llvm::LLVMGetParam(llfndecl, 1u),
          llenv: llvm::LLVMGetParam(llfndecl, 2u),
          llretptr: llvm::LLVMGetParam(llfndecl, 0u),
M
Marijn Haverbeke 已提交
5137
          mutable llstaticallocas: llbbs.sa,
5138
          mutable llloadenv: llbbs.ca,
M
Marijn Haverbeke 已提交
5139 5140 5141
          mutable llderivedtydescs_first: llbbs.dt,
          mutable llderivedtydescs: llbbs.dt,
          mutable lldynamicallocas: llbbs.da,
5142
          mutable llreturn: llbbs.rt,
5143
          mutable llobstacktoken: none::<ValueRef>,
5144 5145 5146
          mutable llself: none::<val_self_pair>,
          mutable lliterbody: none::<ValueRef>,
          mutable iterbodyty: none::<ty::t>,
5147 5148 5149 5150
          llargs: new_int_hash::<ValueRef>(),
          llobjfields: new_int_hash::<ValueRef>(),
          lllocals: new_int_hash::<ValueRef>(),
          llupvars: new_int_hash::<ValueRef>(),
B
Brian Anderson 已提交
5151
          mutable lltydescs: [],
5152
          derived_tydescs: map::mk_hashmap(ty::hash_ty, ty::eq_ty),
5153
          id: id,
5154
          ret_style: rstyle,
M
Marijn Haverbeke 已提交
5155 5156
          sp: sp,
          lcx: cx};
5157 5158
}

5159
fn new_fn_ctxt(cx: @local_ctxt, sp: span, llfndecl: ValueRef) -> @fn_ctxt {
5160
    ret new_fn_ctxt_w_id(cx, sp, llfndecl, -1, ast::return_val);
5161
}
5162

5163 5164
// NB: must keep 4 fns in sync:
//
5165
//  - type_of_fn
5166 5167 5168 5169
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args

L
Lindsey Kuper 已提交
5170 5171 5172 5173 5174 5175 5176
// 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
5177
fn create_llargs_for_fn_args(cx: @fn_ctxt, proto: ast::proto,
5178
                             ty_self: option::t<ty::t>, ret_ty: ty::t,
5179
                             args: [ast::arg], ty_params: [ast::ty_param]) {
L
Lindsey Kuper 已提交
5180 5181 5182
    // Skip the implicit arguments 0, 1, and 2.  TODO: Pull out 3u and define
    // it as a constant, since we're using it in several places in trans this
    // way.
M
Marijn Haverbeke 已提交
5183 5184
    let arg_n = 3u;
    alt ty_self {
5185
      some(tt) { cx.llself = some::<val_self_pair>({v: cx.llenv, t: tt}); }
M
Marijn Haverbeke 已提交
5186 5187
      none. {
        let i = 0u;
5188
        for tp: ast::ty_param in ty_params {
M
Marijn Haverbeke 已提交
5189 5190
            let llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
            assert (llarg as int != 0);
B
Brian Anderson 已提交
5191
            cx.lltydescs += [llarg];
M
Marijn Haverbeke 已提交
5192 5193
            arg_n += 1u;
            i += 1u;
5194
        }
M
Marijn Haverbeke 已提交
5195
      }
5196
    }
5197

L
Lindsey Kuper 已提交
5198 5199 5200
    // If the function is actually an iter, populate the lliterbody field of
    // the function context with the ValueRef that we get from
    // llvm::LLVMGetParam for the iter's body.
M
Marijn Haverbeke 已提交
5201
    if proto == ast::proto_iter {
5202
        cx.iterbodyty = some(ty::mk_iter_body_fn(fcx_tcx(cx), ret_ty));
M
Marijn Haverbeke 已提交
5203
        let llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
5204
        assert (llarg as int != 0);
5205
        cx.lliterbody = some::<ValueRef>(llarg);
5206 5207
        arg_n += 1u;
    }
5208

L
Lindsey Kuper 已提交
5209 5210
    // Populate the llargs field of the function context with the ValueRefs
    // that we get from llvm::LLVMGetParam for each argument.
5211
    for arg: ast::arg in args {
M
Marijn Haverbeke 已提交
5212
        let llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
5213
        assert (llarg as int != 0);
5214 5215 5216 5217 5218
        cx.llargs.insert(arg.id, llarg);
        arg_n += 1u;
    }
}

5219 5220 5221
fn copy_args_to_allocas(fcx: @fn_ctxt, bcx: @block_ctxt, args: [ast::arg],
                        arg_tys: [ty::arg], ignore_mut: bool)
    -> @block_ctxt {
M
Marijn Haverbeke 已提交
5222
    let arg_n: uint = 0u;
5223
    for aarg: ast::arg in args {
5224 5225
        let arg_ty = arg_tys[arg_n].ty;
        alt aarg.mode {
5226
          ast::by_ref. {
5227 5228 5229
            let mutated =
                !ignore_mut && fcx.lcx.ccx.mut_map.contains_key(aarg.id);

5230 5231 5232
            // Overwrite the llargs entry for locally mutated params
            // with a local alloca.
            if mutated {
5233
                let aptr = fcx.llargs.get(aarg.id);
5234 5235 5236 5237
                let {bcx: bcx, val: alloc} = alloc_ty(bcx, arg_ty);
                bcx =
                    copy_val(bcx, INIT, alloc,
                             load_if_immediate(bcx, aptr, arg_ty), arg_ty);
5238 5239
                fcx.llargs.insert(aarg.id, alloc);
                add_clean(bcx, alloc, arg_ty);
5240
            }
5241
          }
5242
          ast::by_move. {
5243
            add_clean(bcx, fcx.llargs.get(aarg.id), arg_ty);
5244
          }
B
Brian Anderson 已提交
5245
          _ { }
5246
        }
5247 5248
        arg_n += 1u;
    }
5249
    ret bcx;
5250 5251
}

5252
fn arg_tys_of_fn(ccx: @crate_ctxt, id: ast::node_id) -> [ty::arg] {
M
Marijn Haverbeke 已提交
5253 5254
    alt ty::struct(ccx.tcx, ty::node_id_to_type(ccx.tcx, id)) {
      ty::ty_fn(_, arg_tys, _, _, _) { ret arg_tys; }
5255 5256 5257
    }
}

M
Marijn Haverbeke 已提交
5258 5259
fn populate_fn_ctxt_from_llself(fcx: @fn_ctxt, llself: val_self_pair) {
    let bcx = llstaticallocas_block_ctxt(fcx);
B
Brian Anderson 已提交
5260
    let field_tys: [ty::t] = [];
5261
    for f: ast::obj_field in bcx.fcx.lcx.obj_fields {
B
Brian Anderson 已提交
5262
        field_tys += [node_id_type(bcx_ccx(bcx), f.id)];
5263
    }
5264 5265 5266
    // Synthesize a tuple type for the fields so that GEP_tup_like() can work
    // its magic.

M
Marijn Haverbeke 已提交
5267
    let fields_tup_ty = ty::mk_tup(fcx.lcx.ccx.tcx, field_tys);
5268
    let n_typarams = std::vec::len::<ast::ty_param>(bcx.fcx.lcx.obj_typarams);
M
Marijn Haverbeke 已提交
5269
    let llobj_box_ty: TypeRef = T_obj_ptr(*bcx_ccx(bcx), n_typarams);
B
Brian Anderson 已提交
5270
    let box_cell = GEP(bcx, llself.v, [C_int(0), C_int(abi::obj_field_box)]);
5271 5272
    let box_ptr = Load(bcx, box_cell);
    box_ptr = PointerCast(bcx, box_ptr, llobj_box_ty);
M
Marijn Haverbeke 已提交
5273
    let obj_typarams =
5274
        GEP(bcx, box_ptr,
B
Brian Anderson 已提交
5275 5276
            [C_int(0), C_int(abi::box_rc_field_body),
             C_int(abi::obj_body_elt_typarams)]);
5277

5278 5279
    // The object fields immediately follow the type parameters, so we skip
    // over them to get the pointer.
5280 5281 5282
    let obj_fields =
        PointerCast(bcx, GEP(bcx, obj_typarams, [C_int(1)]),
                    T_ptr(type_of_or_i8(bcx, fields_tup_ty)));
5283

M
Marijn Haverbeke 已提交
5284
    let i: int = 0;
5285
    for p: ast::ty_param in fcx.lcx.obj_typarams {
M
Marijn Haverbeke 已提交
5286
        let lltyparam: ValueRef =
5287 5288
            GEP(bcx, obj_typarams, [C_int(0), C_int(i)]);
        lltyparam = Load(bcx, lltyparam);
B
Brian Anderson 已提交
5289
        fcx.lltydescs += [lltyparam];
5290 5291 5292
        i += 1;
    }
    i = 0;
5293
    for f: ast::obj_field in fcx.lcx.obj_fields {
5294 5295
        // FIXME: silly check
        check type_is_tup_like(bcx, fields_tup_ty);
B
Brian Anderson 已提交
5296
        let rslt = GEP_tup_like(bcx, fields_tup_ty, obj_fields, [0, i]);
5297
        bcx = llstaticallocas_block_ctxt(fcx);
M
Marijn Haverbeke 已提交
5298
        let llfield = rslt.val;
5299
        fcx.llobjfields.insert(f.id, llfield);
5300 5301
        i += 1;
    }
5302
    fcx.llstaticallocas = bcx.llbb;
5303 5304
}

5305

5306
// Ties up the llstaticallocas -> llloadenv -> llderivedtydescs ->
5307
// lldynamicallocas -> lltop edges, and builds the return block.
5308
fn finish_fn(fcx: @fn_ctxt, lltop: BasicBlockRef) {
5309 5310
    Br(new_raw_block_ctxt(fcx, fcx.llstaticallocas), fcx.llloadenv);
    Br(new_raw_block_ctxt(fcx, fcx.llloadenv), fcx.llderivedtydescs_first);
B
Brian Anderson 已提交
5311
    Br(new_raw_block_ctxt(fcx, fcx.llderivedtydescs), fcx.lldynamicallocas);
5312
    Br(new_raw_block_ctxt(fcx, fcx.lldynamicallocas), lltop);
5313

5314 5315
    let ret_cx = new_raw_block_ctxt(fcx, fcx.llreturn);
    trans_fn_cleanups(fcx, ret_cx);
5316
    RetVoid(ret_cx);
5317 5318
}

5319 5320 5321
// trans_closure: Builds an LLVM function out of a source function.
// If the function closes over its environment a closure will be
// returned.
5322 5323 5324
fn trans_closure(cx: @local_ctxt, sp: span, f: ast::_fn, llfndecl: ValueRef,
                 ty_self: option::t<ty::t>, ty_params: [ast::ty_param],
                 id: ast::node_id, maybe_load_env: block(@fn_ctxt)) {
5325
    set_uwtable(llfndecl);
5326

L
Lindsey Kuper 已提交
5327
    // Set up arguments to the function.
5328
    let fcx = new_fn_ctxt_w_id(cx, sp, llfndecl, id, f.decl.cf);
5329
    create_llargs_for_fn_args(fcx, f.proto, ty_self,
M
Marijn Haverbeke 已提交
5330 5331
                              ty::ret_ty_of_fn(cx.ccx.tcx, id), f.decl.inputs,
                              ty_params);
5332
    alt fcx.llself {
M
Marijn Haverbeke 已提交
5333 5334
      some(llself) { populate_fn_ctxt_from_llself(fcx, llself); }
      _ { }
5335
    }
5336 5337 5338 5339 5340 5341 5342

    // 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;
    let block_ty = node_id_type(cx.ccx, f.body.node.id);

M
Marijn Haverbeke 已提交
5343
    let arg_tys = arg_tys_of_fn(fcx.lcx.ccx, id);
5344
    bcx = copy_args_to_allocas(fcx, bcx, f.decl.inputs, arg_tys, false);
L
Lindsey Kuper 已提交
5345

5346
    maybe_load_env(fcx);
L
Lindsey Kuper 已提交
5347

M
Marijn Haverbeke 已提交
5348 5349 5350 5351
    // This call to trans_block is the place where we bridge between
    // translation calls that don't have a return value (trans_crate,
    // trans_mod, trans_item, trans_obj, et cetera) and those that do
    // (trans_block, trans_expr, et cetera).
5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363
    if ty::type_is_bot(cx.ccx.tcx, block_ty) ||
       ty::type_is_nil(cx.ccx.tcx, block_ty) ||
       f.proto == ast::proto_iter ||
       option::is_none(f.body.node.expr) {
        bcx = trans_block_dps(bcx, f.body, ignore);
    } else if type_is_immediate(cx.ccx, block_ty) {
        let cell = empty_dest_cell();
        bcx = trans_block_dps(bcx, f.body, by_val(cell));
        Store(bcx, *cell, fcx.llretptr);
    } else {
        bcx = trans_block_dps(bcx, f.body, save_in(fcx.llretptr));
    }
5364

5365 5366 5367
    // 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); }
L
Lindsey Kuper 已提交
5368
    // Insert the mandatory first few basic blocks before lltop.
5369
    finish_fn(fcx, lltop);
5370 5371
}

5372 5373 5374
fn trans_fn_inner(cx: @local_ctxt, sp: span, f: ast::_fn, llfndecl: ValueRef,
                  ty_self: option::t<ty::t>, ty_params: [ast::ty_param],
                  id: ast::node_id) {
5375
    trans_closure(cx, sp, f, llfndecl, ty_self, ty_params, id, {|_fcx|});
5376 5377
}

5378 5379 5380

// trans_fn: creates an LLVM function corresponding to a source language
// function.
5381 5382
fn trans_fn(cx: @local_ctxt, sp: span, f: ast::_fn, llfndecl: ValueRef,
            ty_self: option::t<ty::t>, ty_params: [ast::ty_param],
M
Marijn Haverbeke 已提交
5383
            id: ast::node_id) {
5384 5385
    if !cx.ccx.sess.get_opts().stats {
        trans_fn_inner(cx, sp, f, llfndecl, ty_self, ty_params, id);
5386
        ret;
5387 5388
    }

M
Marijn Haverbeke 已提交
5389
    let start = time::get_time();
5390
    trans_fn_inner(cx, sp, f, llfndecl, ty_self, ty_params, id);
M
Marijn Haverbeke 已提交
5391
    let end = time::get_time();
B
Brian Anderson 已提交
5392
    log_fn_time(cx.ccx, str::connect(cx.path, "::"), start, end);
5393 5394
}

5395 5396
fn trans_res_ctor(cx: @local_ctxt, sp: span, dtor: ast::_fn,
                  ctor_id: ast::node_id, ty_params: [ast::ty_param]) {
5397
    // Create a function for the constructor
M
Marijn Haverbeke 已提交
5398 5399 5400
    let llctor_decl;
    alt cx.ccx.item_ids.find(ctor_id) {
      some(x) { llctor_decl = x; }
B
Brian Anderson 已提交
5401
      _ { cx.ccx.sess.span_fatal(sp, "unbound ctor_id in trans_res_ctor"); }
M
Marijn Haverbeke 已提交
5402 5403 5404
    }
    let fcx = new_fn_ctxt(cx, sp, llctor_decl);
    let ret_t = ty::ret_ty_of_fn(cx.ccx.tcx, ctor_id);
5405
    create_llargs_for_fn_args(fcx, ast::proto_fn, none::<ty::t>, ret_t,
M
Marijn Haverbeke 已提交
5406 5407 5408
                              dtor.decl.inputs, ty_params);
    let bcx = new_top_block_ctxt(fcx);
    let lltop = bcx.llbb;
B
Brian Anderson 已提交
5409 5410
    let arg_t = arg_tys_of_fn(cx.ccx, ctor_id)[0].ty;
    let tup_t = ty::mk_tup(cx.ccx.tcx, [ty::mk_int(cx.ccx.tcx), arg_t]);
M
Marijn Haverbeke 已提交
5411
    let arg;
B
Brian Anderson 已提交
5412
    alt fcx.llargs.find(dtor.decl.inputs[0].id) {
M
Marijn Haverbeke 已提交
5413
      some(x) { arg = load_if_immediate(bcx, x, arg_t); }
B
Brian Anderson 已提交
5414
      _ { cx.ccx.sess.span_fatal(sp, "unbound dtor decl in trans_res_ctor"); }
M
Marijn Haverbeke 已提交
5415 5416 5417
    }
    let llretptr = fcx.llretptr;
    if ty::type_has_dynamic_size(cx.ccx.tcx, ret_t) {
B
Brian Anderson 已提交
5418
        let llret_t = T_ptr(T_struct([T_i32(), llvm::LLVMTypeOf(arg)]));
5419
        llretptr = BitCast(bcx, llretptr, llret_t);
5420 5421
    }

5422 5423
    // FIXME: silly checks
    check type_is_tup_like(bcx, tup_t);
B
Brian Anderson 已提交
5424
    let dst = GEP_tup_like(bcx, tup_t, llretptr, [0, 1]);
5425
    bcx = dst.bcx;
5426
    bcx = copy_val(bcx, INIT, dst.val, arg, arg_t);
5427
    check type_is_tup_like(bcx, tup_t);
B
Brian Anderson 已提交
5428
    let flag = GEP_tup_like(bcx, tup_t, llretptr, [0, 0]);
5429
    bcx = flag.bcx;
5430
    Store(bcx, C_int(1), flag.val);
5431
    build_return(bcx);
5432 5433 5434 5435
    finish_fn(fcx, lltop);
}


M
Marijn Haverbeke 已提交
5436
fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
5437 5438
                     variant: ast::variant, index: int, is_degen: bool,
                     ty_params: [ast::ty_param]) {
5439
    if std::vec::len::<ast::variant_arg>(variant.node.args) == 0u {
5440
        ret; // nullary constructors are just constants
5441

5442
    }
5443
    // Translate variant arguments to function arguments.
5444

B
Brian Anderson 已提交
5445
    let fn_args: [ast::arg] = [];
M
Marijn Haverbeke 已提交
5446
    let i = 0u;
5447
    for varg: ast::variant_arg in variant.node.args {
5448
        fn_args +=
5449
            [{mode: ast::by_ref,
B
Brian Anderson 已提交
5450
              ty: varg.ty,
B
Brian Anderson 已提交
5451
              ident: "arg" + uint::to_str(i, 10u),
B
Brian Anderson 已提交
5452
              id: varg.id}];
5453
    }
5454
    assert (cx.ccx.item_ids.contains_key(variant.node.id));
M
Marijn Haverbeke 已提交
5455 5456 5457 5458 5459
    let llfndecl: ValueRef;
    alt cx.ccx.item_ids.find(variant.node.id) {
      some(x) { llfndecl = x; }
      _ {
        cx.ccx.sess.span_fatal(variant.span,
B
Brian Anderson 已提交
5460
                               "unbound variant id in trans_tag_variant");
M
Marijn Haverbeke 已提交
5461
      }
T
Tim Chevalier 已提交
5462
    }
M
Marijn Haverbeke 已提交
5463
    let fcx = new_fn_ctxt(cx, variant.span, llfndecl);
5464
    create_llargs_for_fn_args(fcx, ast::proto_fn, none::<ty::t>,
5465 5466
                              ty::ret_ty_of_fn(cx.ccx.tcx, variant.node.id),
                              fn_args, ty_params);
B
Brian Anderson 已提交
5467
    let ty_param_substs: [ty::t] = [];
5468
    i = 0u;
5469
    for tp: ast::ty_param in ty_params {
B
Brian Anderson 已提交
5470
        ty_param_substs += [ty::mk_param(cx.ccx.tcx, i, tp.kind)];
5471
        i += 1u;
5472
    }
M
Marijn Haverbeke 已提交
5473 5474 5475
    let arg_tys = arg_tys_of_fn(cx.ccx, variant.node.id);
    let bcx = new_top_block_ctxt(fcx);
    let lltop = bcx.llbb;
5476
    bcx = copy_args_to_allocas(fcx, bcx, fn_args, arg_tys, true);
5477

5478 5479
    // Cast the tag to a type we can GEP into.
    let llblobptr =
M
Marijn Haverbeke 已提交
5480 5481 5482 5483
        if is_degen {
            fcx.llretptr
        } else {
            let lltagptr =
5484
                PointerCast(bcx, fcx.llretptr,
B
Brian Anderson 已提交
5485
                            T_opaque_tag_ptr(fcx.lcx.ccx.tn));
5486 5487 5488
            let lldiscrimptr = GEP(bcx, lltagptr, [C_int(0), C_int(0)]);
            Store(bcx, C_int(index), lldiscrimptr);
            GEP(bcx, lltagptr, [C_int(0), C_int(1)])
M
Marijn Haverbeke 已提交
5489
        };
5490
    i = 0u;
T
Tim Chevalier 已提交
5491 5492
    let t_id = ast_util::local_def(tag_id);
    let v_id = ast_util::local_def(variant.node.id);
5493
    for va: ast::variant_arg in variant.node.args {
B
Brian Anderson 已提交
5494 5495
        check (valid_variant_index(i, bcx, t_id, v_id));
        let rslt = GEP_tag(bcx, llblobptr, t_id, v_id, ty_param_substs, i);
5496
        bcx = rslt.bcx;
M
Marijn Haverbeke 已提交
5497
        let lldestptr = rslt.val;
5498 5499 5500 5501
        // If this argument to this function is a tag, it'll have come in to
        // this function as an opaque blob due to the way that type_of()
        // works. So we have to cast to the destination's view of the type.

M
Marijn Haverbeke 已提交
5502 5503
        let llargptr;
        alt fcx.llargs.find(va.id) {
5504
          some(x) { llargptr = PointerCast(bcx, x, val_ty(lldestptr)); }
M
Marijn Haverbeke 已提交
5505
          none. {
B
Brian Anderson 已提交
5506
            bcx_ccx(bcx).sess.bug("unbound argptr in \
5507
                                      trans_tag_variant");
M
Marijn Haverbeke 已提交
5508
          }
T
Tim Chevalier 已提交
5509
        }
B
Brian Anderson 已提交
5510
        let arg_ty = arg_tys[i].ty;
M
Marijn Haverbeke 已提交
5511 5512
        let llargval;
        if ty::type_is_structural(cx.ccx.tcx, arg_ty) ||
B
Brian Anderson 已提交
5513 5514 5515 5516 5517
            ty::type_has_dynamic_size(cx.ccx.tcx, arg_ty) ||
            (ty::type_is_unique(cx.ccx.tcx, arg_ty)
             && !ty::type_is_unique_box(cx.ccx.tcx, arg_ty)) {
            // FIXME: Why do we do this for other unique pointer types but not
            // unique boxes? Something's not quite right.
5518
            llargval = llargptr;
5519
        } else { llargval = Load(bcx, llargptr); }
5520
        bcx = copy_val(bcx, INIT, lldestptr, llargval, arg_ty);
5521 5522 5523
        i += 1u;
    }
    bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
5524
    build_return(bcx);
5525
    finish_fn(fcx, lltop);
5526 5527
}

5528

5529 5530 5531
// 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?
5532
fn trans_const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
M
Marijn Haverbeke 已提交
5533 5534
    alt e.node {
      ast::expr_lit(lit) { ret trans_crate_lit(cx, *lit); }
B
Brian Anderson 已提交
5535
      _ { cx.sess.span_unimpl(e.span, "consts that's not a plain literal"); }
5536 5537 5538
    }
}

5539
fn trans_const(cx: @crate_ctxt, e: @ast::expr, id: ast::node_id) {
M
Marijn Haverbeke 已提交
5540 5541
    let v = trans_const_expr(cx, e);

5542 5543
    // The scalars come back as 1st class LLVM vals
    // which we have to stick into global constants.
5544

M
Marijn Haverbeke 已提交
5545 5546 5547 5548 5549
    alt cx.consts.find(id) {
      some(g) {
        llvm::LLVMSetInitializer(g, v);
        llvm::LLVMSetGlobalConstant(g, True);
      }
B
Brian Anderson 已提交
5550
      _ { cx.sess.span_fatal(e.span, "Unbound const in trans_const"); }
T
Tim Chevalier 已提交
5551
    }
5552 5553
}

5554
fn trans_item(cx: @local_ctxt, item: ast::item) {
M
Marijn Haverbeke 已提交
5555
    alt item.node {
5556
      ast::item_fn(f, tps) {
5557
        let sub_cx = extend_path(cx, item.ident);
M
Marijn Haverbeke 已提交
5558 5559 5560 5561 5562 5563
        alt cx.ccx.item_ids.find(item.id) {
          some(llfndecl) {
            trans_fn(sub_cx, item.span, f, llfndecl, none, tps, item.id);
          }
          _ {
            cx.ccx.sess.span_fatal(item.span,
B
Brian Anderson 已提交
5564
                                   "unbound function item in trans_item");
M
Marijn Haverbeke 已提交
5565
          }
5566
        }
M
Marijn Haverbeke 已提交
5567 5568 5569 5570
      }
      ast::item_obj(ob, tps, ctor_id) {
        let sub_cx =
            @{obj_typarams: tps, obj_fields: ob.fields
5571
                 with *extend_path(cx, item.ident)};
M
Marijn Haverbeke 已提交
5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582
        trans_obj(sub_cx, item.span, ob, ctor_id, tps);
      }
      ast::item_res(dtor, dtor_id, tps, ctor_id) {
        trans_res_ctor(cx, item.span, dtor, ctor_id, tps);

        // Create a function for the destructor
        alt cx.ccx.item_ids.find(item.id) {
          some(lldtor_decl) {
            trans_fn(cx, item.span, dtor, lldtor_decl, none, tps, dtor_id);
          }
          _ {
B
Brian Anderson 已提交
5583
            cx.ccx.sess.span_fatal(item.span, "unbound dtor in trans_item");
M
Marijn Haverbeke 已提交
5584
          }
5585
        }
M
Marijn Haverbeke 已提交
5586 5587 5588
      }
      ast::item_mod(m) {
        let sub_cx =
5589
            @{path: cx.path + [item.ident],
B
Brian Anderson 已提交
5590
              module_path: cx.module_path + [item.ident] with *cx};
M
Marijn Haverbeke 已提交
5591 5592 5593
        trans_mod(sub_cx, m);
      }
      ast::item_tag(variants, tps) {
5594
        let sub_cx = extend_path(cx, item.ident);
B
Brian Anderson 已提交
5595
        let degen = std::vec::len(variants) == 1u;
M
Marijn Haverbeke 已提交
5596
        let i = 0;
5597
        for variant: ast::variant in variants {
M
Marijn Haverbeke 已提交
5598 5599
            trans_tag_variant(sub_cx, item.id, variant, i, degen, tps);
            i += 1;
5600
        }
M
Marijn Haverbeke 已提交
5601 5602 5603
      }
      ast::item_const(_, expr) { trans_const(cx.ccx, expr, item.id); }
      _ {/* fall through */ }
5604 5605 5606
    }
}

5607

5608 5609 5610 5611 5612
// Translate a module.  Doing this amounts to translating the items in the
// module; there ends up being no artifact (aside from linkage names) of
// separate modules in the compiled program.  That's because modules exist
// only as a convenience for humans working with the code, to organize names
// and control visibility.
5613
fn trans_mod(cx: @local_ctxt, m: ast::_mod) {
5614
    for item: @ast::item in m.items { trans_item(cx, *item); }
5615 5616
}

M
Marijn Haverbeke 已提交
5617
fn get_pair_fn_ty(llpairty: TypeRef) -> TypeRef {
5618
    // Bit of a kludge: pick the fn typeref out of the pair.
5619

5620
    ret struct_elt(llpairty, 0u);
5621 5622
}

5623 5624
fn register_fn(ccx: @crate_ctxt, sp: span, path: [str], flav: str,
               ty_params: [ast::ty_param], node_id: ast::node_id) {
5625 5626 5627
    // FIXME: pull this out
    let t = node_id_type(ccx, node_id);
    check returns_non_ty_var(ccx, t);
5628
    register_fn_full(ccx, sp, path, flav, ty_params, node_id, t);
5629 5630
}

5631 5632 5633
fn register_fn_full(ccx: @crate_ctxt, sp: span, path: [str], _flav: str,
                    ty_params: [ast::ty_param], node_id: ast::node_id,
                    node_type: ty::t)
5634
    : returns_non_ty_var(ccx, node_type) {
5635
    let path = path;
B
Brian Anderson 已提交
5636 5637
    let llfty =
        type_of_fn_from_ty(ccx, sp, node_type, std::vec::len(ty_params));
M
Marijn Haverbeke 已提交
5638
    alt ty::struct(ccx.tcx, node_type) {
5639
      ty::ty_fn(proto, inputs, output, rs, _) {
5640
        check non_ty_var(ccx, output);
5641
        llfty = type_of_fn(ccx, sp, proto, false,
5642
                           ast_util::ret_by_ref(rs), inputs, output,
5643
                           vec::len(ty_params));
M
Marijn Haverbeke 已提交
5644
      }
5645
      _ { ccx.sess.bug("register_fn(): fn item doesn't have fn type!"); }
5646
    }
B
Brian Anderson 已提交
5647
    let ps: str = mangle_exported_name(ccx, path, node_type);
5648
    let llfn: ValueRef = decl_cdecl_fn(ccx.llmod, ps, llfty);
5649 5650
    ccx.item_ids.insert(node_id, llfn);
    ccx.item_symbols.insert(node_id, ps);
5651 5652

    let is_main: bool = is_main_name(path) && !ccx.sess.get_opts().library;
B
Brian Anderson 已提交
5653
    if is_main { create_main_wrapper(ccx, sp, llfn, node_type); }
5654 5655
}

5656 5657
// Create a _rust_main(args: [str]) function which will be called from the
// runtime rust_start function
5658
fn create_main_wrapper(ccx: @crate_ctxt, sp: span, main_llfn: ValueRef,
B
Brian Anderson 已提交
5659
                       main_node_type: ty::t) {
5660

5661
    if ccx.main_fn != none::<ValueRef> {
B
Brian Anderson 已提交
5662
        ccx.sess.span_fatal(sp, "multiple 'main' functions");
5663 5664
    }

5665
    let main_takes_argv =
B
Brian Anderson 已提交
5666
        alt ty::struct(ccx.tcx, main_node_type) {
B
Brian Anderson 已提交
5667
          ty::ty_fn(_, args, _, _, _) { std::vec::len(args) != 0u }
B
Brian Anderson 已提交
5668
        };
5669

B
Brian Anderson 已提交
5670
    let llfn = create_main(ccx, sp, main_llfn, main_takes_argv);
5671
    ccx.main_fn = some(llfn);
5672

5673
    fn create_main(ccx: @crate_ctxt, sp: span, main_llfn: ValueRef,
5674
                   takes_argv: bool) -> ValueRef {
5675
        let unit_ty = ty::mk_str(ccx.tcx);
5676
        let vecarg_ty: ty::arg =
5677
            {mode: ast::by_ref,
B
Brian Anderson 已提交
5678
             ty: ty::mk_vec(ccx.tcx, {ty: unit_ty, mut: ast::imm})};
5679
        // FIXME: mk_nil should have a postcondition
5680 5681 5682
        let nt = ty::mk_nil(ccx.tcx);
        check non_ty_var(ccx, nt);

5683
        let llfty = type_of_fn(ccx, sp, ast::proto_fn, false, false,
5684
                               [vecarg_ty], nt, 0u);
5685 5686
        let llfdecl = decl_fn(ccx.llmod, "_rust_main",
                              lib::llvm::LLVMFastCallConv, llfty);
5687 5688

        let fcx = new_fn_ctxt(new_local_ctxt(ccx), sp, llfdecl);
5689

5690
        let bcx = new_top_block_ctxt(fcx);
5691
        let lltop = bcx.llbb;
5692

5693 5694 5695
        let lloutputarg = llvm::LLVMGetParam(llfdecl, 0u);
        let lltaskarg = llvm::LLVMGetParam(llfdecl, 1u);
        let llenvarg = llvm::LLVMGetParam(llfdecl, 2u);
5696
        let args = [lloutputarg, lltaskarg, llenvarg];
5697 5698 5699 5700 5701 5702 5703 5704
        if takes_argv {
            let llargvarg = llvm::LLVMGetParam(llfdecl, 3u);
            // The runtime still passes the arg vector by value, this kludge
            // makes sure it becomes a pointer (to a pointer to a vec).
            let minus_ptr = llvm::LLVMGetElementType(val_ty(llargvarg));
            llargvarg = PointerCast(bcx, llargvarg, minus_ptr);
            args += [do_spill_noroot(bcx, llargvarg)];
        }
5705
        Call(bcx, main_llfn, args);
5706
        build_return(bcx);
5707 5708 5709 5710 5711

        finish_fn(fcx, lltop);

        ret llfdecl;
    }
5712 5713
}

5714 5715 5716
// 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).
5717
fn create_real_fn_pair(cx: @block_ctxt, llfnty: TypeRef, llfn: ValueRef,
M
Marijn Haverbeke 已提交
5718 5719
                       llenvptr: ValueRef) -> ValueRef {
    let lcx = cx.fcx.lcx;
5720

M
Marijn Haverbeke 已提交
5721
    let pair = alloca(cx, T_fn_pair(*lcx.ccx, llfnty));
5722
    fill_fn_pair(cx, pair, llfn, llenvptr);
5723 5724 5725
    ret pair;
}

5726 5727 5728 5729 5730 5731 5732 5733 5734 5735
fn fill_fn_pair(bcx: @block_ctxt, pair: ValueRef, llfn: ValueRef,
                llenvptr: ValueRef) {
    let code_cell = GEP(bcx, pair, [C_int(0), C_int(abi::fn_field_code)]);
    Store(bcx, llfn, code_cell);
    let env_cell = GEP(bcx, pair, [C_int(0), C_int(abi::fn_field_box)]);
    let llenvblobptr =
        PointerCast(bcx, llenvptr, T_opaque_closure_ptr(*bcx_ccx(bcx)));
    Store(bcx, llenvblobptr, env_cell);
}

5736
// Returns the number of type parameters that the given native function has.
5737
fn native_fn_ty_param_count(cx: @crate_ctxt, id: ast::node_id) -> uint {
M
Marijn Haverbeke 已提交
5738 5739 5740 5741 5742
    let count;
    let native_item =
        alt cx.ast_map.find(id) { some(ast_map::node_native_item(i)) { i } };
    alt native_item.node {
      ast::native_item_ty. {
5743
        cx.sess.bug("register_native_fn(): native fn isn't \
5744
                        actually a fn");
M
Marijn Haverbeke 已提交
5745 5746
      }
      ast::native_item_fn(_, _, tps) {
5747
        count = std::vec::len::<ast::ty_param>(tps);
M
Marijn Haverbeke 已提交
5748
      }
5749 5750 5751 5752
    }
    ret count;
}

5753
pure fn native_abi_requires_pair(abi: ast::native_abi) -> bool {
5754 5755 5756 5757
    alt abi {
        ast::native_abi_rust. | ast::native_abi_cdecl. |
        ast::native_abi_llvm. | ast::native_abi_rust_intrinsic. |
        ast::native_abi_x86stdcall. { ret true; }
P
Patrick Walton 已提交
5758 5759
        ast::native_abi_c_stack_cdecl. |
        ast::native_abi_c_stack_stdcall. { ret false; }
5760 5761 5762
    }
}

5763 5764 5765 5766 5767 5768 5769
pure fn type_is_native_fn_on_c_stack(tcx: ty::ctxt, t: ty::t) -> bool {
    alt ty::struct(tcx, t) {
        ty::ty_native_fn(abi, _, _) { ret !native_abi_requires_pair(abi); }
        _ { ret false; }
    }
}

5770
fn native_fn_wrapper_type(cx: @crate_ctxt, sp: span, ty_param_count: uint,
M
Marijn Haverbeke 已提交
5771 5772 5773
                          x: ty::t) -> TypeRef {
    alt ty::struct(cx.tcx, x) {
      ty::ty_native_fn(abi, args, out) {
5774
        check non_ty_var(cx, out);
5775 5776
        ret type_of_fn(cx, sp, ast::proto_fn, false, false, args, out,
                       ty_param_count);
M
Marijn Haverbeke 已提交
5777
      }
5778 5779 5780
    }
}

5781 5782 5783 5784 5785 5786
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));
}

5787
fn register_native_fn(ccx: @crate_ctxt, sp: span, path: [str], name: str,
5788
                           id: ast::node_id) {
M
Marijn Haverbeke 已提交
5789 5790
    let fn_type = node_id_type(ccx, id); // NB: has no type params
    let abi = ty::ty_fn_abi(ccx.tcx, fn_type);
5791

M
Marijn Haverbeke 已提交
5792 5793 5794 5795 5796
    let pass_task;
    let uses_retptr;
    let cast_to_i32;
    alt abi {
      ast::native_abi_rust. {
5797 5798 5799 5800
        pass_task = true;
        uses_retptr = false;
        cast_to_i32 = true;
      }
M
Marijn Haverbeke 已提交
5801
      ast::native_abi_rust_intrinsic. {
5802 5803 5804 5805
        pass_task = true;
        uses_retptr = true;
        cast_to_i32 = false;
      }
M
Marijn Haverbeke 已提交
5806
      ast::native_abi_cdecl. {
5807 5808 5809 5810
        pass_task = false;
        uses_retptr = false;
        cast_to_i32 = true;
      }
M
Marijn Haverbeke 已提交
5811
      ast::native_abi_llvm. {
5812 5813 5814 5815
        pass_task = false;
        uses_retptr = false;
        cast_to_i32 = false;
      }
M
Marijn Haverbeke 已提交
5816
      ast::native_abi_x86stdcall. {
B
Brian Anderson 已提交
5817 5818 5819 5820
        pass_task = false;
        uses_retptr = false;
        cast_to_i32 = true;
      }
5821
      ast::native_abi_c_stack_cdecl. {
5822
        let llfn = decl_cdecl_fn(ccx.llmod, name, T_fn([], T_int()));
5823 5824 5825
        ccx.item_ids.insert(id, llfn);
        ccx.item_symbols.insert(id, name);
        ret;
5826
      }
P
Patrick Walton 已提交
5827 5828 5829 5830 5831 5832 5833
      ast::native_abi_c_stack_stdcall. {
        let llfn = decl_fn(ccx.llmod, name, lib::llvm::LLVMX86StdcallCallConv,
                           T_fn([], T_int()));
        ccx.item_ids.insert(id, llfn);
        ccx.item_symbols.insert(id, name);
        ret;
      }
5834
    }
5835

5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859
    let path = path;
    let num_ty_param = native_fn_ty_param_count(ccx, id);
    // Declare the wrapper.

    let t = node_id_type(ccx, id);
    let wrapper_type = native_fn_wrapper_type(ccx, sp, num_ty_param, t);
    let ps: str = mangle_exported_name(ccx, path, node_id_type(ccx, id));
    let wrapper_fn = decl_cdecl_fn(ccx.llmod, ps, wrapper_type);
    ccx.item_ids.insert(id, wrapper_fn);
    ccx.item_symbols.insert(id, ps);

    // Build the wrapper.
    let fcx = new_fn_ctxt(new_local_ctxt(ccx), sp, wrapper_fn);
    let bcx = new_top_block_ctxt(fcx);
    let lltop = bcx.llbb;

    // Declare the function itself.
    // FIXME: If the returned type is not nil, then we assume it's 32 bits
    // wide. This is obviously wildly unsafe. We should have a better FFI
    // that allows types of different sizes to be returned.

    let rty = ty::ty_fn_ret(ccx.tcx, fn_type);
    let rty_is_nil = ty::type_is_nil(ccx.tcx, rty);

M
Marijn Haverbeke 已提交
5860 5861
    let lltaskptr;
    if cast_to_i32 {
5862
        lltaskptr = vp2i(bcx, fcx.lltaskptr);
5863
    } else { lltaskptr = fcx.lltaskptr; }
5864

B
Brian Anderson 已提交
5865 5866 5867
    let call_args: [ValueRef] = [];
    if pass_task { call_args += [lltaskptr]; }
    if uses_retptr { call_args += [bcx.fcx.llretptr]; }
5868

M
Marijn Haverbeke 已提交
5869
    let arg_n = 3u;
5870
    for each i: uint in uint::range(0u, num_ty_param) {
M
Marijn Haverbeke 已提交
5871
        let llarg = llvm::LLVMGetParam(fcx.llfn, arg_n);
B
Brian Anderson 已提交
5872
        fcx.lltydescs += [llarg];
5873
        assert (llarg as int != 0);
M
Marijn Haverbeke 已提交
5874
        if cast_to_i32 {
B
Brian Anderson 已提交
5875 5876
            call_args += [vp2i(bcx, llarg)];
        } else { call_args += [llarg]; }
5877
        arg_n += 1u;
5878
    }
5879
    fn convert_arg_to_i32(cx: @block_ctxt, v: ValueRef, t: ty::t,
M
Marijn Haverbeke 已提交
5880
                          mode: ty::mode) -> ValueRef {
5881
        if mode == ast::by_ref {
M
Marijn Haverbeke 已提交
5882
            if ty::type_is_integral(bcx_tcx(cx), t) {
5883 5884
                // FIXME: would be nice to have a postcondition that says
                // if a type is integral, then it has static size (#586)
M
Marijn Haverbeke 已提交
5885
                let lldsttype = T_int();
5886 5887
                let ccx = bcx_ccx(cx);
                let sp = cx.sp;
5888
                check (type_has_static_size(ccx, t));
5889
                let llsrctype = type_of(ccx, sp, t);
M
Marijn Haverbeke 已提交
5890 5891
                if llvm::LLVMGetIntTypeWidth(lldsttype) >
                       llvm::LLVMGetIntTypeWidth(llsrctype) {
5892
                    ret ZExtOrBitCast(cx, v, T_int());
5893
                }
5894
                ret TruncOrBitCast(cx, v, T_int());
5895
            }
B
Brian Anderson 已提交
5896
            if ty::type_is_fp(bcx_tcx(cx), t) { ret FPToSI(cx, v, T_int()); }
5897
        }
5898
        ret vp2i(cx, v);
5899
    }
5900

5901
    fn trans_simple_native_abi(bcx: @block_ctxt, name: str,
5902
                               &call_args: [ValueRef], fn_type: ty::t,
B
Brian Anderson 已提交
5903 5904 5905 5906
                               uses_retptr: bool, cc: uint) ->
       {val: ValueRef, rptr: ValueRef} {
        let call_arg_tys: [TypeRef] = [];
        for arg: ValueRef in call_args { call_arg_tys += [val_ty(arg)]; }
5907
        let ccx = bcx_ccx(bcx);
5908

5909
        let llnativefnty =
5910 5911 5912
            if uses_retptr {
                T_fn(call_arg_tys, T_void())
            } else {
5913 5914
                let fn_ret_ty = ty::ty_fn_ret(bcx_tcx(bcx), fn_type);
                // FIXME: Could follow from a constraint on fn_type...
5915
                check (type_has_static_size(ccx, fn_ret_ty));
5916 5917 5918
                let sp = bcx.sp;
                T_fn(call_arg_tys, type_of(ccx, sp, fn_ret_ty))
            };
5919

M
Marijn Haverbeke 已提交
5920
        let llnativefn =
5921
            get_extern_fn(ccx.externs, ccx.llmod, name, cc, llnativefnty);
M
Marijn Haverbeke 已提交
5922 5923
        let r =
            if cc == lib::llvm::LLVMCCallConv {
5924 5925
                Call(bcx, llnativefn, call_args)
            } else { CallWithConv(bcx, llnativefn, call_args, cc) };
M
Marijn Haverbeke 已提交
5926 5927
        let rptr = bcx.fcx.llretptr;
        ret {val: r, rptr: rptr};
5928
    }
5929

M
Marijn Haverbeke 已提交
5930
    let args = ty::ty_fn_args(ccx.tcx, fn_type);
5931
    // Build up the list of arguments.
5932

M
Marijn Haverbeke 已提交
5933
    let i = arg_n;
5934
    for arg: ty::arg in args {
M
Marijn Haverbeke 已提交
5935
        let llarg = llvm::LLVMGetParam(fcx.llfn, i);
5936
        if arg.mode == ast::by_ref {
5937 5938
            llarg = load_if_immediate(bcx, llarg, arg.ty);
        }
5939
        assert (llarg as int != 0);
M
Marijn Haverbeke 已提交
5940 5941
        if cast_to_i32 {
            let llarg_i32 = convert_arg_to_i32(bcx, llarg, arg.ty, arg.mode);
B
Brian Anderson 已提交
5942 5943
            call_args += [llarg_i32];
        } else { call_args += [llarg]; }
5944 5945
        i += 1u;
    }
M
Marijn Haverbeke 已提交
5946 5947 5948 5949 5950
    let r;
    let rptr;
    alt abi {
      ast::native_abi_llvm. {
        let result =
5951
            trans_simple_native_abi(bcx, name, call_args, fn_type,
M
Marijn Haverbeke 已提交
5952 5953 5954 5955 5956
                                    uses_retptr, lib::llvm::LLVMCCallConv);
        r = result.val;
        rptr = result.rptr;
      }
      ast::native_abi_rust_intrinsic. {
B
Brian Anderson 已提交
5957
        let external_name = "rust_intrinsic_" + name;
M
Marijn Haverbeke 已提交
5958 5959
        let result =
            trans_simple_native_abi(bcx, external_name, call_args, fn_type,
5960
                                    uses_retptr, lib::llvm::LLVMCCallConv);
M
Marijn Haverbeke 已提交
5961 5962 5963 5964 5965
        r = result.val;
        rptr = result.rptr;
      }
      ast::native_abi_x86stdcall. {
        let result =
5966
            trans_simple_native_abi(bcx, name, call_args, fn_type,
M
Marijn Haverbeke 已提交
5967 5968 5969 5970 5971 5972
                                    uses_retptr,
                                    lib::llvm::LLVMX86StdcallCallConv);
        r = result.val;
        rptr = result.rptr;
      }
      _ {
5973 5974
        r =
            trans_native_call(new_raw_block_ctxt(bcx.fcx, bcx.llbb),
5975
                              ccx.externs, ccx.llmod, name, call_args);
5976
        rptr = BitCast(bcx, fcx.llretptr, T_ptr(T_i32()));
M
Marijn Haverbeke 已提交
5977
      }
5978
    }
5979 5980 5981 5982
    // We don't store the return value if it's nil, to avoid stomping on a nil
    // pointer. This is the only concession made to non-i32 return values. See
    // the FIXME above.

5983
    if !rty_is_nil && !uses_retptr { Store(bcx, r, rptr); }
5984

5985
    build_return(bcx);
5986
    finish_fn(fcx, lltop);
5987 5988
}

5989
fn item_path(item: @ast::item) -> [str] { ret [item.ident]; }
5990

5991 5992
fn collect_native_item(ccx: @crate_ctxt, i: @ast::native_item, pt: [str],
                       _v: vt<[str]>) {
M
Marijn Haverbeke 已提交
5993 5994 5995
    alt i.node {
      ast::native_item_fn(_, _, _) {
        if !ccx.obj_methods.contains_key(i.id) {
5996
            register_native_fn(ccx, i.span, pt, i.ident, i.id);
5997
        }
M
Marijn Haverbeke 已提交
5998 5999
      }
      _ { }
6000 6001
    }
}
6002

6003
fn collect_item_1(ccx: @crate_ctxt, i: @ast::item, pt: [str], v: vt<[str]>) {
6004
    visit::visit_item(i, pt + item_path(i), v);
M
Marijn Haverbeke 已提交
6005 6006 6007 6008
    alt i.node {
      ast::item_const(_, _) {
        let typ = node_id_type(ccx, i.id);
        let s =
6009
            mangle_exported_name(ccx, pt + [i.ident],
M
Marijn Haverbeke 已提交
6010
                                 node_id_type(ccx, i.id));
6011 6012 6013 6014 6015 6016
        // 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)
        });
6017
        ccx.item_symbols.insert(i.id, s);
M
Marijn Haverbeke 已提交
6018 6019 6020
        ccx.consts.insert(i.id, g);
      }
      _ { }
6021 6022 6023
    }
}

6024
fn collect_item_2(ccx: @crate_ctxt, i: @ast::item, pt: [str], v: vt<[str]>) {
M
Marijn Haverbeke 已提交
6025
    let new_pt = pt + item_path(i);
6026
    visit::visit_item(i, new_pt, v);
M
Marijn Haverbeke 已提交
6027
    alt i.node {
6028
      ast::item_fn(f, tps) {
M
Marijn Haverbeke 已提交
6029
        if !ccx.obj_methods.contains_key(i.id) {
6030
            register_fn(ccx, i.span, new_pt, "fn", tps, i.id);
6031
        }
M
Marijn Haverbeke 已提交
6032 6033
      }
      ast::item_obj(ob, tps, ctor_id) {
6034
        register_fn(ccx, i.span, new_pt, "obj_ctor", tps, ctor_id);
6035
        for m: @ast::method in ob.methods {
M
Marijn Haverbeke 已提交
6036
            ccx.obj_methods.insert(m.node.id, ());
6037
        }
M
Marijn Haverbeke 已提交
6038 6039
      }
      ast::item_res(_, dtor_id, tps, ctor_id) {
6040
        register_fn(ccx, i.span, new_pt, "res_ctor", tps, ctor_id);
M
Marijn Haverbeke 已提交
6041 6042 6043 6044
        // 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.
6045 6046 6047
        let t = node_id_type(ccx, dtor_id);
        // FIXME: how to get rid of this check?
        check returns_non_ty_var(ccx, t);
6048
        register_fn_full(ccx, i.span, new_pt, "res_dtor", tps, i.id, t);
M
Marijn Haverbeke 已提交
6049 6050
      }
      _ { }
6051 6052 6053
    }
}

6054
fn collect_items(ccx: @crate_ctxt, crate: @ast::crate) {
M
Marijn Haverbeke 已提交
6055 6056 6057 6058 6059 6060
    let visitor0 = visit::default_visitor();
    let visitor1 =
        @{visit_native_item: bind collect_native_item(ccx, _, _, _),
          visit_item: bind collect_item_1(ccx, _, _, _) with *visitor0};
    let visitor2 =
        @{visit_item: bind collect_item_2(ccx, _, _, _) with *visitor0};
B
Brian Anderson 已提交
6061 6062
    visit::visit_crate(*crate, [], visit::mk_vt(visitor1));
    visit::visit_crate(*crate, [], visit::mk_vt(visitor2));
6063 6064
}

6065 6066
fn collect_tag_ctor(ccx: @crate_ctxt, i: @ast::item, pt: [str],
                    v: vt<[str]>) {
M
Marijn Haverbeke 已提交
6067
    let new_pt = pt + item_path(i);
6068
    visit::visit_item(i, new_pt, v);
M
Marijn Haverbeke 已提交
6069 6070
    alt i.node {
      ast::item_tag(variants, tps) {
6071
        for variant: ast::variant in variants {
B
Brian Anderson 已提交
6072
            if std::vec::len(variant.node.args) != 0u {
6073 6074
                register_fn(ccx, i.span, new_pt + [variant.node.name],
                            "tag", tps, variant.node.id);
6075 6076
            }
        }
M
Marijn Haverbeke 已提交
6077 6078
      }
      _ {/* fall through */ }
6079 6080 6081
    }
}

6082
fn collect_tag_ctors(ccx: @crate_ctxt, crate: @ast::crate) {
M
Marijn Haverbeke 已提交
6083 6084 6085
    let visitor =
        @{visit_item: bind collect_tag_ctor(ccx, _, _, _)
             with *visit::default_visitor()};
B
Brian Anderson 已提交
6086
    visit::visit_crate(*crate, [], visit::mk_vt(visitor));
6087 6088
}

6089

6090
// The constant translation pass.
6091
fn trans_constant(ccx: @crate_ctxt, it: @ast::item, pt: [str], v: vt<[str]>) {
M
Marijn Haverbeke 已提交
6092
    let new_pt = pt + item_path(it);
6093
    visit::visit_item(it, new_pt, v);
M
Marijn Haverbeke 已提交
6094 6095 6096
    alt it.node {
      ast::item_tag(variants, _) {
        let i = 0u;
6097
        let n_variants = std::vec::len::<ast::variant>(variants);
M
Marijn Haverbeke 已提交
6098
        while i < n_variants {
B
Brian Anderson 已提交
6099
            let variant = variants[i];
B
Brian Anderson 已提交
6100 6101 6102 6103 6104 6105 6106
            let p = new_pt + [it.ident, variant.node.name, "discrim"];
            let s = mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx));
            let discrim_gvar =
                str::as_buf(s,
                            {|buf|
                                llvm::LLVMAddGlobal(ccx.llmod, T_int(), buf)
                            });
6107 6108
            llvm::LLVMSetInitializer(discrim_gvar, C_int(i as int));
            llvm::LLVMSetGlobalConstant(discrim_gvar, True);
M
Marijn Haverbeke 已提交
6109
            ccx.discrims.insert(variant.node.id, discrim_gvar);
6110
            ccx.discrim_symbols.insert(variant.node.id, s);
M
Marijn Haverbeke 已提交
6111
            i += 1u;
6112
        }
M
Marijn Haverbeke 已提交
6113 6114
      }
      _ { }
6115 6116 6117
    }
}

6118
fn trans_constants(ccx: @crate_ctxt, crate: @ast::crate) {
M
Marijn Haverbeke 已提交
6119 6120 6121
    let visitor =
        @{visit_item: bind trans_constant(ccx, _, _, _)
             with *visit::default_visitor()};
B
Brian Anderson 已提交
6122
    visit::visit_crate(*crate, [], visit::mk_vt(visitor));
6123 6124
}

6125
fn vp2i(cx: @block_ctxt, v: ValueRef) -> ValueRef {
6126
    ret PtrToInt(cx, v, T_int());
6127 6128
}

M
Marijn Haverbeke 已提交
6129
fn p2i(v: ValueRef) -> ValueRef { ret llvm::LLVMConstPtrToInt(v, T_int()); }
6130

B
Brian Anderson 已提交
6131
fn declare_intrinsics(llmod: ModuleRef) -> hashmap<str, ValueRef> {
6132
    let T_memmove32_args: [TypeRef] =
B
Brian Anderson 已提交
6133
        [T_ptr(T_i8()), T_ptr(T_i8()), T_i32(), T_i32(), T_i1()];
6134
    let T_memmove64_args: [TypeRef] =
B
Brian Anderson 已提交
6135
        [T_ptr(T_i8()), T_ptr(T_i8()), T_i64(), T_i32(), T_i1()];
6136
    let T_memset32_args: [TypeRef] =
B
Brian Anderson 已提交
6137
        [T_ptr(T_i8()), T_i8(), T_i32(), T_i32(), T_i1()];
6138
    let T_memset64_args: [TypeRef] =
B
Brian Anderson 已提交
6139 6140
        [T_ptr(T_i8()), T_i8(), T_i64(), T_i32(), T_i1()];
    let T_trap_args: [TypeRef] = [];
6141
    let gcroot =
B
Brian Anderson 已提交
6142
        decl_cdecl_fn(llmod, "llvm.gcroot",
B
Brian Anderson 已提交
6143
                      T_fn([T_ptr(T_ptr(T_i8())), T_ptr(T_i8())], T_void()));
6144
    let gcread =
B
Brian Anderson 已提交
6145
        decl_cdecl_fn(llmod, "llvm.gcread",
B
Brian Anderson 已提交
6146
                      T_fn([T_ptr(T_i8()), T_ptr(T_ptr(T_i8()))], T_void()));
M
Marijn Haverbeke 已提交
6147
    let memmove32 =
B
Brian Anderson 已提交
6148
        decl_cdecl_fn(llmod, "llvm.memmove.p0i8.p0i8.i32",
6149
                      T_fn(T_memmove32_args, T_void()));
M
Marijn Haverbeke 已提交
6150
    let memmove64 =
B
Brian Anderson 已提交
6151
        decl_cdecl_fn(llmod, "llvm.memmove.p0i8.p0i8.i64",
6152
                      T_fn(T_memmove64_args, T_void()));
M
Marijn Haverbeke 已提交
6153
    let memset32 =
B
Brian Anderson 已提交
6154
        decl_cdecl_fn(llmod, "llvm.memset.p0i8.i32",
6155
                      T_fn(T_memset32_args, T_void()));
M
Marijn Haverbeke 已提交
6156
    let memset64 =
B
Brian Anderson 已提交
6157
        decl_cdecl_fn(llmod, "llvm.memset.p0i8.i64",
6158
                      T_fn(T_memset64_args, T_void()));
B
Brian Anderson 已提交
6159
    let trap = decl_cdecl_fn(llmod, "llvm.trap", T_fn(T_trap_args, T_void()));
6160
    let intrinsics = new_str_hash::<ValueRef>();
B
Brian Anderson 已提交
6161 6162 6163 6164 6165 6166 6167
    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);
6168
    ret intrinsics;
6169 6170
}

6171
fn trap(bcx: @block_ctxt) {
B
Brian Anderson 已提交
6172
    let v: [ValueRef] = [];
B
Brian Anderson 已提交
6173
    alt bcx_ccx(bcx).intrinsics.find("llvm.trap") {
6174
      some(x) { Call(bcx, x, v); }
B
Brian Anderson 已提交
6175
      _ { bcx_ccx(bcx).sess.bug("unbound llvm.trap in trap"); }
T
Tim Chevalier 已提交
6176
    }
6177
}
6178

M
Marijn Haverbeke 已提交
6179
fn decl_no_op_type_glue(llmod: ModuleRef, taskptr_type: TypeRef) -> ValueRef {
B
Brian Anderson 已提交
6180
    let ty = T_fn([taskptr_type, T_ptr(T_i8())], T_void());
6181
    ret decl_cdecl_fn(llmod, abi::no_op_type_glue_name(), ty);
6182 6183
}

6184
fn create_module_map(ccx: @crate_ctxt) -> ValueRef {
B
Brian Anderson 已提交
6185
    let elttype = T_struct([T_int(), T_int()]);
M
Marijn Haverbeke 已提交
6186
    let maptype = T_array(elttype, ccx.module_data.size() + 1u);
B
Brian Anderson 已提交
6187 6188 6189
    let map =
        str::as_buf("_rust_mod_map",
                    {|buf| llvm::LLVMAddGlobal(ccx.llmod, maptype, buf) });
6190
    llvm::LLVMSetLinkage(map,
M
Marijn Haverbeke 已提交
6191
                         lib::llvm::LLVMInternalLinkage as llvm::Linkage);
B
Brian Anderson 已提交
6192
    let elts: [ValueRef] = [];
B
Brian Anderson 已提交
6193 6194
    for each item: @{key: str, val: ValueRef} in ccx.module_data.items() {
        let elt = C_struct([p2i(C_cstr(ccx, item.key)), p2i(item.val)]);
B
Brian Anderson 已提交
6195
        elts += [elt];
6196
    }
B
Brian Anderson 已提交
6197 6198
    let term = C_struct([C_int(0), C_int(0)]);
    elts += [term];
6199
    llvm::LLVMSetInitializer(map, C_array(elttype, elts));
6200 6201 6202
    ret map;
}

6203

6204
// FIXME use hashed metadata instead of crate names once we have that
6205
fn create_crate_map(ccx: @crate_ctxt) -> ValueRef {
B
Brian Anderson 已提交
6206
    let subcrates: [ValueRef] = [];
M
Marijn Haverbeke 已提交
6207 6208 6209
    let i = 1;
    let cstore = ccx.sess.get_cstore();
    while cstore::have_crate_data(cstore, i) {
B
Brian Anderson 已提交
6210 6211 6212 6213 6214 6215
        let nm = "_rust_crate_map_" + cstore::get_crate_data(cstore, i).name;
        let cr =
            str::as_buf(nm,
                        {|buf|
                            llvm::LLVMAddGlobal(ccx.llmod, T_int(), buf)
                        });
B
Brian Anderson 已提交
6216
        subcrates += [p2i(cr)];
6217 6218
        i += 1;
    }
B
Brian Anderson 已提交
6219
    subcrates += [C_int(0)];
M
Marijn Haverbeke 已提交
6220 6221
    let mapname;
    if ccx.sess.get_opts().library {
6222
        mapname = ccx.link_meta.name;
B
Brian Anderson 已提交
6223 6224
    } else { mapname = "toplevel"; }
    let sym_name = "_rust_crate_map_" + mapname;
6225
    let arrtype = T_array(T_int(), std::vec::len::<ValueRef>(subcrates));
B
Brian Anderson 已提交
6226
    let maptype = T_struct([T_int(), arrtype]);
B
Brian Anderson 已提交
6227 6228 6229
    let map =
        str::as_buf(sym_name,
                    {|buf| llvm::LLVMAddGlobal(ccx.llmod, maptype, buf) });
6230 6231 6232
    llvm::LLVMSetLinkage(map,
                         lib::llvm::LLVMExternalLinkage as llvm::Linkage);
    llvm::LLVMSetInitializer(map,
B
Brian Anderson 已提交
6233 6234
                             C_struct([p2i(create_module_map(ccx)),
                                       C_array(T_int(), subcrates)]));
6235 6236 6237
    ret map;
}

6238
fn write_metadata(cx: @crate_ctxt, crate: @ast::crate) {
M
Marijn Haverbeke 已提交
6239
    if !cx.sess.get_opts().library { ret; }
B
Brian Anderson 已提交
6240
    let llmeta = C_postr(metadata::encoder::encode_metadata(cx, crate));
B
Brian Anderson 已提交
6241
    let llconst = trans_common::C_struct([llmeta]);
B
Brian Anderson 已提交
6242 6243 6244 6245 6246
    let llglobal =
        str::as_buf("rust_metadata",
                    {|buf|
                        llvm::LLVMAddGlobal(cx.llmod, val_ty(llconst), buf)
                    });
6247
    llvm::LLVMSetInitializer(llglobal, llconst);
B
Brian Anderson 已提交
6248 6249 6250
    let _: () =
        str::as_buf(x86::get_meta_sect_name(),
                    {|buf| llvm::LLVMSetSection(llglobal, buf) });
6251 6252 6253
    llvm::LLVMSetLinkage(llglobal,
                         lib::llvm::LLVMInternalLinkage as llvm::Linkage);

M
Marijn Haverbeke 已提交
6254
    let t_ptr_i8 = T_ptr(T_i8());
6255
    llglobal = llvm::LLVMConstBitCast(llglobal, t_ptr_i8);
B
Brian Anderson 已提交
6256 6257 6258 6259 6260 6261
    let llvm_used =
        str::as_buf("llvm.used",
                    {|buf|
                        llvm::LLVMAddGlobal(cx.llmod, T_array(t_ptr_i8, 1u),
                                            buf)
                    });
6262 6263
    llvm::LLVMSetLinkage(llvm_used,
                         lib::llvm::LLVMAppendingLinkage as llvm::Linkage);
B
Brian Anderson 已提交
6264
    llvm::LLVMSetInitializer(llvm_used, C_array(t_ptr_i8, [llglobal]));
6265 6266
}

6267
// Writes the current ABI version into the crate.
6268
fn write_abi_version(ccx: @crate_ctxt) {
B
Brian Anderson 已提交
6269
    shape::mk_global(ccx, "rust_abi_version", C_uint(abi::abi_version),
6270 6271 6272
                     false);
}

6273 6274
fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
               output: str, amap: ast_map::map, mut_map: mut::mut_map,
6275
               copy_map: alias::copy_map) -> ModuleRef {
6276 6277 6278 6279
    let llmod = str::as_buf("rust_out", {|buf|
        llvm::LLVMModuleCreateWithNameInContext
            (buf, llvm::LLVMGetGlobalContext())
    });
B
Brian Anderson 已提交
6280 6281 6282 6283 6284 6285
    let _: () =
        str::as_buf(x86::get_data_layout(),
                    {|buf| llvm::LLVMSetDataLayout(llmod, buf) });
    let _: () =
        str::as_buf(x86::get_target_triple(),
                    {|buf| llvm::LLVMSetTarget(llmod, buf) });
6286
    let td = mk_target_data(x86::get_data_layout());
M
Marijn Haverbeke 已提交
6287 6288 6289 6290
    let tn = mk_type_names();
    let intrinsics = declare_intrinsics(llmod);
    let task_type = T_task();
    let taskptr_type = T_ptr(task_type);
B
Brian Anderson 已提交
6291
    tn.associate("taskptr", taskptr_type);
M
Marijn Haverbeke 已提交
6292
    let tydesc_type = T_tydesc(taskptr_type);
B
Brian Anderson 已提交
6293
    tn.associate("tydesc", tydesc_type);
M
Marijn Haverbeke 已提交
6294 6295
    let hasher = ty::hash_ty;
    let eqer = ty::eq_ty;
6296 6297 6298
    let tag_sizes = map::mk_hashmap::<ty::t, uint>(hasher, eqer);
    let tydescs = map::mk_hashmap::<ty::t, @tydesc_info>(hasher, eqer);
    let lltypes = map::mk_hashmap::<ty::t, TypeRef>(hasher, eqer);
B
Brian Anderson 已提交
6299 6300
    let sha1s = map::mk_hashmap::<ty::t, str>(hasher, eqer);
    let short_names = map::mk_hashmap::<ty::t, str>(hasher, eqer);
M
Marijn Haverbeke 已提交
6301 6302 6303 6304 6305 6306
    let sha = std::sha1::mk_sha1();
    let ccx =
        @{sess: sess,
          llmod: llmod,
          td: td,
          tn: tn,
6307
          externs: new_str_hash::<ValueRef>(),
M
Marijn Haverbeke 已提交
6308
          intrinsics: intrinsics,
6309
          item_ids: new_int_hash::<ValueRef>(),
M
Marijn Haverbeke 已提交
6310
          ast_map: amap,
B
Brian Anderson 已提交
6311
          item_symbols: new_int_hash::<str>(),
6312
          mutable main_fn: none::<ValueRef>,
B
Brian Anderson 已提交
6313
          link_meta: link::build_link_meta(sess, *crate, output, sha),
M
Marijn Haverbeke 已提交
6314
          tag_sizes: tag_sizes,
6315
          discrims: new_int_hash::<ValueRef>(),
B
Brian Anderson 已提交
6316
          discrim_symbols: new_int_hash::<str>(),
6317 6318
          consts: new_int_hash::<ValueRef>(),
          obj_methods: new_int_hash::<()>(),
M
Marijn Haverbeke 已提交
6319
          tydescs: tydescs,
6320
          module_data: new_str_hash::<ValueRef>(),
M
Marijn Haverbeke 已提交
6321 6322 6323 6324 6325 6326
          lltypes: lltypes,
          names: namegen(0),
          sha: sha,
          type_sha1s: sha1s,
          type_short_names: short_names,
          tcx: tcx,
6327
          mut_map: mut_map,
6328
          copy_map: copy_map,
M
Marijn Haverbeke 已提交
6329 6330 6331 6332 6333 6334
          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,
B
Brian Anderson 已提交
6335
               fn_times: @mutable []},
M
Marijn Haverbeke 已提交
6336 6337 6338 6339
          upcalls:
              upcall::declare_upcalls(tn, tydesc_type, taskptr_type, llmod),
          rust_object_type: T_rust_object(),
          tydesc_type: tydesc_type,
P
Patrick Walton 已提交
6340
          task_type: task_type,
6341
          builder: BuilderRef_res(llvm::LLVMCreateBuilder()),
6342
          shape_cx: shape::mk_ctxt(llmod),
6343
          gc_cx: gc::mk_ctxt()};
M
Marijn Haverbeke 已提交
6344
    let cx = new_local_ctxt(ccx);
6345
    collect_items(ccx, crate);
6346 6347
    collect_tag_ctors(ccx, crate);
    trans_constants(ccx, crate);
6348
    trans_mod(cx, crate.node.module);
T
Tim Chevalier 已提交
6349
    create_crate_map(ccx);
6350
    emit_tydescs(ccx);
P
Patrick Walton 已提交
6351
    shape::gen_shape_tables(ccx);
6352
    write_abi_version(ccx);
6353

P
Patrick Walton 已提交
6354
    // Translate the metadata.
6355
    write_metadata(cx.ccx, crate);
M
Marijn Haverbeke 已提交
6356
    if ccx.sess.get_opts().stats {
6357
        log_err "--- trans stats ---";
6358 6359 6360 6361 6362
        log_err #fmt["n_static_tydescs: %u", ccx.stats.n_static_tydescs];
        log_err #fmt["n_derived_tydescs: %u", ccx.stats.n_derived_tydescs];
        log_err #fmt["n_glues_created: %u", ccx.stats.n_glues_created];
        log_err #fmt["n_null_glues: %u", ccx.stats.n_null_glues];
        log_err #fmt["n_real_glues: %u", ccx.stats.n_real_glues];
6363

M
Marijn Haverbeke 已提交
6364

B
Brian Anderson 已提交
6365 6366
        for timing: {ident: str, time: int} in *ccx.stats.fn_times {
            log_err #fmt["time: %s took %d ms", timing.ident, timing.time];
6367
        }
6368
    }
6369
    ret llmod;
6370 6371 6372 6373 6374 6375 6376 6377
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
6378
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
6379 6380
// End:
//