trans.rs 207.0 KB
Newer Older
1
import std._int;
2
import std._str;
3
import std._uint;
4 5 6
import std._vec;
import std._str.rustrt.sbuf;
import std._vec.rustrt.vbuf;
7
import std.map;
8
import std.map.hashmap;
9 10 11
import std.option;
import std.option.some;
import std.option.none;
12

13
import front.ast;
14
import driver.session;
15
import middle.ty;
16
import back.x86;
17 18
import back.abi;

19
import middle.ty.pat_ty;
20
import middle.ty.plain_ty;
P
Patrick Walton 已提交
21

22
import util.common;
23
import util.common.istr;
24
import util.common.new_def_hash;
25
import util.common.new_str_hash;
26 27 28

import lib.llvm.llvm;
import lib.llvm.builder;
29
import lib.llvm.target_data;
30
import lib.llvm.type_handle;
31
import lib.llvm.type_names;
32
import lib.llvm.mk_pass_manager;
33
import lib.llvm.mk_target_data;
34
import lib.llvm.mk_type_handle;
35
import lib.llvm.mk_type_names;
36 37 38
import lib.llvm.llvm.ModuleRef;
import lib.llvm.llvm.ValueRef;
import lib.llvm.llvm.TypeRef;
39
import lib.llvm.llvm.TypeHandleRef;
40 41
import lib.llvm.llvm.BuilderRef;
import lib.llvm.llvm.BasicBlockRef;
42

43 44
import lib.llvm.False;
import lib.llvm.True;
45

46 47 48 49 50 51 52
state obj namegen(mutable int i) {
    fn next(str prefix) -> str {
        i += 1;
        ret prefix + istr(i);
    }
}

53 54
type glue_fns = rec(ValueRef activate_glue,
                    ValueRef yield_glue,
55
                    ValueRef exit_task_glue,
56
                    vec[ValueRef] upcall_glues,
57
                    ValueRef no_op_type_glue,
58
                    ValueRef memcpy_glue,
59
                    ValueRef bzero_glue,
60
                    ValueRef vec_append_glue);
61

62 63 64 65
type tydesc_info = rec(ValueRef tydesc,
                       ValueRef take_glue,
                       ValueRef drop_glue);

66
state type crate_ctxt = rec(session.session sess,
67
                            ModuleRef llmod,
68
                            target_data td,
69
                            type_names tn,
70
                            ValueRef crate_ptr,
71
                            hashmap[str, ValueRef] upcalls,
72
                            hashmap[str, ValueRef] intrinsics,
73
                            hashmap[str, ValueRef] item_names,
74
                            hashmap[str, ValueRef] native_fns,
75
                            hashmap[ast.def_id, ValueRef] item_ids,
76
                            hashmap[ast.def_id, @ast.item] items,
G
Graydon Hoare 已提交
77 78
                            hashmap[ast.def_id,
                                    @ast.native_item] native_items,
79 80
                            // TODO: hashmap[tup(tag_id,subtys), @tag_info]
                            hashmap[@ty.t, uint] tag_sizes,
81
                            hashmap[ast.def_id, ValueRef] discrims,
82
                            hashmap[ast.def_id, ValueRef] fn_pairs,
83
                            hashmap[ast.def_id, ValueRef] consts,
84
                            hashmap[ast.def_id,()] obj_methods,
85
                            hashmap[@ty.t, @tydesc_info] tydescs,
86
                            vec[ast.ty_param] obj_typarams,
87
                            vec[ast.obj_field] obj_fields,
88 89 90
                            @glue_fns glues,
                            namegen names,
                            str path);
91

92 93
state type fn_ctxt = rec(ValueRef llfn,
                         ValueRef lltaskptr,
94 95
                         ValueRef llenv,
                         ValueRef llretptr,
96
                         mutable option.t[ValueRef] llself,
97
                         mutable option.t[ValueRef] lliterbody,
98
                         hashmap[ast.def_id, ValueRef] llargs,
99
                         hashmap[ast.def_id, ValueRef] llobjfields,
100
                         hashmap[ast.def_id, ValueRef] lllocals,
101
                         hashmap[ast.def_id, ValueRef] llupvars,
102
                         hashmap[ast.def_id, ValueRef] lltydescs,
103
                         @crate_ctxt ccx);
104

105
tag cleanup {
106
    clean(fn(@block_ctxt cx) -> result);
107 108
}

109 110 111 112 113 114

tag block_kind {
    SCOPE_BLOCK;
    NON_SCOPE_BLOCK;
}

115 116
state type block_ctxt = rec(BasicBlockRef llbb,
                            builder build,
117
                            block_parent parent,
118
                            block_kind kind,
119 120 121
                            mutable vec[cleanup] cleanups,
                            @fn_ctxt fcx);

122 123 124 125 126 127 128 129
// FIXME: we should be able to use option.t[@block_parent] here but
// the infinite-tag check in rustboot gets upset.

tag block_parent {
    parent_none;
    parent_some(@block_ctxt);
}

130

131 132 133
state type result = rec(mutable @block_ctxt bcx,
                        mutable ValueRef val);

134 135 136 137
fn sep() -> str {
    ret "_";
}

138 139 140 141 142
fn res(@block_ctxt bcx, ValueRef val) -> result {
    ret rec(mutable bcx = bcx,
            mutable val = val);
}

143 144
fn ty_str(type_names tn, TypeRef t) -> str {
    ret lib.llvm.type_to_str(tn, t);
145 146 147 148 149 150
}

fn val_ty(ValueRef v) -> TypeRef {
    ret llvm.LLVMTypeOf(v);
}

151 152
fn val_str(type_names tn, ValueRef v) -> str {
    ret ty_str(tn, val_ty(v));
153
}
154 155 156 157


// LLVM type constructors.

158 159 160 161 162 163 164 165 166 167 168
fn T_void() -> TypeRef {
    // Note: For the time being llvm is kinda busted here, it has the notion
    // of a 'void' type that can only occur as part of the signature of a
    // function, but no general unit type of 0-sized value. This is, afaict,
    // vestigial from its C heritage, and we'll be attempting to submit a
    // patch upstream to fix it. In the mean time we only model function
    // outputs (Rust functions and C functions) using T_void, and model the
    // Rust general purpose nil type you can construct as 1-bit (always
    // zero). This makes the result incorrect for now -- things like a tuple
    // of 10 nil values will have 10-bit size -- but it doesn't seem like we
    // have any other options until it's fixed upstream.
169 170 171
    ret llvm.LLVMVoidType();
}

172 173 174 175 176
fn T_nil() -> TypeRef {
    // NB: See above in T_void().
    ret llvm.LLVMInt1Type();
}

177 178 179 180
fn T_i1() -> TypeRef {
    ret llvm.LLVMInt1Type();
}

181 182 183 184 185 186 187 188 189
fn T_i8() -> TypeRef {
    ret llvm.LLVMInt8Type();
}

fn T_i16() -> TypeRef {
    ret llvm.LLVMInt16Type();
}

fn T_i32() -> TypeRef {
190 191 192
    ret llvm.LLVMInt32Type();
}

193 194 195 196
fn T_i64() -> TypeRef {
    ret llvm.LLVMInt64Type();
}

197 198 199 200 201 202 203 204
fn T_f32() -> TypeRef {
    ret llvm.LLVMFloatType();
}

fn T_f64() -> TypeRef {
    ret llvm.LLVMDoubleType();
}

205 206 207 208
fn T_bool() -> TypeRef {
    ret T_i1();
}

209 210 211 212 213
fn T_int() -> TypeRef {
    // FIXME: switch on target type.
    ret T_i32();
}

214 215 216 217
fn T_char() -> TypeRef {
    ret T_i32();
}

218 219 220 221
fn T_fn(vec[TypeRef] inputs, TypeRef output) -> TypeRef {
    ret llvm.LLVMFunctionType(output,
                              _vec.buf[TypeRef](inputs),
                              _vec.len[TypeRef](inputs),
222 223 224
                              False);
}

225
fn T_fn_pair(type_names tn, TypeRef tfn) -> TypeRef {
226
    ret T_struct(vec(T_ptr(tfn),
227
                     T_opaque_closure_ptr(tn)));
228 229
}

230 231 232 233 234 235 236 237 238 239 240 241 242 243
fn T_ptr(TypeRef t) -> TypeRef {
    ret llvm.LLVMPointerType(t, 0u);
}

fn T_struct(vec[TypeRef] elts) -> TypeRef {
    ret llvm.LLVMStructType(_vec.buf[TypeRef](elts),
                            _vec.len[TypeRef](elts),
                            False);
}

fn T_opaque() -> TypeRef {
    ret llvm.LLVMOpaqueType();
}

244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
fn T_task(type_names tn) -> TypeRef {
    auto s = "task";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }

    auto t = T_struct(vec(T_int(),      // Refcount
                          T_int(),      // Delegate pointer
                          T_int(),      // Stack segment pointer
                          T_int(),      // Runtime SP
                          T_int(),      // Rust SP
                          T_int(),      // GC chain
                          T_int(),      // Domain pointer
                          T_int()       // Crate cache pointer
                          ));
    tn.associate(s, t);
    ret t;
261 262
}

263 264 265 266 267 268
fn T_glue_fn(type_names tn) -> TypeRef {
    auto s = "glue_fn";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }

269 270
    // Bit of a kludge: pick the fn typeref out of the tydesc..
    let vec[TypeRef] tydesc_elts = _vec.init_elt[TypeRef](T_nil(), 10u);
271
    llvm.LLVMGetStructElementTypes(T_tydesc(tn),
272
                                   _vec.buf[TypeRef](tydesc_elts));
273 274 275 276 277
    auto t =
        llvm.LLVMGetElementType
        (tydesc_elts.(abi.tydesc_field_drop_glue_off));
    tn.associate(s, t);
    ret t;
278 279
}

280 281 282 283 284 285
fn T_tydesc(type_names tn) -> TypeRef {

    auto s = "tydesc";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }
286 287 288

    auto th = mk_type_handle();
    auto abs_tydesc = llvm.LLVMResolveTypeHandle(th.llth);
289
    auto tydescpp = T_ptr(T_ptr(abs_tydesc));
290
    auto pvoid = T_ptr(T_i8());
291
    auto glue_fn_ty = T_ptr(T_fn(vec(T_ptr(T_nil()),
292
                                     T_taskptr(tn),
293
                                     T_ptr(T_nil()),
294
                                     tydescpp,
295
                                     pvoid), T_void()));
296
    auto tydesc = T_struct(vec(tydescpp,          // first_param
297 298 299 300 301 302 303 304 305 306 307
                               T_int(),           // size
                               T_int(),           // align
                               glue_fn_ty,        // take_glue_off
                               glue_fn_ty,        // drop_glue_off
                               glue_fn_ty,        // free_glue_off
                               glue_fn_ty,        // sever_glue_off
                               glue_fn_ty,        // mark_glue_off
                               glue_fn_ty,        // obj_drop_glue_off
                               glue_fn_ty));      // is_stateful

    llvm.LLVMRefineType(abs_tydesc, tydesc);
308 309 310
    auto t = llvm.LLVMResolveTypeHandle(th.llth);
    tn.associate(s, t);
    ret t;
311 312
}

313 314 315 316
fn T_array(TypeRef t, uint n) -> TypeRef {
    ret llvm.LLVMArrayType(t, n);
}

317 318 319 320 321
fn T_vec(TypeRef t) -> TypeRef {
    ret T_struct(vec(T_int(),       // Refcount
                     T_int(),       // Alloc
                     T_int(),       // Fill
                     T_array(t, 0u) // Body elements
322 323 324
                     ));
}

325 326 327 328
fn T_opaque_vec_ptr() -> TypeRef {
    ret T_ptr(T_vec(T_int()));
}

329 330
fn T_str() -> TypeRef {
    ret T_vec(T_i8());
331 332
}

333 334 335 336
fn T_box(TypeRef t) -> TypeRef {
    ret T_struct(vec(T_int(), t));
}

337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
fn T_crate(type_names tn) -> TypeRef {
    auto s = "crate";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }

    auto t = T_struct(vec(T_int(),      // ptrdiff_t image_base_off
                          T_int(),      // uintptr_t self_addr
                          T_int(),      // ptrdiff_t debug_abbrev_off
                          T_int(),      // size_t debug_abbrev_sz
                          T_int(),      // ptrdiff_t debug_info_off
                          T_int(),      // size_t debug_info_sz
                          T_int(),      // size_t activate_glue_off
                          T_int(),      // size_t yield_glue_off
                          T_int(),      // size_t unwind_glue_off
                          T_int(),      // size_t gc_glue_off
                          T_int(),      // size_t main_exit_task_glue_off
                          T_int(),      // int n_rust_syms
                          T_int(),      // int n_c_syms
356 357
                          T_int(),      // int n_libs
                          T_int()       // uintptr_t abi_tag
358 359 360
                          ));
    tn.associate(s, t);
    ret t;
361 362
}

363 364 365 366
fn T_double() -> TypeRef {
    ret llvm.LLVMDoubleType();
}

367 368
fn T_taskptr(type_names tn) -> TypeRef {
    ret T_ptr(T_task(tn));
369 370
}

371 372
// This type must never be used directly; it must always be cast away.
fn T_typaram(type_names tn) -> TypeRef {
373 374 375 376 377
    auto s = "typaram";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }

378
    auto t = T_i8();
379 380
    tn.associate(s, t);
    ret t;
381 382
}

383 384 385 386
fn T_typaram_ptr(type_names tn) -> TypeRef {
    ret T_ptr(T_typaram(tn));
}

387 388
fn T_closure_ptr(type_names tn,
                 TypeRef lltarget_ty,
389 390
                 TypeRef llbindings_ty,
                 uint n_ty_params) -> TypeRef {
391 392 393 394

    // NB: keep this in sync with code in trans_bind; we're making
    // an LLVM typeref structure that has the same "shape" as the ty.t
    // it constructs.
395
    ret T_ptr(T_box(T_struct(vec(T_ptr(T_tydesc(tn)),
396
                                 lltarget_ty,
397 398
                                 llbindings_ty,
                                 T_captured_tydescs(tn, n_ty_params))
399 400 401
                             )));
}

402 403 404 405 406 407 408
fn T_opaque_closure_ptr(type_names tn) -> TypeRef {
    auto s = "*closure";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }
    auto t = T_closure_ptr(tn, T_struct(vec(T_ptr(T_nil()),
                                            T_ptr(T_nil()))),
409 410
                           T_nil(),
                           0u);
411 412
    tn.associate(s, t);
    ret t;
413 414
}

415 416 417 418 419 420 421 422 423 424 425 426
fn T_tag(type_names tn, uint size) -> TypeRef {
    auto s = "tag_" + _uint.to_str(size, 10u);
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }
    auto t = T_struct(vec(T_int(), T_array(T_i8(), size)));
    tn.associate(s, t);
    ret t;
}

fn T_opaque_tag(type_names tn) -> TypeRef {
    auto s = "tag";
427 428 429
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }
430
    auto t = T_struct(vec(T_int(), T_i8()));
431 432 433 434
    tn.associate(s, t);
    ret t;
}

435 436 437 438
fn T_opaque_tag_ptr(type_names tn) -> TypeRef {
    ret T_ptr(T_opaque_tag(tn));
}

439 440
fn T_captured_tydescs(type_names tn, uint n) -> TypeRef {
    ret T_struct(_vec.init_elt[TypeRef](T_ptr(T_tydesc(tn)), n));
441 442
}

443 444 445 446 447 448 449
fn T_obj_ptr(type_names tn, uint n_captured_tydescs) -> TypeRef {
    // This function is not publicly exposed because it returns an incomplete
    // type. The dynamically-sized fields follow the captured tydescs.
    fn T_obj(type_names tn, uint n_captured_tydescs) -> TypeRef {
        ret T_struct(vec(T_ptr(T_tydesc(tn)),
                         T_captured_tydescs(tn, n_captured_tydescs)));
    }
450

451
    ret T_ptr(T_box(T_obj(tn, n_captured_tydescs)));
452 453
}

454
fn T_opaque_obj_ptr(type_names tn) -> TypeRef {
455
    ret T_obj_ptr(tn, 0u);
456 457
}

458

459 460 461 462
// This function now fails if called on a type with dynamic size (as its
// return value was always meaningless in that case anyhow). Beware!
//
// TODO: Enforce via a predicate.
463
fn type_of(@crate_ctxt cx, @ty.t t) -> TypeRef {
464 465 466 467 468 469
    if (ty.type_has_dynamic_size(t)) {
        log "type_of() called on a type with dynamic size: " +
            ty.ty_to_str(t);
        fail;
    }

470
    ret type_of_inner(cx, t, false);
471 472
}

473 474 475 476 477 478
fn type_of_explicit_args(@crate_ctxt cx,
                     vec[ty.arg] inputs) -> vec[TypeRef] {
    let vec[TypeRef] atys = vec();
    for (ty.arg arg in inputs) {
        if (ty.type_has_dynamic_size(arg.ty)) {
            check (arg.mode == ast.alias);
479
            atys += vec(T_typaram_ptr(cx.tn));
480
        } else {
481
            let TypeRef t;
482 483
            alt (arg.mode) {
                case (ast.alias) {
484 485 486 487
                    t = T_ptr(type_of_inner(cx, arg.ty, true));
                }
                case (_) {
                    t = type_of_inner(cx, arg.ty, false);
488 489
                }
            }
490
            atys += vec(t);
491 492 493 494
        }
    }
    ret atys;
}
495 496 497 498 499 500 501 502

// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args

503
fn type_of_fn_full(@crate_ctxt cx,
504
                   ast.proto proto,
505 506
                   option.t[TypeRef] obj_self,
                   vec[ty.arg] inputs,
507 508
                   @ty.t output,
                   uint ty_param_count) -> TypeRef {
509
    let vec[TypeRef] atys = vec();
510

511
    // Arg 0: Output pointer.
512
    if (ty.type_has_dynamic_size(output)) {
513
        atys += vec(T_typaram_ptr(cx.tn));
514
    } else {
515
        atys += vec(T_ptr(type_of_inner(cx, output, false)));
516 517
    }

518
    // Arg 1: Task pointer.
519
    atys += vec(T_taskptr(cx.tn));
520 521

    // Arg 2: Env (closure-bindings / self-obj)
522 523 524
    alt (obj_self) {
        case (some[TypeRef](?t)) {
            check (t as int != 0);
525
            atys += vec(t);
526
        }
527
        case (_) {
528
            atys += vec(T_opaque_closure_ptr(cx.tn));
529
        }
530 531
    }

532 533 534 535
    // Args >3: ty params, if not acquired via capture...
    if (obj_self == none[TypeRef]) {
        auto i = 0u;
        while (i < ty_param_count) {
536
            atys += vec(T_ptr(T_tydesc(cx.tn)));
537 538
            i += 1u;
        }
539 540
    }

541
    if (proto == ast.proto_iter) {
542 543 544
        // 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.
545 546
        atys +=
            vec(T_fn_pair(cx.tn,
547
                          type_of_fn_full(cx, ast.proto_fn, none[TypeRef],
548
                                          vec(rec(mode=ast.val, ty=output)),
549
                                          plain_ty(ty.ty_nil), 0u)));
550 551
    }

552
    // ... then explicit args.
553
    atys += type_of_explicit_args(cx, inputs);
554

555
    ret T_fn(atys, llvm.LLVMVoidType());
556 557
}

558
fn type_of_fn(@crate_ctxt cx,
559
              ast.proto proto,
560 561 562 563 564
              vec[ty.arg] inputs,
              @ty.t output,
              uint ty_param_count) -> TypeRef {
    ret type_of_fn_full(cx, proto, none[TypeRef], inputs, output,
                        ty_param_count);
565 566
}

567 568
fn type_of_native_fn(@crate_ctxt cx, ast.native_abi abi,
                     vec[ty.arg] inputs,
569 570
                     @ty.t output,
                     uint ty_param_count) -> TypeRef {
571 572
    let vec[TypeRef] atys = vec();
    if (abi == ast.native_abi_rust) {
573
        atys += vec(T_taskptr(cx.tn));
574 575 576
        auto t = ty.ty_native_fn(abi, inputs, output);
        auto i = 0u;
        while (i < ty_param_count) {
577
            atys += vec(T_ptr(T_tydesc(cx.tn)));
578 579 580 581
            i += 1u;
        }
    }
    atys += type_of_explicit_args(cx, inputs);
582
    ret T_fn(atys, type_of_inner(cx, output, false));
583 584
}

585
fn type_of_inner(@crate_ctxt cx, @ty.t t, bool boxed) -> TypeRef {
586 587
    let TypeRef llty = 0 as TypeRef;

588
    alt (t.struct) {
589 590 591 592 593
        case (ty.ty_native) { llty = T_ptr(T_i8()); }
        case (ty.ty_nil) { llty = T_nil(); }
        case (ty.ty_bool) { llty = T_bool(); }
        case (ty.ty_int) { llty = T_int(); }
        case (ty.ty_uint) { llty = T_int(); }
594
        case (ty.ty_machine(?tm)) {
595
            alt (tm) {
596 597 598 599 600 601 602 603 604 605
                case (common.ty_i8) { llty = T_i8(); }
                case (common.ty_u8) { llty = T_i8(); }
                case (common.ty_i16) { llty = T_i16(); }
                case (common.ty_u16) { llty = T_i16(); }
                case (common.ty_i32) { llty = T_i32(); }
                case (common.ty_u32) { llty = T_i32(); }
                case (common.ty_i64) { llty = T_i64(); }
                case (common.ty_u64) { llty = T_i64(); }
                case (common.ty_f32) { llty = T_f32(); }
                case (common.ty_f64) { llty = T_f64(); }
606 607
            }
        }
608 609
        case (ty.ty_char) { llty = T_char(); }
        case (ty.ty_str) { llty = T_ptr(T_str()); }
610 611 612 613 614 615 616
        case (ty.ty_tag(_, _)) {
            if (boxed) {
                llty = T_opaque_tag(cx.tn);
            } else {
                auto size = static_size_of_tag(cx, t);
                llty = T_tag(cx.tn, size);
            }
617
        }
618 619
        case (ty.ty_box(?mt)) {
            llty = T_ptr(T_box(type_of_inner(cx, mt.ty, true)));
620
        }
621 622
        case (ty.ty_vec(?mt)) {
            llty = T_ptr(T_vec(type_of_inner(cx, mt.ty, true)));
623
        }
624
        case (ty.ty_tup(?elts)) {
625
            let vec[TypeRef] tys = vec();
626 627
            for (ty.mt elt in elts) {
                tys += vec(type_of_inner(cx, elt.ty, boxed));
628
            }
629
            llty = T_struct(tys);
630
        }
631
        case (ty.ty_rec(?fields)) {
632
            let vec[TypeRef] tys = vec();
633
            for (ty.field f in fields) {
634
                tys += vec(type_of_inner(cx, f.mt.ty, boxed));
635
            }
636
            llty = T_struct(tys);
637
        }
638
        case (ty.ty_fn(?proto, ?args, ?out)) {
639
            llty = T_fn_pair(cx.tn, type_of_fn(cx, proto, args, out, 0u));
640
        }
641
        case (ty.ty_native_fn(?abi, ?args, ?out)) {
642 643
            auto nft = type_of_native_fn(cx, abi, args, out, 0u);
            llty = T_fn_pair(cx.tn, nft);
644
        }
645
        case (ty.ty_obj(?meths)) {
646 647 648
            auto th = mk_type_handle();
            auto self_ty = llvm.LLVMResolveTypeHandle(th.llth);

649
            let vec[TypeRef] mtys = vec();
650
            for (ty.method m in meths) {
651
                let TypeRef mty =
652
                    type_of_fn_full(cx, m.proto,
653
                                    some[TypeRef](self_ty),
654
                                    m.inputs, m.output, 0u);
655
                mtys += vec(T_ptr(mty));
656
            }
657
            let TypeRef vtbl = T_struct(mtys);
658
            let TypeRef pair = T_struct(vec(T_ptr(vtbl),
659
                                            T_opaque_obj_ptr(cx.tn)));
660

661 662 663
            auto abs_pair = llvm.LLVMResolveTypeHandle(th.llth);
            llvm.LLVMRefineType(abs_pair, pair);
            abs_pair = llvm.LLVMResolveTypeHandle(th.llth);
664
            llty = abs_pair;
665
        }
666
        case (ty.ty_var(_)) {
667
            log "ty_var in trans.type_of";
668 669
            fail;
        }
670
        case (ty.ty_param(_)) {
671
            llty = T_i8();
672
        }
673
        case (ty.ty_type) { llty = T_ptr(T_tydesc(cx.tn)); }
674
    }
675 676 677 678

    check (llty as int != 0);
    llvm.LLVMAddTypeName(cx.llmod, _str.buf(ty.ty_to_str(t)), llty);
    ret llty;
679 680
}

681
fn type_of_arg(@crate_ctxt cx, &ty.arg arg) -> TypeRef {
682 683 684 685 686 687 688 689 690 691 692
    alt (arg.ty.struct) {
        case (ty.ty_param(_)) {
            if (arg.mode == ast.alias) {
                ret T_typaram_ptr(cx.tn);
            }
        }
        case (_) {
            // fall through
        }
    }

693
    auto typ;
694
    if (arg.mode == ast.alias) {
695 696 697
        typ = T_ptr(type_of_inner(cx, arg.ty, true));
    } else {
        typ = type_of_inner(cx, arg.ty, false);
698
    }
699
    ret typ;
700 701
}

702 703 704 705 706 707 708 709 710
// Name sanitation. LLVM will happily accept identifiers with weird names, but
// gas doesn't!

fn sanitize(str s) -> str {
    auto result = "";
    for (u8 c in s) {
        if (c == ('@' as u8)) {
            result += "boxed_";
        } else {
711 712 713 714 715 716 717
            if (c == (',' as u8)) {
                result += "_";
            } else {
                if (c == ('{' as u8) || c == ('(' as u8)) {
                    result += "_of_";
                } else {
                    if (c != 10u8 && c != ('}' as u8) && c != (')' as u8) &&
G
Graydon Hoare 已提交
718 719
                        c != (' ' as u8) && c != ('\t' as u8) &&
                        c != (';' as u8)) {
720 721 722 723 724
                        auto v = vec(c);
                        result += _str.from_bytes(v);
                    }
                }
            }
725 726 727 728 729
        }
    }
    ret result;
}

730 731 732 733 734 735
// LLVM constant constructors.

fn C_null(TypeRef t) -> ValueRef {
    ret llvm.LLVMConstNull(t);
}

736
fn C_integral(int i, TypeRef t) -> ValueRef {
737 738 739 740 741 742
    // FIXME. We can't use LLVM.ULongLong with our existing minimal native
    // API, which only knows word-sized args.  Lucky for us LLVM has a "take a
    // string encoding" version.  Hilarious. Please fix to handle:
    //
    // ret llvm.LLVMConstInt(T_int(), t as LLVM.ULongLong, False);
    //
743 744 745
    ret llvm.LLVMConstIntOfString(t, _str.buf(istr(i)), 10);
}

746 747 748 749 750
fn C_nil() -> ValueRef {
    // NB: See comment above in T_void().
    ret C_integral(0, T_i1());
}

751 752
fn C_bool(bool b) -> ValueRef {
    if (b) {
753
        ret C_integral(1, T_bool());
754
    } else {
755
        ret C_integral(0, T_bool());
756 757 758
    }
}

759 760
fn C_int(int i) -> ValueRef {
    ret C_integral(i, T_int());
761 762
}

763 764 765
// This is a 'c-like' raw string, which differs from
// our boxed-and-length-annotated strings.
fn C_cstr(@crate_ctxt cx, str s) -> ValueRef {
766
    auto sc = llvm.LLVMConstString(_str.buf(s), _str.byte_len(s), False);
767
    auto g = llvm.LLVMAddGlobal(cx.llmod, val_ty(sc),
768 769
                                _str.buf(cx.names.next("str")));
    llvm.LLVMSetInitializer(g, sc);
770
    llvm.LLVMSetGlobalConstant(g, True);
771 772
    llvm.LLVMSetLinkage(g, lib.llvm.LLVMPrivateLinkage
                        as llvm.Linkage);
773
    ret g;
774 775
}

776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792
// A rust boxed-and-length-annotated string.
fn C_str(@crate_ctxt cx, str s) -> ValueRef {
    auto len = _str.byte_len(s);
    auto box = C_struct(vec(C_int(abi.const_refcount as int),
                            C_int(len + 1u as int), // 'alloc'
                            C_int(len + 1u as int), // 'fill'
                            llvm.LLVMConstString(_str.buf(s),
                                                 len, False)));
    auto g = llvm.LLVMAddGlobal(cx.llmod, val_ty(box),
                                _str.buf(cx.names.next("str")));
    llvm.LLVMSetInitializer(g, box);
    llvm.LLVMSetGlobalConstant(g, True);
    llvm.LLVMSetLinkage(g, lib.llvm.LLVMPrivateLinkage
                        as llvm.Linkage);
    ret llvm.LLVMConstPointerCast(g, T_ptr(T_str()));
}

793 794 795 796 797 798 799 800 801 802 803
fn C_zero_byte_arr(uint size) -> ValueRef {
    auto i = 0u;
    let vec[ValueRef] elts = vec();
    while (i < size) {
        elts += vec(C_integral(0, T_i8()));
        i += 1u;
    }
    ret llvm.LLVMConstArray(T_i8(), _vec.buf[ValueRef](elts),
                            _vec.len[ValueRef](elts));
}

804 805 806 807 808 809
fn C_struct(vec[ValueRef] elts) -> ValueRef {
    ret llvm.LLVMConstStruct(_vec.buf[ValueRef](elts),
                             _vec.len[ValueRef](elts),
                             False);
}

810
fn decl_fn(ModuleRef llmod, str name, uint cc, TypeRef llty) -> ValueRef {
811 812
    let ValueRef llfn =
        llvm.LLVMAddFunction(llmod, _str.buf(name), llty);
813
    llvm.LLVMSetFunctionCallConv(llfn, cc);
814 815 816
    ret llfn;
}

817 818
fn decl_cdecl_fn(ModuleRef llmod, str name, TypeRef llty) -> ValueRef {
    ret decl_fn(llmod, name, lib.llvm.LLVMCCallConv, llty);
819 820
}

821 822
fn decl_fastcall_fn(ModuleRef llmod, str name, TypeRef llty) -> ValueRef {
    ret decl_fn(llmod, name, lib.llvm.LLVMFastCallConv, llty);
823 824
}

825 826
fn decl_glue(ModuleRef llmod, type_names tn, str s) -> ValueRef {
    ret decl_cdecl_fn(llmod, s, T_fn(vec(T_taskptr(tn)), T_void()));
827 828
}

829
fn decl_upcall_glue(ModuleRef llmod, type_names tn, uint _n) -> ValueRef {
830 831 832 833
    // It doesn't actually matter what type we come up with here, at the
    // moment, as we cast the upcall function pointers to int before passing
    // them to the indirect upcall-invocation glue.  But eventually we'd like
    // to call them directly, once we have a calling convention worked out.
834
    let int n = _n as int;
835
    let str s = abi.upcall_glue_name(n);
836
    let vec[TypeRef] args =
837
        vec(T_int())     // callee
838 839
        + _vec.init_elt[TypeRef](T_int(), n as uint);

840
    ret decl_fastcall_fn(llmod, s, T_fn(args, T_int()));
841 842
}

843 844 845 846 847
fn get_upcall(&hashmap[str, ValueRef] upcalls,
              type_names tn, ModuleRef llmod,
              str name, int n_args) -> ValueRef {
    if (upcalls.contains_key(name)) {
        ret upcalls.get(name);
848
    }
849
    auto inputs = vec(T_taskptr(tn));
850
    inputs += _vec.init_elt[TypeRef](T_int(), n_args as uint);
851
    auto output = T_int();
852 853
    auto f = decl_cdecl_fn(llmod, name, T_fn(inputs, output));
    upcalls.insert(name, f);
854 855 856
    ret f;
}

857
fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args) -> result {
858 859 860 861 862 863 864 865 866 867
    auto cxx = cx.fcx.ccx;
    auto t = trans_upcall2(cx.build, cxx.glues, cx.fcx.lltaskptr,
                           cxx.upcalls, cxx.tn, cxx.llmod, name, args);
    ret res(cx, t);
}

fn trans_upcall2(builder b, @glue_fns glues, ValueRef lltaskptr,
                 &hashmap[str, ValueRef] upcalls,
                 type_names tn, ModuleRef llmod, str name,
                 vec[ValueRef] args) -> ValueRef {
868
    let int n = (_vec.len[ValueRef](args) as int) + 1;
869
    let ValueRef llupcall = get_upcall(upcalls, tn, llmod, name, n);
870 871
    llupcall = llvm.LLVMConstPointerCast(llupcall, T_int());

872
    let ValueRef llglue = glues.upcall_glues.(n);
873
    let vec[ValueRef] call_args = vec(llupcall);
874
    call_args += vec( b.PtrToInt(lltaskptr, T_int()));
875

876
    for (ValueRef a in args) {
877
        call_args += vec(b.ZExtOrBitCast(a, T_int()));
878
    }
879

880
    ret b.FastCall(llglue, call_args);
881 882
}

883
fn trans_non_gc_free(@block_ctxt cx, ValueRef v) -> result {
884
    ret trans_upcall(cx, "upcall_free", vec(vp2i(cx, v),
885
                                            C_int(0)));
886 887
}

888
fn find_scope_cx(@block_ctxt cx) -> @block_ctxt {
889
    if (cx.kind == SCOPE_BLOCK) {
890 891 892 893 894 895 896 897 898 899 900 901
        ret cx;
    }
    alt (cx.parent) {
        case (parent_some(?b)) {
            be find_scope_cx(b);
        }
        case (parent_none) {
            fail;
        }
    }
}

902 903 904 905 906
fn umax(@block_ctxt cx, ValueRef a, ValueRef b) -> ValueRef {
    auto cond = cx.build.ICmp(lib.llvm.LLVMIntULT, a, b);
    ret cx.build.Select(cond, b, a);
}

907 908 909 910 911
fn umin(@block_ctxt cx, ValueRef a, ValueRef b) -> ValueRef {
    auto cond = cx.build.ICmp(lib.llvm.LLVMIntULT, a, b);
    ret cx.build.Select(cond, a, b);
}

912 913 914 915 916 917
fn align_to(@block_ctxt cx, ValueRef off, ValueRef align) -> ValueRef {
    auto mask = cx.build.Sub(align, C_int(1));
    auto bumped = cx.build.Add(off, mask);
    ret cx.build.And(bumped, cx.build.Not(mask));
}

918 919 920 921 922
// Returns the real size of the given type for the current target.
fn llsize_of_real(@crate_ctxt cx, TypeRef t) -> uint {
    ret llvm.LLVMStoreSizeOfType(cx.td.lltd, t);
}

923
fn llsize_of(TypeRef t) -> ValueRef {
924 925 926
    ret llvm.LLVMConstIntCast(lib.llvm.llvm.LLVMSizeOf(t), T_int(), False);
}

927
fn llalign_of(TypeRef t) -> ValueRef {
928 929 930
    ret llvm.LLVMConstIntCast(lib.llvm.llvm.LLVMAlignOf(t), T_int(), False);
}

931
fn size_of(@block_ctxt cx, @ty.t t) -> result {
932
    if (!ty.type_has_dynamic_size(t)) {
933
        ret res(cx, llsize_of(type_of(cx.fcx.ccx, t)));
934 935 936 937
    }
    ret dynamic_size_of(cx, t);
}

938
fn align_of(@block_ctxt cx, @ty.t t) -> result {
939
    if (!ty.type_has_dynamic_size(t)) {
940
        ret res(cx, llalign_of(type_of(cx.fcx.ccx, t)));
941 942 943 944
    }
    ret dynamic_align_of(cx, t);
}

945 946 947 948 949 950 951 952 953 954 955
// Computes the size of the data part of a non-dynamically-sized tag.
fn static_size_of_tag(@crate_ctxt cx, @ty.t t) -> uint {
    if (ty.type_has_dynamic_size(t)) {
        log "dynamically sized type passed to static_size_of_tag()";
        fail;
    }

    if (cx.tag_sizes.contains_key(t)) {
        ret cx.tag_sizes.get(t);
    }

B
Brian Anderson 已提交
956 957
    auto tid;
    let vec[@ty.t] subtys;
958 959 960 961 962 963 964 965 966 967 968
    alt (t.struct) {
        case (ty.ty_tag(?tid_, ?subtys_)) {
            tid = tid_;
            subtys = subtys_;
        }
        case (_) {
            log "non-tag passed to static_size_of_tag()";
            fail;
        }
    }

969
    // Pull the type parameters out of the corresponding tag item.
970
    let vec[ast.ty_param] ty_params = tag_ty_params(cx, tid);
971

972 973 974 975
    // Compute max(variant sizes).
    auto max_size = 0u;
    auto variants = tag_variants(cx, tid);
    for (ast.variant variant in variants) {
976
        auto tup_ty = ty.plain_tup_ty(variant_types(cx, variant));
977

978 979 980
        // Perform any type parameter substitutions.
        tup_ty = ty.substitute_ty_params(ty_params, subtys, tup_ty);

981 982 983 984 985 986 987 988 989 990 991 992
        // Here we possibly do a recursive call.
        auto this_size = llsize_of_real(cx, type_of(cx, tup_ty));

        if (max_size < this_size) {
            max_size = this_size;
        }
    }

    cx.tag_sizes.insert(t, max_size);
    ret max_size;
}

993
fn dynamic_size_of(@block_ctxt cx, @ty.t t) -> result {
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
    fn align_elements(@block_ctxt cx, vec[@ty.t] elts) -> result {
        //
        // C padding rules:
        //
        //
        //   - Pad after each element so that next element is aligned.
        //   - Pad after final structure member so that whole structure
        //     is aligned to max alignment of interior.
        //
        auto off = C_int(0);
        auto max_align = C_int(1);
        auto bcx = cx;
        for (@ty.t e in elts) {
            auto elt_align = align_of(bcx, e);
            bcx = elt_align.bcx;
            auto elt_size = size_of(bcx, e);
            bcx = elt_size.bcx;
            auto aligned_off = align_to(bcx, off, elt_align.val);
            off = cx.build.Add(aligned_off, elt_size.val);
            max_align = umax(bcx, max_align, elt_align.val);
        }
        off = align_to(bcx, off, max_align);
        ret res(bcx, off);
    }

1019 1020 1021
    alt (t.struct) {
        case (ty.ty_param(?p)) {
            auto szptr = field_of_tydesc(cx, t, abi.tydesc_field_size);
1022
            ret res(szptr.bcx, szptr.bcx.build.Load(szptr.val));
1023 1024
        }
        case (ty.ty_tup(?elts)) {
1025 1026 1027 1028 1029
            let vec[@ty.t] tys = vec();
            for (ty.mt mt in elts) {
                tys += vec(mt.ty);
            }
            ret align_elements(cx, tys);
1030 1031
        }
        case (ty.ty_rec(?flds)) {
1032
            let vec[@ty.t] tys = vec();
1033
            for (ty.field f in flds) {
1034
                tys += vec(f.mt.ty);
1035
            }
1036
            ret align_elements(cx, tys);
1037
        }
1038 1039 1040 1041 1042 1043 1044
        case (ty.ty_tag(?tid, ?tps)) {
            auto bcx = cx;

            // Compute max(variant sizes).
            let ValueRef max_size = bcx.build.Alloca(T_int());
            bcx.build.Store(C_int(0), max_size);

1045
            auto ty_params = tag_ty_params(bcx.fcx.ccx, tid);
1046 1047
            auto variants = tag_variants(bcx.fcx.ccx, tid);
            for (ast.variant variant in variants) {
1048 1049 1050 1051 1052 1053 1054 1055
                // Perform type substitution on the raw variant types.
                let vec[@ty.t] raw_tys = variant_types(bcx.fcx.ccx, variant);
                let vec[@ty.t] tys = vec();
                for (@ty.t raw_ty in raw_tys) {
                    auto t = ty.substitute_ty_params(ty_params, tps, raw_ty);
                    tys += vec(t);
                }

1056 1057 1058 1059 1060 1061 1062 1063
                auto rslt = align_elements(bcx, tys);
                bcx = rslt.bcx;

                auto this_size = rslt.val;
                auto old_max_size = bcx.build.Load(max_size);
                bcx.build.Store(umax(bcx, this_size, old_max_size), max_size);
            }

1064 1065 1066
            auto max_size_val = bcx.build.Load(max_size);
            auto total_size = bcx.build.Add(max_size_val, llsize_of(T_int()));
            ret res(bcx, total_size);
1067
        }
1068 1069 1070
    }
}

1071
fn dynamic_align_of(@block_ctxt cx, @ty.t t) -> result {
1072 1073 1074
    alt (t.struct) {
        case (ty.ty_param(?p)) {
            auto aptr = field_of_tydesc(cx, t, abi.tydesc_field_align);
1075
            ret res(aptr.bcx, aptr.bcx.build.Load(aptr.val));
1076 1077 1078
        }
        case (ty.ty_tup(?elts)) {
            auto a = C_int(1);
1079
            auto bcx = cx;
1080 1081
            for (ty.mt e in elts) {
                auto align = align_of(bcx, e.ty);
1082 1083
                bcx = align.bcx;
                a = umax(bcx, a, align.val);
1084
            }
1085
            ret res(bcx, a);
1086 1087 1088
        }
        case (ty.ty_rec(?flds)) {
            auto a = C_int(1);
1089
            auto bcx = cx;
1090
            for (ty.field f in flds) {
1091
                auto align = align_of(bcx, f.mt.ty);
1092 1093
                bcx = align.bcx;
                a = umax(bcx, a, align.val);
1094
            }
1095
            ret res(bcx, a);
1096
        }
1097 1098 1099
        case (ty.ty_tag(_, _)) {
            ret res(cx, C_int(1)); // FIXME: stub
        }
1100 1101 1102
    }
}

1103
// Replacement for the LLVM 'GEP' instruction when field-indexing into a
1104 1105 1106 1107
// tuple-like structure (tup, rec) with a static index. This one is driven off
// ty.struct and knows what to do when it runs into a ty_param stuck in the
// middle of the thing it's GEP'ing into. Much like size_of and align_of,
// above.
1108 1109

fn GEP_tup_like(@block_ctxt cx, @ty.t t,
1110
                ValueRef base, vec[int] ixs) -> result {
1111 1112 1113 1114 1115 1116 1117 1118

    check (ty.type_is_tup_like(t));

    // It might be a static-known type. Handle this.

    if (! ty.type_has_dynamic_size(t)) {
        let vec[ValueRef] v = vec();
        for (int i in ixs) {
1119
            v += vec(C_int(i));
1120
        }
1121
        ret res(cx, cx.build.GEP(base, v));
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165
    }

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

    fn split_type(@ty.t t, vec[int] ixs, uint n)
        -> rec(vec[@ty.t] prefix, @ty.t target) {

        let uint len = _vec.len[int](ixs);

        // We don't support 0-index or 1-index GEPs. The former is nonsense
        // and the latter would only be meaningful if we supported non-0
        // values for the 0th index (we don't).

        check (len > 1u);

        if (n == 0u) {
            // Since we're starting from a value that's a pointer to a
            // *single* structure, the first index (in GEP-ese) should just be
            // 0, to yield the pointee.
            check (ixs.(n) == 0);
            ret split_type(t, ixs, n+1u);
        }

        check (n < len);

        let int ix = ixs.(n);
        let vec[@ty.t] prefix = vec();
        let int i = 0;
        while (i < ix) {
1166 1167
            _vec.push[@ty.t](prefix, ty.get_element_type(t, i as uint));
            i += 1 ;
1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
        }

        auto selected = ty.get_element_type(t, i as uint);

        if (n == len-1u) {
            // We are at the innermost index.
            ret rec(prefix=prefix, target=selected);

        } 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.
            auto inner = split_type(selected, ixs, n+1u);
            prefix += inner.prefix;
            ret rec(prefix=prefix with inner);
        }
    }

    // We make a fake prefix tuple-type here; luckily for measuring sizes
    // the tuple parens are associative so it doesn't matter that we've
    // flattened the incoming structure.

    auto s = split_type(t, ixs, 0u);
1191
    auto prefix_ty = ty.plain_tup_ty(s.prefix);
1192 1193 1194 1195 1196
    auto bcx = cx;
    auto sz = size_of(bcx, prefix_ty);
    bcx = sz.bcx;
    auto raw = bcx.build.PointerCast(base, T_ptr(T_i8()));
    auto bumped = bcx.build.GEP(raw, vec(sz.val));
1197 1198 1199

    if (ty.type_has_dynamic_size(s.target)) {
        ret res(bcx, bumped);
1200
    }
1201 1202 1203

    auto typ = T_ptr(type_of(bcx.fcx.ccx, s.target));
    ret res(bcx, bcx.build.PointerCast(bumped, typ));
1204 1205
}

1206 1207 1208 1209
// 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.
1210 1211 1212 1213 1214 1215
fn GEP_tag(@block_ctxt cx,
           ValueRef llblobptr,
           &ast.def_id tag_id,
           &ast.def_id variant_id,
           vec[@ty.t] ty_substs,
           int ix)
1216
        -> result {
1217 1218 1219
    auto ty_params = tag_ty_params(cx.fcx.ccx, tag_id);
    auto variant = tag_variant_with_id(cx.fcx.ccx, tag_id, variant_id);

1220 1221 1222 1223 1224 1225 1226
    // Synthesize a tuple type so that GEP_tup_like() can work its magic.
    // Separately, store the type of the element we're interested in.
    auto arg_tys = arg_tys_of_fn(variant.ann);
    auto elem_ty = ty.plain_ty(ty.ty_nil);  // typestate infelicity
    auto i = 0;
    let vec[@ty.t] true_arg_tys = vec();
    for (ty.arg a in arg_tys) {
1227 1228
        auto arg_ty = ty.substitute_ty_params(ty_params, ty_substs, a.ty);
        true_arg_tys += vec(arg_ty);
1229
        if (i == ix) {
1230
            elem_ty = arg_ty;
1231 1232 1233 1234
        }

        i += 1;
    }
1235 1236

    auto tup_ty = ty.plain_tup_ty(true_arg_tys);
1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262

    // Cast the blob pointer to the appropriate type, if we need to (i.e. if
    // the blob pointer isn't dynamically sized).
    let ValueRef llunionptr;
    if (!ty.type_has_dynamic_size(tup_ty)) {
        auto llty = type_of(cx.fcx.ccx, tup_ty);
        llunionptr = cx.build.TruncOrBitCast(llblobptr, T_ptr(llty));
    } else {
        llunionptr = llblobptr;
    }

    // Do the GEP_tup_like().
    auto rslt = GEP_tup_like(cx, tup_ty, llunionptr, vec(0, ix));

    // Cast the result to the appropriate type, if necessary.
    auto val;
    if (!ty.type_has_dynamic_size(elem_ty)) {
        auto llelemty = type_of(rslt.bcx.fcx.ccx, elem_ty);
        val = rslt.bcx.build.PointerCast(rslt.val, T_ptr(llelemty));
    } else {
        val = rslt.val;
    }

    ret res(rslt.bcx, val);
}

1263

1264 1265
fn trans_raw_malloc(@block_ctxt cx, TypeRef llptr_ty, ValueRef llsize)
        -> result {
1266 1267
    // FIXME: need a table to collect tydesc globals.
    auto tydesc = C_int(0);
1268 1269 1270 1271 1272
    auto rslt = trans_upcall(cx, "upcall_malloc", vec(llsize, tydesc));
    rslt = res(rslt.bcx, vi2p(cx, rslt.val, llptr_ty));
    ret rslt;
}

1273 1274 1275
fn trans_malloc_boxed(@block_ctxt cx, @ty.t t) -> result {
    // Synthesize a fake box type structurally so we have something
    // to measure the size of.
1276 1277
    auto boxed_body = ty.plain_tup_ty(vec(plain_ty(ty.ty_int), t));
    auto box_ptr = ty.plain_box_ty(t);
1278 1279 1280
    auto sz = size_of(cx, boxed_body);
    auto llty = type_of(cx.fcx.ccx, box_ptr);
    ret trans_raw_malloc(sz.bcx, llty, sz.val);
1281 1282 1283
}


1284 1285 1286 1287 1288
// 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.
1289
fn field_of_tydesc(@block_ctxt cx, @ty.t t, int field) -> result {
1290
    auto tydesc = get_tydesc(cx, t);
1291 1292
    ret res(tydesc.bcx,
            tydesc.bcx.build.GEP(tydesc.val, vec(C_int(0), C_int(field))));
1293
}
1294

1295 1296 1297 1298 1299 1300 1301 1302 1303
// Given a type containing ty params, build a vector containing a ValueRef for
// each of the ty params it uses (from the current frame), as well as a vec
// containing a def_id for each such param. This is used solely for
// constructing derived tydescs.
fn linearize_ty_params(@block_ctxt cx, @ty.t t)
    -> tup(vec[ast.def_id], vec[ValueRef]) {
    let vec[ValueRef] param_vals = vec();
    let vec[ast.def_id] param_defs = vec();
    type rr = rec(@block_ctxt cx,
1304 1305
                  mutable vec[ValueRef] vals,
                  mutable vec[ast.def_id] defs);
1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317

    state obj folder(@rr r) {
        fn fold_simple_ty(@ty.t t) -> @ty.t {
            alt(t.struct) {
                case (ty.ty_param(?pid)) {
                    let bool seen = false;
                    for (ast.def_id d in r.defs) {
                        if (d == pid) {
                            seen = true;
                        }
                    }
                    if (!seen) {
1318 1319
                        r.vals += vec(r.cx.fcx.lltydescs.get(pid));
                        r.defs += vec(pid);
1320 1321
                    }
                }
1322
                case (_) { }
1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337
            }
            ret t;
        }
    }


    auto x = @rec(cx = cx,
                  mutable vals = param_vals,
                  mutable defs = param_defs);

    ty.fold_ty(folder(x), t);

    ret tup(x.defs, x.vals);
}

1338
fn get_tydesc(&@block_ctxt cx, @ty.t t) -> result {
1339
    // Is the supplied type a type param? If so, return the passed-in tydesc.
1340
    alt (ty.type_param(t)) {
1341
        case (some[ast.def_id](?id)) {
1342
            check (cx.fcx.lltydescs.contains_key(id));
1343 1344
            ret res(cx, cx.fcx.lltydescs.get(id));
        }
1345
        case (none[ast.def_id])      { /* fall through */ }
1346
    }
1347 1348

    // Does it contain a type param? If so, generate a derived tydesc.
1349
    let uint n_params = ty.count_ty_params(t);
1350

1351
    if (ty.count_ty_params(t) > 0u) {
1352
        auto tys = linearize_ty_params(cx, t);
1353

1354 1355 1356
        check (n_params == _vec.len[ast.def_id](tys._0));
        check (n_params == _vec.len[ValueRef](tys._1));

1357
        if (!cx.fcx.ccx.tydescs.contains_key(t)) {
1358 1359
            declare_tydesc(cx.fcx.ccx, t);
            define_tydesc(cx.fcx.ccx, t, tys._0);
1360 1361
        }

1362
        auto root = cx.fcx.ccx.tydescs.get(t).tydesc;
1363

1364 1365
        auto tydescs = cx.build.Alloca(T_array(T_ptr(T_tydesc(cx.fcx.ccx.tn)),
                                               n_params));
1366

1367
        auto i = 0;
1368 1369 1370
        auto tdp = cx.build.GEP(tydescs, vec(C_int(0), C_int(i)));
        cx.build.Store(root, tdp);
        i += 1;
1371 1372
        for (ValueRef td in tys._1) {
            auto tdp = cx.build.GEP(tydescs, vec(C_int(0), C_int(i)));
1373
            cx.build.Store(td, tdp);
1374
            i += 1;
1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386
        }

        auto bcx = cx;
        auto sz = size_of(bcx, t);
        bcx = sz.bcx;
        auto align = align_of(bcx, t);
        bcx = align.bcx;

        auto v = trans_upcall(bcx, "upcall_get_type_desc",
                              vec(p2i(bcx.fcx.ccx.crate_ptr),
                                  sz.val,
                                  align.val,
1387
                                  C_int((1u + n_params) as int),
1388
                                  vp2i(bcx, tydescs)));
1389

1390 1391
        ret res(v.bcx, vi2p(v.bcx, v.val,
                            T_ptr(T_tydesc(cx.fcx.ccx.tn))));
1392 1393 1394
    }

    // Otherwise, generate a tydesc if necessary, and return it.
1395
    if (!cx.fcx.ccx.tydescs.contains_key(t)) {
1396
        let vec[ast.def_id] defs = vec();
1397 1398
        declare_tydesc(cx.fcx.ccx, t);
        define_tydesc(cx.fcx.ccx, t, defs);
1399
    }
1400
    ret res(cx, cx.fcx.ccx.tydescs.get(t).tydesc);
1401 1402
}

1403 1404 1405 1406 1407 1408
// Generates the declaration for (but doesn't fill in) a type descriptor. This
// needs to be separate from make_tydesc() below, because sometimes type glue
// functions needs to refer to their own type descriptors.
fn declare_tydesc(@crate_ctxt cx, @ty.t t) {
    auto take_glue = declare_generic_glue(cx, t, "take");
    auto drop_glue = declare_generic_glue(cx, t, "drop");
1409

1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422
    auto llsize;
    auto llalign;
    if (!ty.type_has_dynamic_size(t)) {
        auto llty = type_of(cx, t);
        llsize = llsize_of(llty);
        llalign = llalign_of(llty);
    } else {
        // These will be overwritten as the derived tydesc is generated, so
        // we create placeholder values.
        llsize = C_int(0);
        llalign = C_int(0);
    }

1423
    auto glue_fn_ty = T_ptr(T_glue_fn(cx.tn));
1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435

    // FIXME: this adjustment has to do with the ridiculous encoding of
    // glue-pointer-constants in the tydesc records: They are tydesc-relative
    // displacements.  This is purely for compatibility with rustboot and
    // should go when it is discarded.
    fn off(ValueRef tydescp,
           ValueRef gluefn) -> ValueRef {
        ret i2p(llvm.LLVMConstSub(p2i(gluefn), p2i(tydescp)),
                val_ty(gluefn));
    }

    auto name = sanitize(cx.names.next("tydesc_" + ty.ty_to_str(t)));
1436 1437 1438
    auto gvar = llvm.LLVMAddGlobal(cx.llmod, T_tydesc(cx.tn),
                                   _str.buf(name));
    auto tydesc = C_struct(vec(C_null(T_ptr(T_ptr(T_tydesc(cx.tn)))),
1439 1440
                               llsize,
                               llalign,
1441 1442
                               off(gvar, take_glue),  // take_glue_off
                               off(gvar, drop_glue),  // drop_glue_off
1443 1444 1445 1446 1447 1448 1449 1450
                               C_null(glue_fn_ty),    // free_glue_off
                               C_null(glue_fn_ty),    // sever_glue_off
                               C_null(glue_fn_ty),    // mark_glue_off
                               C_null(glue_fn_ty),    // obj_drop_glue_off
                               C_null(glue_fn_ty)));  // is_stateful

    llvm.LLVMSetInitializer(gvar, tydesc);
    llvm.LLVMSetGlobalConstant(gvar, True);
1451 1452
    llvm.LLVMSetLinkage(gvar, lib.llvm.LLVMPrivateLinkage
                        as llvm.Linkage);
1453 1454 1455 1456 1457 1458 1459 1460

    auto info = rec(
        tydesc=gvar,
        take_glue=take_glue,
        drop_glue=drop_glue
    );

    cx.tydescs.insert(t, @info);
1461 1462
}

1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476
// declare_tydesc() above must have been called first.
fn define_tydesc(@crate_ctxt cx, @ty.t t, vec[ast.def_id] typaram_defs) {
    auto info = cx.tydescs.get(t);
    auto gvar = info.tydesc;

    auto tg = make_take_glue;
    auto take_glue = make_generic_glue(cx, t, info.take_glue, tg,
                                       typaram_defs);
    auto dg = make_drop_glue;
    auto drop_glue = make_generic_glue(cx, t, info.drop_glue, dg,
                                       typaram_defs);
}

fn declare_generic_glue(@crate_ctxt cx, @ty.t t, str name) -> ValueRef {
1477
    auto llfnty = T_glue_fn(cx.tn);
1478

1479
    auto fn_name = cx.names.next("_rust_" + name) + sep() + ty.ty_to_str(t);
1480
    fn_name = sanitize(fn_name);
1481 1482 1483
    auto llfn = decl_fastcall_fn(cx.llmod, fn_name, llfnty);
    llvm.LLVMSetLinkage(llfn, lib.llvm.LLVMPrivateLinkage as llvm.Linkage);
    ret llfn;
1484
}
1485

1486 1487 1488
fn make_generic_glue(@crate_ctxt cx, @ty.t t, ValueRef llfn,
                     val_and_ty_fn helper,
                     vec[ast.def_id] typaram_defs) -> ValueRef {
1489
    auto fcx = new_fn_ctxt(cx, llfn);
1490 1491
    auto bcx = new_top_block_ctxt(fcx);

1492
    auto re;
1493
    if (!ty.type_is_scalar(t)) {
1494
        auto llty;
1495 1496 1497
        if (ty.type_has_dynamic_size(t)) {
            llty = T_ptr(T_i8());
        } else if (ty.type_is_structural(t)) {
1498 1499 1500 1501
            llty = T_ptr(type_of(cx, t));
        } else {
            llty = type_of(cx, t);
        }
1502

1503
        auto lltyparams = llvm.LLVMGetParam(llfn, 3u);
1504 1505 1506 1507 1508 1509 1510 1511
        auto p = 0;
        for (ast.def_id d in typaram_defs) {
            auto llparam = bcx.build.GEP(lltyparams, vec(C_int(p)));
            llparam = bcx.build.Load(llparam);
            bcx.fcx.lltydescs.insert(d, llparam);
            p += 1;
        }

1512
        auto llrawptr = llvm.LLVMGetParam(llfn, 4u);
1513
        auto llval = bcx.build.BitCast(llrawptr, llty);
G
Graydon Hoare 已提交
1514

1515 1516 1517 1518
        re = helper(bcx, llval, t);
    } else {
        re = res(bcx, C_nil());
    }
1519

1520
    re.bcx.build.RetVoid();
1521 1522 1523
    ret llfn;
}

1524 1525
fn make_take_glue(@block_ctxt cx, ValueRef v, @ty.t t) -> result {
    if (ty.type_is_boxed(t)) {
1526 1527
        ret incr_refcnt_of_boxed(cx, v);

1528
    } else if (ty.type_is_structural(t)) {
1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553
        ret iter_structural_ty(cx, v, t,
                               bind incr_all_refcnts(_, _, _));
    }
    ret res(cx, C_nil());
}

fn incr_refcnt_of_boxed(@block_ctxt cx, ValueRef box_ptr) -> result {
    auto rc_ptr = cx.build.GEP(box_ptr, vec(C_int(0),
                                            C_int(abi.box_rc_field_refcnt)));
    auto rc = cx.build.Load(rc_ptr);

    auto rc_adj_cx = new_sub_block_ctxt(cx, "rc++");
    auto next_cx = new_sub_block_ctxt(cx, "next");

    auto const_test = cx.build.ICmp(lib.llvm.LLVMIntEQ,
                                    C_int(abi.const_refcount as int), rc);
    cx.build.CondBr(const_test, next_cx.llbb, rc_adj_cx.llbb);

    rc = rc_adj_cx.build.Add(rc, C_int(1));
    rc_adj_cx.build.Store(rc, rc_ptr);
    rc_adj_cx.build.Br(next_cx.llbb);

    ret res(next_cx, C_nil());
}

1554
fn make_drop_glue(@block_ctxt cx, ValueRef v, @ty.t t) -> result {
1555
    alt (t.struct) {
1556
        case (ty.ty_str) {
G
Graydon Hoare 已提交
1557 1558 1559 1560
            ret decr_refcnt_and_if_zero
                (cx, v, bind trans_non_gc_free(_, v),
                 "free string",
                 T_int(), C_int(0));
1561 1562
        }

1563
        case (ty.ty_vec(_)) {
G
Graydon Hoare 已提交
1564 1565 1566 1567
            fn hit_zero(@block_ctxt cx, ValueRef v,
                        @ty.t t) -> result {
                auto res = iter_sequence(cx, v, t,
                                         bind drop_ty(_,_,_));
1568 1569 1570 1571 1572 1573 1574 1575 1576
                // FIXME: switch gc/non-gc on layer of the type.
                ret trans_non_gc_free(res.bcx, v);
            }
            ret decr_refcnt_and_if_zero(cx, v,
                                        bind hit_zero(_, v, t),
                                        "free vector",
                                        T_int(), C_int(0));
        }

1577
        case (ty.ty_box(?body_mt)) {
G
Graydon Hoare 已提交
1578 1579
            fn hit_zero(@block_ctxt cx, ValueRef v,
                        @ty.t body_ty) -> result {
1580 1581 1582 1583
                auto body = cx.build.GEP(v,
                                         vec(C_int(0),
                                             C_int(abi.box_rc_field_body)));

1584
                auto body_val = load_scalar_or_boxed(cx, body, body_ty);
1585 1586 1587 1588 1589
                auto res = drop_ty(cx, body_val, body_ty);
                // FIXME: switch gc/non-gc on layer of the type.
                ret trans_non_gc_free(res.bcx, v);
            }
            ret decr_refcnt_and_if_zero(cx, v,
1590
                                        bind hit_zero(_, v, body_mt.ty),
1591 1592 1593 1594
                                        "free box",
                                        T_int(), C_int(0));
        }

1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607
        case (ty.ty_obj(_)) {
            fn hit_zero(@block_ctxt cx, ValueRef v) -> result {

                // Call through the obj's own fields-drop glue first.
                auto body =
                    cx.build.GEP(v,
                                 vec(C_int(0),
                                     C_int(abi.box_rc_field_body)));

                auto tydescptr =
                    cx.build.GEP(body,
                                 vec(C_int(0),
                                     C_int(abi.obj_body_elt_tydesc)));
1608

1609
                call_tydesc_glue_full(cx, body, cx.build.Load(tydescptr),
1610
                                      abi.tydesc_field_drop_glue_off);
1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628

                // Then free the body.
                // FIXME: switch gc/non-gc on layer of the type.
                ret trans_non_gc_free(cx, v);
            }
            auto box_cell =
                cx.build.GEP(v,
                             vec(C_int(0),
                                 C_int(abi.obj_field_box)));

            auto boxptr = cx.build.Load(box_cell);

            ret decr_refcnt_and_if_zero(cx, boxptr,
                                        bind hit_zero(_, boxptr),
                                        "free obj",
                                        T_int(), C_int(0));
        }

1629
        case (ty.ty_fn(_,_,_)) {
1630 1631 1632 1633 1634 1635 1636
            fn hit_zero(@block_ctxt cx, ValueRef v) -> result {

                // Call through the closure's own fields-drop glue first.
                auto body =
                    cx.build.GEP(v,
                                 vec(C_int(0),
                                     C_int(abi.box_rc_field_body)));
1637 1638 1639 1640
                auto bindings =
                    cx.build.GEP(body,
                                 vec(C_int(0),
                                     C_int(abi.closure_elt_bindings)));
1641 1642 1643 1644 1645

                auto tydescptr =
                    cx.build.GEP(body,
                                 vec(C_int(0),
                                     C_int(abi.closure_elt_tydesc)));
1646

1647
                call_tydesc_glue_full(cx, bindings, cx.build.Load(tydescptr),
1648 1649
                                      abi.tydesc_field_drop_glue_off);

1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667

                // Then free the body.
                // FIXME: switch gc/non-gc on layer of the type.
                ret trans_non_gc_free(cx, v);
            }
            auto box_cell =
                cx.build.GEP(v,
                             vec(C_int(0),
                                 C_int(abi.fn_field_box)));

            auto boxptr = cx.build.Load(box_cell);

            ret decr_refcnt_and_if_zero(cx, boxptr,
                                        bind hit_zero(_, boxptr),
                                        "free fn",
                                        T_int(), C_int(0));
        }

1668
        case (_) {
1669
            if (ty.type_is_structural(t)) {
1670 1671 1672
                ret iter_structural_ty(cx, v, t,
                                       bind drop_ty(_, _, _));

1673
            } else if (ty.type_is_scalar(t) ||
1674
                       ty.type_is_native(t) ||
1675
                       ty.type_is_nil(t)) {
1676 1677 1678 1679
                ret res(cx, C_nil());
            }
        }
    }
1680
    cx.fcx.ccx.sess.bug("bad type in trans.make_drop_glue_inner: " +
1681
                        ty.ty_to_str(t));
1682 1683 1684
    fail;
}

1685 1686
fn decr_refcnt_and_if_zero(@block_ctxt cx,
                           ValueRef box_ptr,
1687
                           fn(@block_ctxt cx) -> result inner,
1688
                           str inner_name,
1689
                           TypeRef t_else, ValueRef v_else) -> result {
1690

1691
    auto load_rc_cx = new_sub_block_ctxt(cx, "load rc");
1692 1693 1694 1695
    auto rc_adj_cx = new_sub_block_ctxt(cx, "rc--");
    auto inner_cx = new_sub_block_ctxt(cx, inner_name);
    auto next_cx = new_sub_block_ctxt(cx, "next");

1696 1697
    auto null_test = cx.build.IsNull(box_ptr);
    cx.build.CondBr(null_test, next_cx.llbb, load_rc_cx.llbb);
1698

1699 1700 1701 1702 1703 1704 1705 1706 1707 1708

    auto rc_ptr = load_rc_cx.build.GEP(box_ptr,
                                       vec(C_int(0),
                                           C_int(abi.box_rc_field_refcnt)));

    auto rc = load_rc_cx.build.Load(rc_ptr);
    auto const_test =
        load_rc_cx.build.ICmp(lib.llvm.LLVMIntEQ,
                              C_int(abi.const_refcount as int), rc);
    load_rc_cx.build.CondBr(const_test, next_cx.llbb, rc_adj_cx.llbb);
1709 1710 1711 1712

    rc = rc_adj_cx.build.Sub(rc, C_int(1));
    rc_adj_cx.build.Store(rc, rc_ptr);
    auto zero_test = rc_adj_cx.build.ICmp(lib.llvm.LLVMIntEQ, C_int(0), rc);
1713 1714 1715 1716
    rc_adj_cx.build.CondBr(zero_test, inner_cx.llbb, next_cx.llbb);

    auto inner_res = inner(inner_cx);
    inner_res.bcx.build.Br(next_cx.llbb);
1717

1718
    auto phi = next_cx.build.Phi(t_else,
1719
                                 vec(v_else, v_else, v_else, inner_res.val),
1720
                                 vec(cx.llbb,
1721
                                     load_rc_cx.llbb,
1722
                                     rc_adj_cx.llbb,
1723 1724
                                     inner_res.bcx.llbb));

1725
    ret res(next_cx, phi);
1726 1727
}

1728 1729
// Tag information

1730 1731
fn variant_types(@crate_ctxt cx, &ast.variant v) -> vec[@ty.t] {
    let vec[@ty.t] tys = vec();
1732
    alt (ty.ann_to_type(v.ann).struct) {
1733
        case (ty.ty_fn(_, ?args, _)) {
1734
            for (ty.arg arg in args) {
1735
                tys += vec(arg.ty);
1736 1737
            }
        }
1738
        case (ty.ty_tag(_, _)) { /* nothing */ }
1739 1740
        case (_) { fail; }
    }
1741 1742 1743
    ret tys;
}

1744 1745 1746 1747 1748 1749 1750 1751 1752
// Returns the type parameters of a tag.
fn tag_ty_params(@crate_ctxt cx, ast.def_id id) -> vec[ast.ty_param] {
    check (cx.items.contains_key(id));
    alt (cx.items.get(id).node) {
        case (ast.item_tag(_, _, ?tps, _)) { ret tps; }
    }
    fail;   // not reached
}

1753 1754
// Returns the variants in a tag.
fn tag_variants(@crate_ctxt cx, ast.def_id id) -> vec[ast.variant] {
1755 1756
    check (cx.items.contains_key(id));
    alt (cx.items.get(id).node) {
1757
        case (ast.item_tag(_, ?variants, _, _)) { ret variants; }
1758 1759 1760 1761
    }
    fail;   // not reached
}

1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780
// Returns the tag variant with the given ID.
fn tag_variant_with_id(@crate_ctxt cx,
                       &ast.def_id tag_id,
                       &ast.def_id variant_id) -> ast.variant {
    auto variants = tag_variants(cx, tag_id);

    auto i = 0u;
    while (i < _vec.len[ast.variant](variants)) {
        auto variant = variants.(i);
        if (common.def_eq(variant.id, variant_id)) {
            ret variant;
        }
        i += 1u;
    }

    log "tag_variant_with_id(): no variant exists with that ID";
    fail;
}

1781 1782 1783 1784 1785 1786 1787 1788
// Returns a new plain tag type of the given ID with no type parameters. Don't
// use this function in new code; it's a hack to keep things working for now.
fn mk_plain_tag(ast.def_id tid) -> @ty.t {
    let vec[@ty.t] tps = vec();
    ret ty.plain_ty(ty.ty_tag(tid, tps));
}


1789
type val_pair_fn = fn(@block_ctxt cx, ValueRef dst, ValueRef src) -> result;
1790

1791
type val_and_ty_fn = fn(@block_ctxt cx, ValueRef v, @ty.t t) -> result;
1792

1793 1794 1795
type val_pair_and_ty_fn =
    fn(@block_ctxt cx, ValueRef av, ValueRef bv, @ty.t t) -> result;

1796
// Iterates through the elements of a structural type.
1797 1798
fn iter_structural_ty(@block_ctxt cx,
                      ValueRef v,
1799
                      @ty.t t,
1800 1801
                      val_and_ty_fn f)
    -> result {
1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819
    fn adaptor_fn(val_and_ty_fn f,
                  @block_ctxt cx,
                  ValueRef av,
                  ValueRef bv,
                  @ty.t t) -> result {
        ret f(cx, av, t);
    }
    be iter_structural_ty_full(cx, v, v, t,
                               bind adaptor_fn(f, _, _, _, _));
}


fn iter_structural_ty_full(@block_ctxt cx,
                           ValueRef av,
                           ValueRef bv,
                           @ty.t t,
                           val_pair_and_ty_fn f)
    -> result {
1820
    let result r = res(cx, C_nil());
1821

1822
    fn iter_boxpp(@block_ctxt cx,
1823 1824 1825 1826 1827
                  ValueRef box_a_cell,
                  ValueRef box_b_cell,
                  val_pair_and_ty_fn f) -> result {
        auto box_a_ptr = cx.build.Load(box_a_cell);
        auto box_b_ptr = cx.build.Load(box_b_cell);
1828
        auto tnil = plain_ty(ty.ty_nil);
1829
        auto tbox = ty.plain_box_ty(tnil);
1830 1831 1832

        auto inner_cx = new_sub_block_ctxt(cx, "iter box");
        auto next_cx = new_sub_block_ctxt(cx, "next");
1833
        auto null_test = cx.build.IsNull(box_a_ptr);
1834 1835
        cx.build.CondBr(null_test, next_cx.llbb, inner_cx.llbb);

1836
        auto r = f(inner_cx, box_a_ptr, box_b_ptr, tbox);
1837 1838 1839 1840
        r.bcx.build.Br(next_cx.llbb);
        ret res(next_cx, r.val);
    }

1841
    alt (t.struct) {
1842
        case (ty.ty_tup(?args)) {
1843
            let int i = 0;
1844
            for (ty.mt arg in args) {
1845 1846 1847 1848
                r = GEP_tup_like(r.bcx, t, av, vec(0, i));
                auto elt_a = r.val;
                r = GEP_tup_like(r.bcx, t, bv, vec(0, i));
                auto elt_b = r.val;
1849
                r = f(r.bcx,
1850 1851 1852
                      load_scalar_or_boxed(r.bcx, elt_a, arg.ty),
                      load_scalar_or_boxed(r.bcx, elt_b, arg.ty),
                      arg.ty);
1853 1854 1855
                i += 1;
            }
        }
1856
        case (ty.ty_rec(?fields)) {
1857
            let int i = 0;
1858
            for (ty.field fld in fields) {
1859 1860 1861 1862
                r = GEP_tup_like(r.bcx, t, av, vec(0, i));
                auto llfld_a = r.val;
                r = GEP_tup_like(r.bcx, t, bv, vec(0, i));
                auto llfld_b = r.val;
1863
                r = f(r.bcx,
1864 1865 1866
                      load_scalar_or_boxed(r.bcx, llfld_a, fld.mt.ty),
                      load_scalar_or_boxed(r.bcx, llfld_b, fld.mt.ty),
                      fld.mt.ty);
1867 1868 1869
                i += 1;
            }
        }
1870
        case (ty.ty_tag(?tid, ?tps)) {
1871 1872
            auto variants = tag_variants(cx.fcx.ccx, tid);
            auto n_variants = _vec.len[ast.variant](variants);
1873

1874 1875 1876 1877 1878 1879 1880 1881 1882
            // Cast the tags to types we can GEP into.
            auto lltagty = T_opaque_tag_ptr(cx.fcx.ccx.tn);
            auto av_tag = cx.build.PointerCast(av, lltagty);
            auto bv_tag = cx.build.PointerCast(bv, lltagty);

            auto lldiscrim_a_ptr = cx.build.GEP(av_tag,
                                                vec(C_int(0), C_int(0)));
            auto llunion_a_ptr = cx.build.GEP(av_tag,
                                              vec(C_int(0), C_int(1)));
1883 1884
            auto lldiscrim_a = cx.build.Load(lldiscrim_a_ptr);

1885 1886 1887 1888
            auto lldiscrim_b_ptr = cx.build.GEP(bv_tag,
                                                vec(C_int(0), C_int(0)));
            auto llunion_b_ptr = cx.build.GEP(bv_tag,
                                              vec(C_int(0), C_int(1)));
1889
            auto lldiscrim_b = cx.build.Load(lldiscrim_b_ptr);
G
Graydon Hoare 已提交
1890

1891 1892 1893 1894 1895 1896 1897
            // NB: we must hit the discriminant first so that structural
            // comparison know not to proceed when the discriminants differ.
            auto bcx = cx;
            bcx = f(bcx, lldiscrim_a, lldiscrim_b,
                    plain_ty(ty.ty_int)).bcx;

            auto unr_cx = new_sub_block_ctxt(bcx, "tag-iter-unr");
1898 1899
            unr_cx.build.Unreachable();

1900
            auto llswitch = bcx.build.Switch(lldiscrim_a, unr_cx.llbb,
1901
                                             n_variants);
G
Graydon Hoare 已提交
1902

1903
            auto next_cx = new_sub_block_ctxt(bcx, "tag-iter-next");
1904

1905 1906
            auto ty_params = tag_ty_params(bcx.fcx.ccx, tid);

1907
            auto i = 0u;
1908
            for (ast.variant variant in variants) {
1909
                auto variant_cx = new_sub_block_ctxt(bcx,
1910
                                                     "tag-iter-variant-" +
1911 1912 1913
                                                     _uint.to_str(i, 10u));
                llvm.LLVMAddCase(llswitch, C_int(i as int), variant_cx.llbb);

1914 1915 1916 1917 1918
                if (_vec.len[ast.variant_arg](variant.args) > 0u) {
                    // N-ary variant.
                    auto fn_ty = ty.ann_to_type(variants.(i).ann);
                    alt (fn_ty.struct) {
                        case (ty.ty_fn(_, ?args, _)) {
1919
                            auto j = 0;
1920 1921
                            for (ty.arg a in args) {
                                auto v = vec(C_int(0), C_int(j as int));
1922

1923 1924 1925 1926
                                auto rslt = GEP_tag(variant_cx, llunion_a_ptr,
                                    tid, variants.(i).id, tps, j);
                                auto llfldp_a = rslt.val;
                                variant_cx = rslt.bcx;
1927

1928 1929 1930 1931
                                rslt = GEP_tag(variant_cx, llunion_b_ptr, tid,
                                    variants.(i).id, tps, j);
                                auto llfldp_b = rslt.val;
                                variant_cx = rslt.bcx;
1932 1933

                                auto ty_subst = ty.substitute_ty_params(
1934
                                    ty_params, tps, a.ty);
1935

1936
                                auto llfld_a =
1937
                                    load_scalar_or_boxed(variant_cx,
1938
                                                         llfldp_a,
1939 1940
                                                         ty_subst);

1941 1942 1943 1944 1945 1946 1947
                                auto llfld_b =
                                    load_scalar_or_boxed(variant_cx,
                                                         llfldp_b,
                                                         ty_subst);

                                auto res = f(variant_cx,
                                             llfld_a, llfld_b, ty_subst);
1948
                                variant_cx = res.bcx;
1949
                                j += 1;
1950 1951
                            }
                        }
1952
                        case (_) { fail; }
1953
                    }
1954 1955 1956 1957 1958

                    variant_cx.build.Br(next_cx.llbb);
                } else {
                    // Nullary variant; nothing to do.
                    variant_cx.build.Br(next_cx.llbb);
1959 1960 1961 1962 1963 1964 1965
                }

                i += 1u;
            }

            ret res(next_cx, C_nil());
        }
1966
        case (ty.ty_fn(_,_,_)) {
1967 1968 1969 1970 1971 1972
            auto box_cell_a =
                cx.build.GEP(av,
                             vec(C_int(0),
                                 C_int(abi.fn_field_box)));
            auto box_cell_b =
                cx.build.GEP(bv,
1973 1974
                             vec(C_int(0),
                                 C_int(abi.fn_field_box)));
1975
            ret iter_boxpp(cx, box_cell_a, box_cell_b, f);
1976
        }
1977
        case (ty.ty_obj(_)) {
1978 1979 1980 1981 1982 1983
            auto box_cell_a =
                cx.build.GEP(av,
                             vec(C_int(0),
                                 C_int(abi.obj_field_box)));
            auto box_cell_b =
                cx.build.GEP(bv,
1984 1985
                             vec(C_int(0),
                                 C_int(abi.obj_field_box)));
1986
            ret iter_boxpp(cx, box_cell_a, box_cell_b, f);
1987
        }
1988
        case (_) {
1989
            cx.fcx.ccx.sess.unimpl("type in iter_structural_ty_full");
1990
        }
1991
    }
1992
    ret r;
1993 1994
}

1995 1996
// Iterates through a pointer range, until the src* hits the src_lim*.
fn iter_sequence_raw(@block_ctxt cx,
1997
                     ValueRef dst,     // elt*
1998 1999 2000
                     ValueRef src,     // elt*
                     ValueRef src_lim, // elt*
                     ValueRef elt_sz,
2001
                     val_pair_fn f) -> result {
2002 2003 2004

    auto bcx = cx;

2005
    let ValueRef dst_int = vp2i(bcx, dst);
2006 2007 2008 2009 2010 2011 2012 2013 2014
    let ValueRef src_int = vp2i(bcx, src);
    let ValueRef src_lim_int = vp2i(bcx, src_lim);

    auto cond_cx = new_scope_block_ctxt(cx, "sequence-iter cond");
    auto body_cx = new_scope_block_ctxt(cx, "sequence-iter body");
    auto next_cx = new_sub_block_ctxt(cx, "next");

    bcx.build.Br(cond_cx.llbb);

2015 2016
    let ValueRef dst_curr = cond_cx.build.Phi(T_int(),
                                              vec(dst_int), vec(bcx.llbb));
2017 2018 2019
    let ValueRef src_curr = cond_cx.build.Phi(T_int(),
                                              vec(src_int), vec(bcx.llbb));

2020
    auto end_test = cond_cx.build.ICmp(lib.llvm.LLVMIntULT,
2021 2022 2023 2024
                                       src_curr, src_lim_int);

    cond_cx.build.CondBr(end_test, body_cx.llbb, next_cx.llbb);

2025
    auto dst_curr_ptr = vi2p(body_cx, dst_curr, T_ptr(T_i8()));
2026
    auto src_curr_ptr = vi2p(body_cx, src_curr, T_ptr(T_i8()));
2027

2028
    auto body_res = f(body_cx, dst_curr_ptr, src_curr_ptr);
2029 2030
    body_cx = body_res.bcx;

2031
    auto dst_next = body_cx.build.Add(dst_curr, elt_sz);
2032
    auto src_next = body_cx.build.Add(src_curr, elt_sz);
2033 2034
    body_cx.build.Br(cond_cx.llbb);

2035 2036
    cond_cx.build.AddIncomingToPhi(dst_curr, vec(dst_next),
                                   vec(body_cx.llbb));
2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049
    cond_cx.build.AddIncomingToPhi(src_curr, vec(src_next),
                                   vec(body_cx.llbb));

    ret res(next_cx, C_nil());
}


fn iter_sequence_inner(@block_ctxt cx,
                       ValueRef src,     // elt*
                       ValueRef src_lim, // elt*
                       @ty.t elt_ty,
                       val_and_ty_fn f) -> result {
    fn adaptor_fn(val_and_ty_fn f,
2050
                  @ty.t elt_ty,
2051
                  @block_ctxt cx,
2052 2053
                  ValueRef dst,
                  ValueRef src) -> result {
2054 2055 2056 2057 2058 2059 2060 2061 2062
        auto llptrty;
        if (!ty.type_has_dynamic_size(elt_ty)) {
            auto llty = type_of(cx.fcx.ccx, elt_ty);
            llptrty = T_ptr(llty);
        } else {
            llptrty = T_ptr(T_ptr(T_i8()));
        }

        auto p = cx.build.PointerCast(src, llptrty);
2063
        ret f(cx, load_scalar_or_boxed(cx, p, elt_ty), elt_ty);
2064 2065
    }

2066
    auto elt_sz = size_of(cx, elt_ty);
2067 2068
    be iter_sequence_raw(elt_sz.bcx, src, src, src_lim, elt_sz.val,
                         bind adaptor_fn(f, elt_ty, _, _, _));
2069 2070 2071
}


2072 2073 2074
// Iterates through the elements of a vec or str.
fn iter_sequence(@block_ctxt cx,
                 ValueRef v,
2075
                 @ty.t t,
2076 2077 2078 2079
                 val_and_ty_fn f) -> result {

    fn iter_sequence_body(@block_ctxt cx,
                          ValueRef v,
2080
                          @ty.t elt_ty,
2081 2082 2083 2084 2085 2086 2087
                          val_and_ty_fn f,
                          bool trailing_null) -> result {

        auto p0 = cx.build.GEP(v, vec(C_int(0),
                                      C_int(abi.vec_elt_data)));
        auto lenptr = cx.build.GEP(v, vec(C_int(0),
                                          C_int(abi.vec_elt_fill)));
2088

2089 2090 2091 2092 2093 2094 2095
        auto llunit_ty;
        if (ty.type_has_dynamic_size(elt_ty)) {
            llunit_ty = T_i8();
        } else {
            llunit_ty = type_of(cx.fcx.ccx, elt_ty);
        }

2096
        auto bcx = cx;
2097

2098
        auto len = bcx.build.Load(lenptr);
2099
        if (trailing_null) {
2100 2101
            auto unit_sz = size_of(bcx, elt_ty);
            bcx = unit_sz.bcx;
2102
            len = bcx.build.Sub(len, unit_sz.val);
2103 2104
        }

2105 2106
        auto p1 = vi2p(bcx, bcx.build.Add(vp2i(bcx, p0), len),
                       T_ptr(llunit_ty));
2107

2108
        ret iter_sequence_inner(cx, p0, p1, elt_ty, f);
2109 2110
    }

2111
    alt (t.struct) {
2112 2113
        case (ty.ty_vec(?elt)) {
            ret iter_sequence_body(cx, v, elt.ty, f, false);
2114
        }
2115
        case (ty.ty_str) {
2116
            auto et = plain_ty(ty.ty_machine(common.ty_u8));
2117
            ret iter_sequence_body(cx, v, et, f, true);
2118
        }
2119
        case (_) { fail; }
2120
    }
2121 2122 2123 2124
    cx.fcx.ccx.sess.bug("bad type in trans.iter_sequence");
    fail;
}

2125 2126 2127 2128 2129 2130 2131 2132 2133
fn call_tydesc_glue_full(@block_ctxt cx, ValueRef v,
                         ValueRef tydesc, int field) {
    auto llrawptr = cx.build.BitCast(v, T_ptr(T_i8()));
    auto lltydescs = cx.build.GEP(tydesc,
                                  vec(C_int(0),
                                      C_int(abi.tydesc_field_first_param)));
    lltydescs = cx.build.Load(lltydescs);
    auto llfnptr = cx.build.GEP(tydesc, vec(C_int(0), C_int(field)));
    auto llfn = cx.build.Load(llfnptr);
2134 2135 2136 2137 2138

    // FIXME: this adjustment has to do with the ridiculous encoding of
    // glue-pointer-constants in the tydesc records: They are tydesc-relative
    // displacements.  This is purely for compatibility with rustboot and
    // should go when it is discarded.
2139 2140 2141
    llfn = vi2p(cx, cx.build.Add(vp2i(cx, llfn),
                                 vp2i(cx, tydesc)),
                val_ty(llfn));
2142

2143 2144 2145 2146 2147
    cx.build.FastCall(llfn, vec(C_null(T_ptr(T_nil())),
                                cx.fcx.lltaskptr,
                                C_null(T_ptr(T_nil())),
                                lltydescs,
                                llrawptr));
2148 2149 2150
}

fn call_tydesc_glue(@block_ctxt cx, ValueRef v, @ty.t t, int field) {
2151 2152
    auto td = get_tydesc(cx, t);
    call_tydesc_glue_full(td.bcx, v, td.val, field);
2153 2154
}

2155 2156
fn incr_all_refcnts(@block_ctxt cx,
                    ValueRef v,
2157 2158
                    @ty.t t) -> result {
    if (!ty.type_is_scalar(t)) {
2159
        call_tydesc_glue(cx, v, t, abi.tydesc_field_take_glue_off);
2160
    }
2161
    ret res(cx, C_nil());
2162 2163
}

2164 2165
fn drop_slot(@block_ctxt cx,
             ValueRef slot,
2166
             @ty.t t) -> result {
2167
    auto llptr = load_scalar_or_boxed(cx, slot, t);
2168 2169 2170 2171 2172 2173
    auto re = drop_ty(cx, llptr, t);

    auto llty = val_ty(slot);
    auto llelemty = lib.llvm.llvm.LLVMGetElementType(llty);
    re.bcx.build.Store(C_null(llelemty), slot);
    ret re;
2174 2175
}

2176 2177
fn drop_ty(@block_ctxt cx,
           ValueRef v,
2178
           @ty.t t) -> result {
2179

2180
    if (!ty.type_is_scalar(t)) {
2181
        call_tydesc_glue(cx, v, t, abi.tydesc_field_drop_glue_off);
2182
    }
2183
    ret res(cx, C_nil());
2184 2185
}

2186 2187 2188 2189
fn call_memcpy(@block_ctxt cx,
               ValueRef dst,
               ValueRef src,
               ValueRef n_bytes) -> result {
2190 2191
    auto src_ptr = cx.build.PointerCast(src, T_ptr(T_i8()));
    auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
2192 2193 2194
    auto size = cx.build.IntCast(n_bytes, T_int());
    ret res(cx, cx.build.FastCall(cx.fcx.ccx.glues.memcpy_glue,
                                  vec(dst_ptr, src_ptr, size)));
2195 2196
}

2197 2198 2199 2200 2201 2202 2203 2204 2205
fn call_bzero(@block_ctxt cx,
              ValueRef dst,
              ValueRef n_bytes) -> result {
    auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
    auto size = cx.build.IntCast(n_bytes, T_int());
    ret res(cx, cx.build.FastCall(cx.fcx.ccx.glues.bzero_glue,
                                  vec(dst_ptr, size)));
}

2206 2207 2208 2209 2210 2211
fn memcpy_ty(@block_ctxt cx,
             ValueRef dst,
             ValueRef src,
             @ty.t t) -> result {
    if (ty.type_has_dynamic_size(t)) {
        auto llszptr = field_of_tydesc(cx, t, abi.tydesc_field_size);
2212 2213
        auto llsz = llszptr.bcx.build.Load(llszptr.val);
        ret call_memcpy(llszptr.bcx, dst, src, llsz);
2214 2215 2216 2217 2218 2219

    } else {
        ret res(cx, cx.build.Store(cx.build.Load(src), dst));
    }
}

2220 2221 2222 2223 2224
tag copy_action {
    INIT;
    DROP_EXISTING;
}

2225
fn copy_ty(@block_ctxt cx,
2226
           copy_action action,
2227 2228
           ValueRef dst,
           ValueRef src,
2229
           @ty.t t) -> result {
2230
    if (ty.type_is_scalar(t) || ty.type_is_native(t)) {
2231 2232
        ret res(cx, cx.build.Store(src, dst));

2233
    } else if (ty.type_is_nil(t)) {
2234 2235
        ret res(cx, C_nil());

2236
    } else if (ty.type_is_boxed(t)) {
2237
        auto r = incr_all_refcnts(cx, src, t);
2238
        if (action == DROP_EXISTING) {
2239
            r = drop_ty(r.bcx, r.bcx.build.Load(dst), t);
2240 2241 2242
        }
        ret res(r.bcx, r.bcx.build.Store(src, dst));

2243 2244
    } else if (ty.type_is_structural(t) ||
               ty.type_has_dynamic_size(t)) {
2245
        auto r = incr_all_refcnts(cx, src, t);
2246
        if (action == DROP_EXISTING) {
2247 2248
            r = drop_ty(r.bcx, dst, t);
        }
2249
        ret memcpy_ty(r.bcx, dst, src, t);
2250 2251 2252
    }

    cx.fcx.ccx.sess.bug("unexpected type in trans.copy_ty: " +
2253
                        ty.ty_to_str(t));
2254 2255 2256
    fail;
}

2257
fn trans_lit(@crate_ctxt cx, &ast.lit lit, &ast.ann ann) -> ValueRef {
2258
    alt (lit.node) {
2259
        case (ast.lit_int(?i)) {
2260
            ret C_int(i);
2261 2262
        }
        case (ast.lit_uint(?u)) {
2263
            ret C_int(u as int);
2264
        }
2265 2266 2267 2268 2269 2270
        case (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.
            auto t = T_int();
            alt (tm) {
G
Graydon Hoare 已提交
2271 2272 2273 2274 2275 2276 2277 2278 2279
                case (common.ty_u8) { t = T_i8(); }
                case (common.ty_u16) { t = T_i16(); }
                case (common.ty_u32) { t = T_i32(); }
                case (common.ty_u64) { t = T_i64(); }

                case (common.ty_i8) { t = T_i8(); }
                case (common.ty_i16) { t = T_i16(); }
                case (common.ty_i32) { t = T_i32(); }
                case (common.ty_i64) { t = T_i64(); }
2280
            }
2281
            ret C_integral(i, t);
2282
        }
2283
        case (ast.lit_char(?c)) {
2284
            ret C_integral(c as int, T_char());
2285 2286
        }
        case (ast.lit_bool(?b)) {
2287
            ret C_bool(b);
2288 2289
        }
        case (ast.lit_nil) {
2290
            ret C_nil();
2291 2292
        }
        case (ast.lit_str(?s)) {
2293
            ret C_str(cx, s);
2294 2295 2296 2297
        }
    }
}

2298
fn target_type(@crate_ctxt cx, @ty.t t) -> @ty.t {
2299
    alt (t.struct) {
2300 2301
        case (ty.ty_int) {
            auto tm = ty.ty_machine(cx.sess.get_targ_cfg().int_type);
2302 2303
            ret @rec(struct=tm with *t);
        }
2304 2305
        case (ty.ty_uint) {
            auto tm = ty.ty_machine(cx.sess.get_targ_cfg().uint_type);
2306 2307
            ret @rec(struct=tm with *t);
        }
2308
        case (_) { /* fall through */ }
2309 2310 2311 2312
    }
    ret t;
}

2313
fn node_ann_type(@crate_ctxt cx, &ast.ann a) -> @ty.t {
2314 2315
    alt (a) {
        case (ast.ann_none) {
2316
            cx.sess.bug("missing type annotation");
2317
        }
2318
        case (ast.ann_type(?t, _)) {
2319
            ret target_type(cx, t);
2320 2321 2322 2323
        }
    }
}

2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341
fn node_ann_ty_params(&ast.ann a) -> vec[@ty.t] {
    alt (a) {
        case (ast.ann_none) {
            log "missing type annotation";
            fail;
        }
        case (ast.ann_type(_, ?tps_opt)) {
            alt (tps_opt) {
                case (none[vec[@ty.t]]) {
                    log "type annotation has no ty params";
                    fail;
                }
                case (some[vec[@ty.t]](?tps)) { ret tps; }
            }
        }
    }
}

2342 2343 2344 2345
fn node_type(@crate_ctxt cx, &ast.ann a) -> TypeRef {
    ret type_of(cx, node_ann_type(cx, a));
}

2346 2347
fn trans_unary(@block_ctxt cx, ast.unop op,
               @ast.expr e, &ast.ann a) -> result {
2348 2349 2350

    auto sub = trans_expr(cx, e);

2351 2352
    alt (op) {
        case (ast.bitnot) {
2353
            sub = autoderef(sub.bcx, sub.val, ty.expr_ty(e));
2354
            ret res(sub.bcx, sub.bcx.build.Not(sub.val));
2355 2356
        }
        case (ast.not) {
2357
            sub = autoderef(sub.bcx, sub.val, ty.expr_ty(e));
2358
            ret res(sub.bcx, sub.bcx.build.Not(sub.val));
2359 2360
        }
        case (ast.neg) {
2361
            sub = autoderef(sub.bcx, sub.val, ty.expr_ty(e));
2362
            ret res(sub.bcx, sub.bcx.build.Neg(sub.val));
2363
        }
2364
        case (ast.box) {
2365
            auto e_ty = ty.expr_ty(e);
2366
            auto e_val = sub.val;
2367 2368 2369
            auto box_ty = node_ann_type(sub.bcx.fcx.ccx, a);
            sub = trans_malloc_boxed(sub.bcx, e_ty);
            find_scope_cx(cx).cleanups +=
2370
                vec(clean(bind drop_ty(_, sub.val, box_ty)));
2371

2372 2373
            auto box = sub.val;
            auto rc = sub.bcx.build.GEP(box,
2374 2375
                                        vec(C_int(0),
                                            C_int(abi.box_rc_field_refcnt)));
2376 2377 2378 2379
            auto body = sub.bcx.build.GEP(box,
                                          vec(C_int(0),
                                              C_int(abi.box_rc_field_body)));
            sub.bcx.build.Store(C_int(1), rc);
2380 2381 2382 2383 2384 2385 2386 2387 2388

            // 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.
            if (!ty.type_has_dynamic_size(e_ty)) {
                auto llety = T_ptr(type_of(sub.bcx.fcx.ccx, e_ty));
                body = sub.bcx.build.PointerCast(body, llety);
            }

2389
            sub = copy_ty(sub.bcx, INIT, body, e_val, e_ty);
2390
            ret res(sub.bcx, box);
2391
        }
2392
        case (ast.deref) {
2393 2394 2395
            auto val = sub.bcx.build.GEP(sub.val,
                                         vec(C_int(0),
                                             C_int(abi.box_rc_field_body)));
2396
            auto e_ty = node_ann_type(sub.bcx.fcx.ccx, a);
2397 2398
            if (ty.type_is_scalar(e_ty) ||
                ty.type_is_nil(e_ty)) {
2399
                val = sub.bcx.build.Load(val);
2400
            }
2401
            ret res(sub.bcx, val);
2402
        }
2403 2404 2405 2406
    }
    fail;
}

2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420
fn trans_compare(@block_ctxt cx0, ast.binop op, @ty.t t0,
                 ValueRef lhs0, ValueRef rhs0) -> result {

    auto cx = cx0;

    auto lhs_r = autoderef(cx, lhs0, t0);
    auto lhs = lhs_r.val;
    cx = lhs_r.bcx;

    auto rhs_r = autoderef(cx, rhs0, t0);
    auto rhs = rhs_r.val;
    cx = rhs_r.bcx;

    auto t = autoderefed_ty(t0);
2421 2422 2423 2424

    if (ty.type_is_scalar(t)) {
        ret res(cx, trans_scalar_compare(cx, op, t, lhs, rhs));

2425 2426 2427
    } else if (ty.type_is_structural(t)
               || ty.type_is_sequence(t)) {

2428 2429
        auto scx = new_sub_block_ctxt(cx, "structural compare start");
        auto next = new_sub_block_ctxt(cx, "structural compare end");
2430 2431
        cx.build.Br(scx.llbb);

2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455
        /*
         * We're doing lexicographic comparison here. We start with the
         * assumption that the two input elements are equal. Depending on
         * operator, this means that the result is either true or false;
         * equality produces 'true' for ==, <= and >=. It produces 'false' for
         * !=, < and >.
         *
         * We then move one element at a time through the structure checking
         * for pairwise element equality. If we have equality, our assumption
         * about overall sequence equality is not modified, so we have to move
         * to the next element.
         *
         * If we do not have pairwise element equality, we have reached an
         * element that 'decides' the lexicographic comparison. So we exit the
         * loop with a flag that indicates the true/false sense of that
         * decision, by testing the element again with the operator we're
         * interested in.
         *
         * When we're lucky, LLVM should be able to fold some of these two
         * tests together (as they're applied to the same operands and in some
         * cases are sometimes redundant). But we don't bother trying to
         * optimize combinations like that, at this level.
         */

2456 2457
        auto flag = scx.build.Alloca(T_i1());

2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481
        if (ty.type_is_sequence(t)) {

            // If we hit == all the way through the minimum-shared-length
            // section, default to judging the relative sequence lengths.
            auto len_cmp =
                trans_integral_compare(scx, op, plain_ty(ty.ty_uint),
                                       vec_fill(scx, lhs),
                                       vec_fill(scx, rhs));
            scx.build.Store(len_cmp, flag);

        } else {
            auto T = C_integral(1, T_i1());
            auto F = C_integral(0, T_i1());

            alt (op) {
                // ==, <= and >= default to true if they find == all the way.
                case (ast.eq) { scx.build.Store(T, flag); }
                case (ast.le) { scx.build.Store(T, flag); }
                case (ast.ge) { scx.build.Store(T, flag); }
                case (_) {
                    // < > default to false if they find == all the way.
                    scx.build.Store(F, flag);
                }

2482 2483
            }
        }
2484

2485
        fn inner(@block_ctxt last_cx,
2486
                 bool load_inner,
2487 2488 2489
                 ValueRef flag,
                 ast.binop op,
                 @block_ctxt cx,
2490 2491
                 ValueRef av0,
                 ValueRef bv0,
2492
                 @ty.t t) -> result {
2493

2494 2495 2496
            auto cnt_cx = new_sub_block_ctxt(cx, "continue comparison");
            auto stop_cx = new_sub_block_ctxt(cx, "stop comparison");

2497 2498 2499 2500 2501 2502 2503
            auto av = av0;
            auto bv = bv0;
            if (load_inner) {
                av = load_scalar_or_boxed(cx, av, t);
                bv = load_scalar_or_boxed(cx, bv, t);
            }

2504 2505 2506
            // First 'eq' comparison: if so, continue to next elts.
            auto eq_r = trans_compare(cx, ast.eq, t, av, bv);
            eq_r.bcx.build.CondBr(eq_r.val, cnt_cx.llbb, stop_cx.llbb);
2507

2508 2509 2510 2511
            // Second 'op' comparison: find out how this elt-pair decides.
            auto stop_r = trans_compare(stop_cx, op, t, av, bv);
            stop_r.bcx.build.Store(stop_r.val, flag);
            stop_r.bcx.build.Br(last_cx.llbb);
2512 2513 2514
            ret res(cnt_cx, C_nil());
        }

2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532
        auto r;
        if (ty.type_is_structural(t)) {
            r = iter_structural_ty_full(scx, lhs, rhs, t,
                                        bind inner(next, false, flag, op,
                                                   _, _, _, _));
        } else {
            auto lhs_p0 = vec_p0(scx, lhs);
            auto rhs_p0 = vec_p0(scx, rhs);
            auto min_len = umin(scx, vec_fill(scx, lhs), vec_fill(scx, rhs));
            auto rhs_lim = scx.build.GEP(rhs_p0, vec(min_len));
            auto elt_ty = ty.sequence_element_type(t);
            auto elt_llsz_r = size_of(scx, elt_ty);
            scx = elt_llsz_r.bcx;
            r = iter_sequence_raw(scx, lhs, rhs, rhs_lim,
                                  elt_llsz_r.val,
                                  bind inner(next, true, flag, op,
                                             _, _, _, elt_ty));
        }
2533

2534 2535
        r.bcx.build.Br(next.llbb);
        auto v = next.build.Load(flag);
2536 2537
        ret res(next, v);

2538

2539
    } else {
2540
        // FIXME: compare obj, fn by pointer?
2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556
        cx.fcx.ccx.sess.unimpl("type in trans_compare");
        ret res(cx, C_bool(false));
    }
}

fn trans_scalar_compare(@block_ctxt cx, ast.binop op, @ty.t t,
                        ValueRef lhs, ValueRef rhs) -> ValueRef {
    if (ty.type_is_fp(t)) {
        ret trans_fp_compare(cx, op, t, lhs, rhs);
    } else {
        ret trans_integral_compare(cx, op, t, lhs, rhs);
    }
}

fn trans_fp_compare(@block_ctxt cx, ast.binop op, @ty.t fptype,
                    ValueRef lhs, ValueRef rhs) -> ValueRef {
2557

2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574
    auto cmp = lib.llvm.LLVMIntEQ;
    alt (op) {
        // FIXME: possibly use the unordered-or-< predicates here,
        // for now we're only going with ordered-and-< style (no NaNs).
        case (ast.eq) { cmp = lib.llvm.LLVMRealOEQ; }
        case (ast.ne) { cmp = lib.llvm.LLVMRealONE; }
        case (ast.lt) { cmp = lib.llvm.LLVMRealOLT; }
        case (ast.gt) { cmp = lib.llvm.LLVMRealOGT; }
        case (ast.le) { cmp = lib.llvm.LLVMRealOLE; }
        case (ast.ge) { cmp = lib.llvm.LLVMRealOGE; }
    }

    ret cx.build.FCmp(cmp, lhs, rhs);
}

fn trans_integral_compare(@block_ctxt cx, ast.binop op, @ty.t intype,
                          ValueRef lhs, ValueRef rhs) -> ValueRef {
2575 2576 2577 2578 2579
    auto cmp = lib.llvm.LLVMIntEQ;
    alt (op) {
        case (ast.eq) { cmp = lib.llvm.LLVMIntEQ; }
        case (ast.ne) { cmp = lib.llvm.LLVMIntNE; }

2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607
        case (ast.lt) {
            if (ty.type_is_signed(intype)) {
                cmp = lib.llvm.LLVMIntSLT;
            } else {
                cmp = lib.llvm.LLVMIntULT;
            }
        }
        case (ast.le) {
            if (ty.type_is_signed(intype)) {
                cmp = lib.llvm.LLVMIntSLE;
            } else {
                cmp = lib.llvm.LLVMIntULE;
            }
        }
        case (ast.gt) {
            if (ty.type_is_signed(intype)) {
                cmp = lib.llvm.LLVMIntSGT;
            } else {
                cmp = lib.llvm.LLVMIntUGT;
            }
        }
        case (ast.ge) {
            if (ty.type_is_signed(intype)) {
                cmp = lib.llvm.LLVMIntSGE;
            } else {
                cmp = lib.llvm.LLVMIntUGE;
            }
        }
2608 2609 2610 2611
    }
    ret cx.build.ICmp(cmp, lhs, rhs);
}

2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630
fn trans_vec_append(@block_ctxt cx, @ty.t t,
                    ValueRef lhs, ValueRef rhs) -> result {

    auto elt_ty = ty.sequence_element_type(t);

    auto skip_null = C_bool(false);
    alt (t.struct) {
        case (ty.ty_str) { skip_null = C_bool(true); }
        case (_) { }
    }

    auto bcx = cx;

    auto llvec_tydesc = get_tydesc(bcx, t);
    bcx = llvec_tydesc.bcx;

    auto llelt_tydesc = get_tydesc(bcx, elt_ty);
    bcx = llelt_tydesc.bcx;

2631 2632 2633 2634 2635 2636 2637 2638
    auto dst = bcx.build.PointerCast(lhs, T_ptr(T_opaque_vec_ptr()));
    auto src = bcx.build.PointerCast(rhs, T_opaque_vec_ptr());

    ret res(bcx, bcx.build.FastCall(cx.fcx.ccx.glues.vec_append_glue,
                                    vec(cx.fcx.lltaskptr,
                                        llvec_tydesc.val,
                                        llelt_tydesc.val,
                                        dst, src, skip_null)));
2639 2640
}

2641 2642
fn trans_vec_add(@block_ctxt cx, @ty.t t,
                 ValueRef lhs, ValueRef rhs) -> result {
2643
    auto r = alloc_ty(cx, t);
2644 2645
    auto tmp = r.val;
    r = copy_ty(r.bcx, INIT, tmp, lhs, t);
2646
    auto bcx = trans_vec_append(r.bcx, t, tmp, rhs).bcx;
2647
    tmp = load_scalar_or_boxed(bcx, tmp, t);
2648 2649
    find_scope_cx(cx).cleanups +=
        vec(clean(bind drop_ty(_, tmp, t)));
2650
    ret res(bcx, tmp);
2651 2652 2653
}


2654
fn trans_eager_binop(@block_ctxt cx, ast.binop op, @ty.t intype,
2655
                     ValueRef lhs, ValueRef rhs) -> result {
2656 2657

    alt (op) {
2658 2659
        case (ast.add) {
            if (ty.type_is_sequence(intype)) {
2660
                ret trans_vec_add(cx, intype, lhs, rhs);
2661 2662 2663
            }
            ret res(cx, cx.build.Add(lhs, rhs));
        }
2664
        case (ast.sub) { ret res(cx, cx.build.Sub(lhs, rhs)); }
2665

2666
        case (ast.mul) { ret res(cx, cx.build.Mul(lhs, rhs)); }
2667 2668
        case (ast.div) {
            if (ty.type_is_signed(intype)) {
2669
                ret res(cx, cx.build.SDiv(lhs, rhs));
2670
            } else {
2671
                ret res(cx, cx.build.UDiv(lhs, rhs));
2672 2673 2674 2675
            }
        }
        case (ast.rem) {
            if (ty.type_is_signed(intype)) {
2676
                ret res(cx, cx.build.SRem(lhs, rhs));
2677
            } else {
2678
                ret res(cx, cx.build.URem(lhs, rhs));
2679 2680
            }
        }
2681

2682 2683 2684 2685 2686 2687
        case (ast.bitor) { ret res(cx, cx.build.Or(lhs, rhs)); }
        case (ast.bitand) { ret res(cx, cx.build.And(lhs, rhs)); }
        case (ast.bitxor) { ret res(cx, cx.build.Xor(lhs, rhs)); }
        case (ast.lsl) { ret res(cx, cx.build.Shl(lhs, rhs)); }
        case (ast.lsr) { ret res(cx, cx.build.LShr(lhs, rhs)); }
        case (ast.asr) { ret res(cx, cx.build.AShr(lhs, rhs)); }
2688
        case (_) {
2689
            ret trans_compare(cx, op, intype, lhs, rhs);
2690 2691 2692 2693 2694
        }
    }
    fail;
}

2695 2696 2697 2698 2699 2700
fn autoderef(@block_ctxt cx, ValueRef v, @ty.t t) -> result {
    let ValueRef v1 = v;
    let @ty.t t1 = t;

    while (true) {
        alt (t1.struct) {
2701
            case (ty.ty_box(?mt)) {
2702 2703 2704
                auto body = cx.build.GEP(v1,
                                         vec(C_int(0),
                                             C_int(abi.box_rc_field_body)));
2705 2706
                t1 = mt.ty;
                v1 = load_scalar_or_boxed(cx, body, t1);
2707 2708 2709 2710 2711 2712 2713 2714
            }
            case (_) {
                ret res(cx, v1);
            }
        }
    }
}

2715 2716 2717 2718 2719
fn autoderefed_ty(@ty.t t) -> @ty.t {
    let @ty.t t1 = t;

    while (true) {
        alt (t1.struct) {
2720 2721
            case (ty.ty_box(?mt)) {
                t1 = mt.ty;
2722 2723 2724 2725 2726 2727 2728 2729
            }
            case (_) {
                ret t1;
            }
        }
    }
}

2730 2731
fn trans_binary(@block_ctxt cx, ast.binop op,
                @ast.expr a, @ast.expr b) -> result {
2732

2733 2734 2735 2736 2737 2738
    // First couple cases are lazy:

    alt (op) {
        case (ast.and) {
            // Lazy-eval and
            auto lhs_res = trans_expr(cx, a);
2739
            lhs_res = autoderef(lhs_res.bcx, lhs_res.val, ty.expr_ty(a));
2740

2741
            auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
2742
            auto rhs_res = trans_expr(rhs_cx, b);
2743
            rhs_res = autoderef(rhs_res.bcx, rhs_res.val, ty.expr_ty(b));
2744

2745
            auto lhs_false_cx = new_scope_block_ctxt(cx, "lhs false");
2746
            auto lhs_false_res = res(lhs_false_cx, C_bool(false));
2747 2748 2749

            lhs_res.bcx.build.CondBr(lhs_res.val,
                                     rhs_cx.llbb,
2750 2751 2752 2753
                                     lhs_false_cx.llbb);

            ret join_results(cx, T_bool(),
                             vec(lhs_false_res, rhs_res));
2754 2755 2756 2757 2758
        }

        case (ast.or) {
            // Lazy-eval or
            auto lhs_res = trans_expr(cx, a);
2759
            lhs_res = autoderef(lhs_res.bcx, lhs_res.val, ty.expr_ty(a));
2760

2761
            auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
2762
            auto rhs_res = trans_expr(rhs_cx, b);
2763
            rhs_res = autoderef(rhs_res.bcx, rhs_res.val, ty.expr_ty(b));
2764

2765
            auto lhs_true_cx = new_scope_block_ctxt(cx, "lhs true");
2766
            auto lhs_true_res = res(lhs_true_cx, C_bool(true));
2767 2768

            lhs_res.bcx.build.CondBr(lhs_res.val,
2769
                                     lhs_true_cx.llbb,
2770
                                     rhs_cx.llbb);
2771 2772 2773

            ret join_results(cx, T_bool(),
                             vec(lhs_true_res, rhs_res));
2774
        }
2775 2776

        case (_) {
2777 2778
            // Remaining cases are eager:
            auto lhs = trans_expr(cx, a);
2779 2780
            auto lhty = ty.expr_ty(a);
            lhs = autoderef(lhs.bcx, lhs.val, lhty);
2781
            auto rhs = trans_expr(lhs.bcx, b);
2782 2783
            auto rhty = ty.expr_ty(b);
            rhs = autoderef(rhs.bcx, rhs.val, rhty);
2784 2785 2786
            ret trans_eager_binop(rhs.bcx, op,
                                  autoderefed_ty(lhty),
                                  lhs.val, rhs.val);
2787
        }
2788 2789 2790 2791
    }
    fail;
}

2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802
fn join_results(@block_ctxt parent_cx,
                TypeRef t,
                vec[result] ins)
    -> result {

    let vec[result] live = vec();
    let vec[ValueRef] vals = vec();
    let vec[BasicBlockRef] bbs = vec();

    for (result r in ins) {
        if (! is_terminated(r.bcx)) {
2803 2804 2805
            live += vec(r);
            vals += vec(r.val);
            bbs += vec(r.bcx.llbb);
2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822
        }
    }

    alt (_vec.len[result](live)) {
        case (0u) {
            // No incoming edges are live, so we're in dead-code-land.
            // Arbitrarily pick the first dead edge, since the caller
            // is just going to propagate it outward.
            check (_vec.len[result](ins) >= 1u);
            ret ins.(0);
        }

        case (1u) {
            // Only one incoming edge is live, so we just feed that block
            // onward.
            ret live.(0);
        }
2823 2824

        case (_) { /* fall through */ }
2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835
    }

    // We have >1 incoming edges. Make a join block and br+phi them into it.
    auto join_cx = new_sub_block_ctxt(parent_cx, "join");
    for (result r in live) {
        r.bcx.build.Br(join_cx.llbb);
    }
    auto phi = join_cx.build.Phi(t, vals, bbs);
    ret res(join_cx, phi);
}

2836
fn trans_if(@block_ctxt cx, @ast.expr cond,
2837
            &ast.block thn, &option.t[@ast.expr] els) -> result {
2838 2839 2840

    auto cond_res = trans_expr(cx, cond);

2841
    auto then_cx = new_scope_block_ctxt(cx, "then");
2842 2843
    auto then_res = trans_block(then_cx, thn);

2844
    auto else_cx = new_scope_block_ctxt(cx, "else");
2845
    auto else_res = res(else_cx, C_nil());
2846 2847

    alt (els) {
2848
        case (some[@ast.expr](?elexpr)) {
2849
            else_res = trans_expr(else_cx, elexpr);
2850
        }
2851
        case (_) { /* fall through */ }
2852 2853
    }

2854
    cond_res.bcx.build.CondBr(cond_res.val,
2855 2856
                              then_cx.llbb,
                              else_cx.llbb);
2857 2858 2859 2860

    // FIXME: use inferred type when available.
    ret join_results(cx, T_nil(),
                     vec(then_res, else_res));
2861 2862
}

G
Graydon Hoare 已提交
2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876
fn trans_for(@block_ctxt cx,
             @ast.decl decl,
             @ast.expr seq,
             &ast.block body) -> result {

    fn inner(@block_ctxt cx,
             @ast.local local, ValueRef curr,
             @ty.t t, ast.block body) -> result {

        auto scope_cx = new_scope_block_ctxt(cx, "for loop scope");
        auto next_cx = new_sub_block_ctxt(cx, "next");

        cx.build.Br(scope_cx.llbb);
        auto local_res = alloc_local(scope_cx, local);
2877
        auto bcx = copy_ty(local_res.bcx, INIT, local_res.val, curr, t).bcx;
2878 2879
        scope_cx.cleanups +=
            vec(clean(bind drop_slot(_, local_res.val, t)));
2880
        bcx = trans_block(bcx, body).bcx;
G
Graydon Hoare 已提交
2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898
        bcx.build.Br(next_cx.llbb);
        ret res(next_cx, C_nil());
    }


    let @ast.local local;
    alt (decl.node) {
        case (ast.decl_local(?loc)) {
            local = loc;
        }
    }

    auto seq_ty = ty.expr_ty(seq);
    auto seq_res = trans_expr(cx, seq);
    ret iter_sequence(seq_res.bcx, seq_res.val, seq_ty,
                      bind inner(_, local, _, _, body));
}

2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954

// Iterator translation

// Searches through a block for all references to locals or upvars in this
// frame and returns the list of definition IDs thus found.
fn collect_upvars(@block_ctxt cx, &ast.block bloc, &ast.def_id initial_decl)
        -> vec[ast.def_id] {
    type env = @rec(
        mutable vec[ast.def_id] refs,
        hashmap[ast.def_id,()] decls
    );

    fn fold_expr_path(&env e, &common.span sp, &ast.path p,
                      &option.t[ast.def] d, ast.ann a) -> @ast.expr {
        alt (option.get[ast.def](d)) {
            case (ast.def_arg(?did))    { e.refs += vec(did);   }
            case (ast.def_local(?did))  { e.refs += vec(did);   }
            case (ast.def_upvar(?did))  { e.refs += vec(did);   }
            case (_)                    { /* ignore */          }
        }

        ret @fold.respan[ast.expr_](sp, ast.expr_path(p, d, a));
    }

    fn fold_decl_local(&env e, &common.span sp, @ast.local local)
            -> @ast.decl {
        e.decls.insert(local.id, ());
        ret @fold.respan[ast.decl_](sp, ast.decl_local(local));
    }

    auto fep = fold_expr_path;
    auto fdl = fold_decl_local;
    auto fld = @rec(
        fold_expr_path=fep,
        fold_decl_local=fdl
        with *fold.new_identity_fold[env]()
    );

    let vec[ast.def_id] refs = vec();
    let hashmap[ast.def_id,()] decls = new_def_hash[()]();
    decls.insert(initial_decl, ());
    let env e = @rec(mutable refs=refs, decls=decls);

    fold.fold_block[env](e, fld, bloc);

    // Calculate (refs - decls). This is the set of captured upvars.
    let vec[ast.def_id] result = vec();
    for (ast.def_id ref_id in e.refs) {
        if (!decls.contains_key(ref_id)) {
            result += vec(ref_id);
        }
    }

    ret result;
}

2955 2956 2957 2958
fn trans_for_each(@block_ctxt cx,
                  @ast.decl decl,
                  @ast.expr seq,
                  &ast.block body) -> result {
2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987

    /*
     * The translation is a little .. complex here. Code like:
     *
     *    let ty1 p = ...;
     *
     *    let ty1 q = ...;
     *
     *    foreach (ty v in foo(a,b)) { body(p,q,v) }
     *
     *
     * Turns into a something like so (C/Rust mishmash):
     *
     *    type env = { *ty1 p, *ty2 q, ... };
     *
     *    let env e = { &p, &q, ... };
     *
     *    fn foreach123_body(env* e, ty v) { body(*(e->p),*(e->q),v) }
     *
     *    foo([foreach123_body, env*], a, b);
     *
     */

    // Step 1: walk body and figure out which references it makes
    // escape. This could be determined upstream, and probably ought
    // to be so, eventualy. For first cut, skip this. Null env.

    // FIXME: possibly support alias-mode here?
    auto decl_ty = plain_ty(ty.ty_nil);
2988
    auto decl_id;
2989 2990 2991
    alt (decl.node) {
        case (ast.decl_local(?local)) {
            decl_ty = node_ann_type(cx.fcx.ccx, local.ann);
2992
            decl_id = local.id;
2993 2994 2995
        }
    }

2996
    auto upvars = collect_upvars(cx, body, decl_id);
2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007
    auto upvar_count = _vec.len[ast.def_id](upvars);

    auto llbindingsptr;
    if (upvar_count > 0u) {
        // Gather up the upvars.
        let vec[ValueRef] llbindings = vec();
        let vec[TypeRef] llbindingtys = vec();
        for (ast.def_id did in upvars) {
            auto llbinding;
            alt (cx.fcx.lllocals.find(did)) {
                case (none[ValueRef]) {
3008 3009 3010 3011 3012 3013
                    alt (cx.fcx.llupvars.find(did)) {
                        case (none[ValueRef]) {
                            llbinding = cx.fcx.llargs.get(did);
                        }
                        case (some[ValueRef](?llval)) { llbinding = llval; }
                    }
3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032
                }
                case (some[ValueRef](?llval)) { llbinding = llval; }
            }
            llbindings += vec(llbinding);
            llbindingtys += vec(val_ty(llbinding));
        }

        // Create an array of bindings and copy in aliases to the upvars.
        llbindingsptr = cx.build.Alloca(T_struct(llbindingtys));
        auto i = 0u;
        while (i < upvar_count) {
            auto llbindingptr = cx.build.GEP(llbindingsptr,
                                             vec(C_int(0), C_int(i as int)));
            cx.build.Store(llbindings.(i), llbindingptr);
            i += 1u;
        }
    } else {
        // Null bindings.
        llbindingsptr = C_null(T_ptr(T_i8()));
3033 3034
    }

3035 3036 3037 3038 3039 3040 3041 3042 3043 3044
    // Create an environment and populate it with the bindings.
    auto llenvptrty = T_closure_ptr(cx.fcx.ccx.tn, T_ptr(T_nil()),
                                    val_ty(llbindingsptr), 0u);
    auto llenvptr = cx.build.Alloca(llvm.LLVMGetElementType(llenvptrty));

    auto llbindingsptrptr = cx.build.GEP(llenvptr,
                                         vec(C_int(0),
                                             C_int(abi.box_rc_field_body),
                                             C_int(2)));
    cx.build.Store(llbindingsptr, llbindingsptrptr);
3045 3046 3047

    // Step 2: Declare foreach body function.

3048 3049 3050 3051 3052 3053 3054 3055 3056 3057
    let str s =
        cx.fcx.ccx.names.next("_rust_foreach")
        + sep() + cx.fcx.ccx.path;

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

3058 3059 3060
    auto iter_body_llty = type_of_fn_full(cx.fcx.ccx, ast.proto_fn,
                                          none[TypeRef],
                                          vec(rec(mode=ast.val, ty=decl_ty)),
3061
                                          plain_ty(ty.ty_nil), 0u);
3062

3063 3064
    let ValueRef lliterbody = decl_fastcall_fn(cx.fcx.ccx.llmod,
                                               s, iter_body_llty);
3065 3066 3067 3068

    // FIXME: handle ty params properly.
    let vec[ast.ty_param] ty_params = vec();

3069
    auto fcx = new_fn_ctxt(cx.fcx.ccx, lliterbody);
3070 3071
    auto bcx = new_top_block_ctxt(fcx);

3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095
    // Populate the upvars from the environment.
    auto llremoteenvptr = bcx.build.PointerCast(fcx.llenv, llenvptrty);
    auto llremotebindingsptrptr = bcx.build.GEP(llremoteenvptr,
        vec(C_int(0), C_int(abi.box_rc_field_body), C_int(2)));
    auto llremotebindingsptr = bcx.build.Load(llremotebindingsptrptr);

    auto i = 0u;
    while (i < upvar_count) {
        auto upvar_id = upvars.(i);
        auto llupvarptrptr = bcx.build.GEP(llremotebindingsptr,
                                           vec(C_int(0), C_int(i as int)));
        auto llupvarptr = bcx.build.Load(llupvarptrptr);
        fcx.llupvars.insert(upvar_id, llupvarptr);

        i += 1u;
    }

    // Treat the loop variable as an upvar as well. We copy it to an alloca
    // as usual.
    auto lllvar = llvm.LLVMGetParam(fcx.llfn, 3u);
    auto lllvarptr = bcx.build.Alloca(val_ty(lllvar));
    bcx.build.Store(lllvar, lllvarptr);
    fcx.llupvars.insert(decl_id, lllvarptr);

3096 3097 3098 3099
    auto res = trans_block(bcx, body);
    res.bcx.build.RetVoid();


3100
    // Step 3: Call iter passing [lliterbody, llenv], plus other args.
3101 3102

    alt (seq.node) {
3103

3104
        case (ast.expr_call(?f, ?args, ?ann)) {
3105

3106 3107 3108 3109 3110 3111 3112
            auto pair = cx.build.Alloca(T_fn_pair(cx.fcx.ccx.tn,
                                                  iter_body_llty));
            auto code_cell = cx.build.GEP(pair,
                                          vec(C_int(0),
                                              C_int(abi.fn_field_code)));
            cx.build.Store(lliterbody, code_cell);

3113 3114 3115 3116 3117 3118
            auto env_cell = cx.build.GEP(pair, vec(C_int(0),
                                                   C_int(abi.fn_field_box)));
            auto llenvblobptr = cx.build.PointerCast(llenvptr,
                T_opaque_closure_ptr(cx.fcx.ccx.tn));
            cx.build.Store(llenvblobptr, env_cell);

3119 3120
            // log "lliterbody: " + val_str(cx.fcx.ccx.tn, lliterbody);
            ret trans_call(cx, f,
3121
                           some[ValueRef](cx.build.Load(pair)),
3122 3123
                           args,
                           ann);
3124 3125
        }
    }
3126 3127 3128 3129
    fail;
}


3130 3131
fn trans_while(@block_ctxt cx, @ast.expr cond,
               &ast.block body) -> result {
3132

3133 3134
    auto cond_cx = new_scope_block_ctxt(cx, "while cond");
    auto body_cx = new_scope_block_ctxt(cx, "while loop body");
3135
    auto next_cx = new_sub_block_ctxt(cx, "next");
3136 3137

    auto body_res = trans_block(body_cx, body);
3138 3139 3140
    auto cond_res = trans_expr(cond_cx, cond);

    body_res.bcx.build.Br(cond_cx.llbb);
3141 3142 3143

    auto cond_bcx = trans_block_cleanups(cond_res.bcx, cond_cx);
    cond_bcx.build.CondBr(cond_res.val, body_cx.llbb, next_cx.llbb);
3144 3145

    cx.build.Br(cond_cx.llbb);
3146 3147 3148
    ret res(next_cx, C_nil());
}

3149 3150
fn trans_do_while(@block_ctxt cx, &ast.block body,
                  @ast.expr cond) -> result {
3151

3152
    auto body_cx = new_scope_block_ctxt(cx, "do-while loop body");
3153
    auto next_cx = new_sub_block_ctxt(cx, "next");
3154 3155

    auto body_res = trans_block(body_cx, body);
3156 3157 3158 3159 3160 3161
    auto cond_res = trans_expr(body_res.bcx, cond);

    cond_res.bcx.build.CondBr(cond_res.val,
                              body_cx.llbb,
                              next_cx.llbb);
    cx.build.Br(body_cx.llbb);
3162 3163 3164
    ret res(next_cx, body_res.val);
}

P
Patrick Walton 已提交
3165 3166
// Pattern matching translation

3167 3168
fn trans_pat_match(@block_ctxt cx, @ast.pat pat, ValueRef llval,
                   @block_ctxt next_cx) -> result {
P
Patrick Walton 已提交
3169 3170 3171
    alt (pat.node) {
        case (ast.pat_wild(_)) { ret res(cx, llval); }
        case (ast.pat_bind(_, _, _)) { ret res(cx, llval); }
3172 3173 3174

        case (ast.pat_lit(?lt, ?ann)) {
            auto lllit = trans_lit(cx.fcx.ccx, *lt, ann);
3175 3176
            auto lltype = ty.ann_to_type(ann);
            auto lleq = trans_compare(cx, ast.eq, lltype, llval, lllit);
3177

3178 3179
            auto matched_cx = new_sub_block_ctxt(lleq.bcx, "matched_cx");
            lleq.bcx.build.CondBr(lleq.val, matched_cx.llbb, next_cx.llbb);
3180 3181 3182
            ret res(matched_cx, llval);
        }

P
Patrick Walton 已提交
3183
        case (ast.pat_tag(?id, ?subpats, ?vdef_opt, ?ann)) {
3184 3185 3186 3187 3188
            auto lltagptr = cx.build.PointerCast(llval,
                T_opaque_tag_ptr(cx.fcx.ccx.tn));

            auto lldiscrimptr = cx.build.GEP(lltagptr,
                                             vec(C_int(0), C_int(0)));
3189
            auto lldiscrim = cx.build.Load(lldiscrimptr);
3190

P
Patrick Walton 已提交
3191 3192 3193
            auto vdef = option.get[ast.variant_def](vdef_opt);
            auto variant_id = vdef._1;
            auto variant_tag = 0;
3194 3195

            auto variants = tag_variants(cx.fcx.ccx, vdef._0);
P
Patrick Walton 已提交
3196
            auto i = 0;
3197 3198
            for (ast.variant v in variants) {
                auto this_variant_id = v.id;
P
Patrick Walton 已提交
3199
                if (variant_id._0 == this_variant_id._0 &&
G
Graydon Hoare 已提交
3200
                    variant_id._1 == this_variant_id._1) {
P
Patrick Walton 已提交
3201 3202 3203 3204 3205 3206 3207
                    variant_tag = i;
                }
                i += 1;
            }

            auto matched_cx = new_sub_block_ctxt(cx, "matched_cx");

3208
            auto lleq = cx.build.ICmp(lib.llvm.LLVMIntEQ, lldiscrim,
P
Patrick Walton 已提交
3209 3210 3211
                                      C_int(variant_tag));
            cx.build.CondBr(lleq, matched_cx.llbb, next_cx.llbb);

3212 3213
            auto ty_params = node_ann_ty_params(ann);

P
Patrick Walton 已提交
3214
            if (_vec.len[@ast.pat](subpats) > 0u) {
3215 3216
                auto llblobptr = matched_cx.build.GEP(lltagptr,
                    vec(C_int(0), C_int(1)));
P
Patrick Walton 已提交
3217 3218
                auto i = 0;
                for (@ast.pat subpat in subpats) {
3219 3220
                    auto rslt = GEP_tag(matched_cx, llblobptr, vdef._0,
                                        vdef._1, ty_params, i);
3221 3222 3223
                    auto llsubvalptr = rslt.val;
                    matched_cx = rslt.bcx;

3224
                    auto llsubval = load_scalar_or_boxed(matched_cx,
G
Graydon Hoare 已提交
3225 3226
                                                         llsubvalptr,
                                                         pat_ty(subpat));
P
Patrick Walton 已提交
3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239
                    auto subpat_res = trans_pat_match(matched_cx, subpat,
                                                      llsubval, next_cx);
                    matched_cx = subpat_res.bcx;
                }
            }

            ret res(matched_cx, llval);
        }
    }

    fail;
}

3240 3241
fn trans_pat_binding(@block_ctxt cx, @ast.pat pat, ValueRef llval)
    -> result {
P
Patrick Walton 已提交
3242 3243
    alt (pat.node) {
        case (ast.pat_wild(_)) { ret res(cx, llval); }
3244
        case (ast.pat_lit(_, _)) { ret res(cx, llval); }
P
Patrick Walton 已提交
3245 3246 3247
        case (ast.pat_bind(?id, ?def_id, ?ann)) {
            auto ty = node_ann_type(cx.fcx.ccx, ann);

3248 3249 3250 3251
            auto rslt = alloc_ty(cx, ty);
            auto dst = rslt.val;
            auto bcx = rslt.bcx;

P
Patrick Walton 已提交
3252
            llvm.LLVMSetValueName(dst, _str.buf(id));
3253
            bcx.fcx.lllocals.insert(def_id, dst);
3254 3255
            bcx.cleanups +=
                vec(clean(bind drop_slot(_, dst, ty)));
P
Patrick Walton 已提交
3256

3257
            ret copy_ty(bcx, INIT, dst, llval, ty);
P
Patrick Walton 已提交
3258
        }
3259
        case (ast.pat_tag(_, ?subpats, ?vdef_opt, ?ann)) {
P
Patrick Walton 已提交
3260 3261
            if (_vec.len[@ast.pat](subpats) == 0u) { ret res(cx, llval); }

3262 3263 3264 3265 3266 3267 3268
            // Get the appropriate variant for this tag.
            auto vdef = option.get[ast.variant_def](vdef_opt);
            auto variant = tag_variant_with_id(cx.fcx.ccx, vdef._0, vdef._1);

            auto lltagptr = cx.build.PointerCast(llval,
                T_opaque_tag_ptr(cx.fcx.ccx.tn));
            auto llblobptr = cx.build.GEP(lltagptr, vec(C_int(0), C_int(1)));
P
Patrick Walton 已提交
3269

3270 3271
            auto ty_param_substs = node_ann_ty_params(ann);

P
Patrick Walton 已提交
3272 3273 3274
            auto this_cx = cx;
            auto i = 0;
            for (@ast.pat subpat in subpats) {
3275 3276
                auto rslt = GEP_tag(this_cx, llblobptr, vdef._0, vdef._1,
                                    ty_param_substs, i);
3277 3278 3279
                this_cx = rslt.bcx;
                auto llsubvalptr = rslt.val;

3280
                auto llsubval = load_scalar_or_boxed(this_cx, llsubvalptr,
G
Graydon Hoare 已提交
3281
                                                     pat_ty(subpat));
P
Patrick Walton 已提交
3282 3283 3284
                auto subpat_res = trans_pat_binding(this_cx, subpat,
                                                    llsubval);
                this_cx = subpat_res.bcx;
3285
                i += 1;
P
Patrick Walton 已提交
3286 3287 3288 3289 3290 3291 3292
            }

            ret res(this_cx, llval);
        }
    }
}

3293 3294
fn trans_alt(@block_ctxt cx, @ast.expr expr, vec[ast.arm] arms)
    -> result {
P
Patrick Walton 已提交
3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327
    auto expr_res = trans_expr(cx, expr);

    auto last_cx = new_sub_block_ctxt(expr_res.bcx, "last");

    auto this_cx = expr_res.bcx;
    for (ast.arm arm in arms) {
        auto next_cx = new_sub_block_ctxt(expr_res.bcx, "next");
        auto match_res = trans_pat_match(this_cx, arm.pat, expr_res.val,
                                         next_cx);

        auto binding_cx = new_scope_block_ctxt(match_res.bcx, "binding");
        match_res.bcx.build.Br(binding_cx.llbb);

        auto binding_res = trans_pat_binding(binding_cx, arm.pat,
                                             expr_res.val);

        auto block_res = trans_block(binding_res.bcx, arm.block);
        if (!is_terminated(block_res.bcx)) {
            block_res.bcx.build.Br(last_cx.llbb);
        }

        this_cx = next_cx;
    }

    // FIXME: This is executed when none of the patterns match; it should fail
    // instead!
    this_cx.build.Br(last_cx.llbb);

    // FIXME: This is very wrong; we should phi together all the arm blocks,
    // since this is an expression.
    ret res(last_cx, C_nil());
}

3328
type generic_info = rec(@ty.t item_type,
3329 3330
                        vec[ValueRef] tydescs);

3331 3332
type lval_result = rec(result res,
                       bool is_mem,
3333
                       option.t[generic_info] generic,
3334 3335 3336 3337 3338
                       option.t[ValueRef] llobj);

fn lval_mem(@block_ctxt cx, ValueRef val) -> lval_result {
    ret rec(res=res(cx, val),
            is_mem=true,
3339
            generic=none[generic_info],
3340 3341 3342 3343 3344 3345
            llobj=none[ValueRef]);
}

fn lval_val(@block_ctxt cx, ValueRef val) -> lval_result {
    ret rec(res=res(cx, val),
            is_mem=false,
3346
            generic=none[generic_info],
3347 3348
            llobj=none[ValueRef]);
}
3349

3350 3351 3352 3353 3354 3355 3356 3357
fn lval_generic_fn(@block_ctxt cx,
                   ty.ty_params_and_ty tpt,
                   ast.def_id fn_id,
                   &ast.ann ann)
    -> lval_result {

    check (cx.fcx.ccx.fn_pairs.contains_key(fn_id));
    auto lv = lval_val(cx, cx.fcx.ccx.fn_pairs.get(fn_id));
3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370

    auto monoty;
    auto tys;
    alt (ann) {
        case (ast.ann_none) {
            cx.fcx.ccx.sess.bug("no type annotation for path!");
            fail;
        }
        case (ast.ann_type(?monoty_, ?tps)) {
            monoty = monoty_;
            tys = option.get[vec[@ty.t]](tps);
        }
    }
3371 3372 3373 3374 3375 3376 3377

    if (_vec.len[@ty.t](tys) != 0u) {
        auto bcx = cx;
        let vec[ValueRef] tydescs = vec();
        for (@ty.t t in tys) {
            auto td = get_tydesc(bcx, t);
            bcx = td.bcx;
3378
            _vec.push[ValueRef](tydescs, td.val);
3379 3380 3381 3382 3383 3384 3385 3386 3387 3388
        }
        auto gen = rec( item_type = tpt._1,
                        tydescs = tydescs );
        lv = rec(res = res(bcx, lv.res.val),
                 generic = some[generic_info](gen)
                 with lv);
    }
    ret lv;
}

3389
fn trans_path(@block_ctxt cx, &ast.path p, &option.t[ast.def] dopt,
G
Graydon Hoare 已提交
3390
              &ast.ann ann) -> lval_result {
3391 3392 3393 3394
    alt (dopt) {
        case (some[ast.def](?def)) {
            alt (def) {
                case (ast.def_arg(?did)) {
3395 3396 3397 3398 3399 3400 3401 3402 3403
                    alt (cx.fcx.llargs.find(did)) {
                        case (none[ValueRef]) {
                            check (cx.fcx.llupvars.contains_key(did));
                            ret lval_mem(cx, cx.fcx.llupvars.get(did));
                        }
                        case (some[ValueRef](?llval)) {
                            ret lval_mem(cx, llval);
                        }
                    }
3404 3405
                }
                case (ast.def_local(?did)) {
3406 3407 3408 3409 3410 3411 3412 3413 3414
                    alt (cx.fcx.lllocals.find(did)) {
                        case (none[ValueRef]) {
                            check (cx.fcx.llupvars.contains_key(did));
                            ret lval_mem(cx, cx.fcx.llupvars.get(did));
                        }
                        case (some[ValueRef](?llval)) {
                            ret lval_mem(cx, llval);
                        }
                    }
G
Graydon Hoare 已提交
3415
                }
P
Patrick Walton 已提交
3416 3417
                case (ast.def_binding(?did)) {
                    check (cx.fcx.lllocals.contains_key(did));
3418
                    ret lval_mem(cx, cx.fcx.lllocals.get(did));
P
Patrick Walton 已提交
3419
                }
3420 3421 3422 3423
                case (ast.def_obj_field(?did)) {
                    check (cx.fcx.llobjfields.contains_key(did));
                    ret lval_mem(cx, cx.fcx.llobjfields.get(did));
                }
3424
                case (ast.def_fn(?did)) {
3425
                    check (cx.fcx.ccx.items.contains_key(did));
3426
                    auto fn_item = cx.fcx.ccx.items.get(did);
3427
                    ret lval_generic_fn(cx, ty.item_ty(fn_item), did, ann);
3428
                }
3429
                case (ast.def_obj(?did)) {
3430 3431 3432
                    check (cx.fcx.ccx.items.contains_key(did));
                    auto fn_item = cx.fcx.ccx.items.get(did);
                    ret lval_generic_fn(cx, ty.item_ty(fn_item), did, ann);
3433
                }
3434
                case (ast.def_variant(?tid, ?vid)) {
3435
                    if (cx.fcx.ccx.fn_pairs.contains_key(vid)) {
3436 3437 3438
                        check (cx.fcx.ccx.items.contains_key(tid));
                        auto tag_item = cx.fcx.ccx.items.get(tid);
                        auto params = ty.item_ty(tag_item)._0;
3439
                        auto fty = plain_ty(ty.ty_nil);
3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450
                        alt (tag_item.node) {
                            case (ast.item_tag(_, ?variants, _, _)) {
                                for (ast.variant v in variants) {
                                    if (v.id == vid) {
                                        fty = node_ann_type(cx.fcx.ccx,
                                                            v.ann);
                                    }
                                }
                            }
                        }
                        ret lval_generic_fn(cx, tup(params, fty), vid, ann);
3451
                    } else {
3452 3453
                        // Nullary variant.
                        auto tag_ty = node_ann_type(cx.fcx.ccx, ann);
3454
                        auto lldiscrim_gv = cx.fcx.ccx.discrims.get(vid);
3455 3456 3457 3458
                        auto lldiscrim = cx.build.Load(lldiscrim_gv);

                        auto alloc_result = alloc_ty(cx, tag_ty);
                        auto lltagblob = alloc_result.val;
3459 3460 3461 3462 3463 3464 3465

                        auto lltagty;
                        if (ty.type_has_dynamic_size(tag_ty)) {
                            lltagty = T_opaque_tag(cx.fcx.ccx.tn);
                        } else {
                            lltagty = type_of(cx.fcx.ccx, tag_ty);
                        }
3466
                        auto lltagptr = alloc_result.bcx.build.PointerCast(
3467
                            lltagblob, T_ptr(lltagty));
3468 3469 3470 3471 3472 3473

                        auto lldiscrimptr = alloc_result.bcx.build.GEP(
                            lltagptr, vec(C_int(0), C_int(0)));
                        alloc_result.bcx.build.Store(lldiscrim, lldiscrimptr);

                        ret lval_val(alloc_result.bcx, lltagptr);
3474
                    }
3475
                }
3476 3477 3478 3479
                case (ast.def_const(?did)) {
                    check (cx.fcx.ccx.consts.contains_key(did));
                    ret lval_mem(cx, cx.fcx.ccx.consts.get(did));
                }
3480 3481 3482 3483 3484 3485
                case (ast.def_native_fn(?did)) {
                    check (cx.fcx.ccx.native_items.contains_key(did));
                    auto fn_item = cx.fcx.ccx.native_items.get(did);
                    ret lval_generic_fn(cx, ty.native_item_ty(fn_item),
                                        did, ann);
                }
3486 3487
                case (_) {
                    cx.fcx.ccx.sess.unimpl("def variant in trans");
G
Graydon Hoare 已提交
3488 3489 3490
                }
            }
        }
3491
        case (none[ast.def]) {
3492
            cx.fcx.ccx.sess.err("unresolved expr_path in trans");
3493 3494 3495 3496 3497
        }
    }
    fail;
}

3498 3499
fn trans_field(@block_ctxt cx, &ast.span sp, @ast.expr base,
               &ast.ident field, &ast.ann ann) -> lval_result {
3500
    auto r = trans_expr(cx, base);
3501
    auto t = ty.expr_ty(base);
3502 3503
    r = autoderef(r.bcx, r.val, t);
    t = autoderefed_ty(t);
3504
    alt (t.struct) {
3505
        case (ty.ty_tup(_)) {
3506
            let uint ix = ty.field_num(cx.fcx.ccx.sess, sp, field);
3507
            auto v = GEP_tup_like(r.bcx, t, r.val, vec(0, ix as int));
3508
            ret lval_mem(v.bcx, v.val);
3509
        }
3510 3511
        case (ty.ty_rec(?fields)) {
            let uint ix = ty.field_idx(cx.fcx.ccx.sess, sp, field, fields);
3512
            auto v = GEP_tup_like(r.bcx, t, r.val, vec(0, ix as int));
3513
            ret lval_mem(v.bcx, v.val);
3514
        }
3515 3516
        case (ty.ty_obj(?methods)) {
            let uint ix = ty.method_idx(cx.fcx.ccx.sess, sp, field, methods);
3517 3518 3519 3520 3521 3522
            auto vtbl = r.bcx.build.GEP(r.val,
                                        vec(C_int(0),
                                            C_int(abi.obj_field_vtbl)));
            vtbl = r.bcx.build.Load(vtbl);
            auto v =  r.bcx.build.GEP(vtbl, vec(C_int(0),
                                                C_int(ix as int)));
3523 3524 3525

            auto lvo = lval_mem(r.bcx, v);
            ret rec(llobj = some[ValueRef](r.val) with lvo);
3526
        }
3527
        case (_) { cx.fcx.ccx.sess.unimpl("field variant in trans_field"); }
3528 3529 3530 3531
    }
    fail;
}

3532 3533
fn trans_index(@block_ctxt cx, &ast.span sp, @ast.expr base,
               @ast.expr idx, &ast.ann ann) -> lval_result {
3534

G
Graydon Hoare 已提交
3535
    auto lv = trans_expr(cx, base);
3536
    lv = autoderef(lv.bcx, lv.val, ty.expr_ty(base));
G
Graydon Hoare 已提交
3537 3538
    auto ix = trans_expr(lv.bcx, idx);
    auto v = lv.val;
3539
    auto bcx = ix.bcx;
3540

3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552
    // Cast to an LLVM integer. Rust is less strict than LLVM in this regard.
    auto ix_val;
    auto ix_size = llsize_of_real(cx.fcx.ccx, val_ty(ix.val));
    auto int_size = llsize_of_real(cx.fcx.ccx, T_int());
    if (ix_size < int_size) {
        ix_val = bcx.build.ZExt(ix.val, T_int());
    } else if (ix_size > int_size) {
        ix_val = bcx.build.Trunc(ix.val, T_int());
    } else {
        ix_val = ix.val;
    }

3553 3554
    auto unit_sz = size_of(bcx, node_ann_type(cx.fcx.ccx, ann));
    bcx = unit_sz.bcx;
3555 3556

    auto scaled_ix = bcx.build.Mul(ix_val, unit_sz.val);
3557

3558 3559
    auto lim = bcx.build.GEP(v, vec(C_int(0), C_int(abi.vec_elt_fill)));
    lim = bcx.build.Load(lim);
3560

3561 3562
    auto bounds_check = bcx.build.ICmp(lib.llvm.LLVMIntULT,
                                       scaled_ix, lim);
3563

3564 3565 3566
    auto fail_cx = new_sub_block_ctxt(bcx, "fail");
    auto next_cx = new_sub_block_ctxt(bcx, "next");
    bcx.build.CondBr(bounds_check, next_cx.llbb, fail_cx.llbb);
3567 3568

    // fail: bad bounds check.
B
Brian Anderson 已提交
3569
    auto fail_res = trans_fail(fail_cx, sp, "bounds check");
3570 3571 3572
    fail_res.bcx.build.Br(next_cx.llbb);

    auto body = next_cx.build.GEP(v, vec(C_int(0), C_int(abi.vec_elt_data)));
3573
    auto elt = next_cx.build.GEP(body, vec(C_int(0), ix_val));
3574
    ret lval_mem(next_cx, elt);
3575 3576
}

3577 3578 3579 3580
// 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).

3581
fn trans_lval(@block_ctxt cx, @ast.expr e) -> lval_result {
3582
    alt (e.node) {
3583 3584
        case (ast.expr_path(?p, ?dopt, ?ann)) {
            ret trans_path(cx, p, dopt, ann);
3585 3586 3587 3588
        }
        case (ast.expr_field(?base, ?ident, ?ann)) {
            ret trans_field(cx, e.span, base, ident, ann);
        }
3589 3590 3591
        case (ast.expr_index(?base, ?idx, ?ann)) {
            ret trans_index(cx, e.span, base, idx, ann);
        }
3592
        case (_) { cx.fcx.ccx.sess.unimpl("expr variant in trans_lval"); }
G
Graydon Hoare 已提交
3593 3594 3595 3596
    }
    fail;
}

3597
fn trans_cast(@block_ctxt cx, @ast.expr e, &ast.ann ann) -> result {
3598 3599 3600 3601
    auto e_res = trans_expr(cx, e);
    auto llsrctype = val_ty(e_res.val);
    auto t = node_ann_type(cx.fcx.ccx, ann);
    auto lldsttype = type_of(cx.fcx.ccx, t);
3602
    if (!ty.type_is_fp(t)) {
3603
        // TODO: native-to-native casts
3604 3605
        if (ty.type_is_native(ty.expr_ty(e))) {
            e_res.val = e_res.bcx.build.PtrToInt(e_res.val, lldsttype);
3606 3607
        } else if (ty.type_is_native(t)) {
            e_res.val = e_res.bcx.build.IntToPtr(e_res.val, lldsttype);
3608
        } else if (llvm.LLVMGetIntTypeWidth(lldsttype) >
3609
            llvm.LLVMGetIntTypeWidth(llsrctype)) {
3610
            if (ty.type_is_signed(t)) {
3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632
                // Widening signed cast.
                e_res.val =
                    e_res.bcx.build.SExtOrBitCast(e_res.val,
                                                  lldsttype);
            } else {
                // Widening unsigned cast.
                e_res.val =
                    e_res.bcx.build.ZExtOrBitCast(e_res.val,
                                                  lldsttype);
            }
        } else {
            // Narrowing cast.
            e_res.val =
                e_res.bcx.build.TruncOrBitCast(e_res.val,
                                               lldsttype);
        }
    } else {
        cx.fcx.ccx.sess.unimpl("fp cast");
    }
    ret e_res;
}

3633 3634 3635 3636
fn trans_bind_thunk(@crate_ctxt cx,
                    @ty.t incoming_fty,
                    @ty.t outgoing_fty,
                    vec[option.t[@ast.expr]] args,
3637
                    @ty.t closure_ty,
3638 3639
                    vec[@ty.t] bound_tys,
                    uint ty_param_count) -> ValueRef {
3640 3641 3642
    // Construct a thunk-call with signature incoming_fty, and that copies
    // args forward into a call to outgoing_fty.

3643
    let str s = cx.names.next("_rust_thunk") + sep() + cx.path;
3644 3645 3646
    let TypeRef llthunk_ty = get_pair_fn_ty(type_of(cx, incoming_fty));
    let ValueRef llthunk = decl_fastcall_fn(cx.llmod, s, llthunk_ty);

3647
    auto fcx = new_fn_ctxt(cx, llthunk);
3648 3649
    auto bcx = new_top_block_ctxt(fcx);

3650
    auto llclosure_ptr_ty = type_of(cx, ty.plain_box_ty(closure_ty));
3651
    auto llclosure = bcx.build.PointerCast(fcx.llenv, llclosure_ptr_ty);
3652

3653 3654 3655 3656 3657 3658
    auto lltarget = GEP_tup_like(bcx, closure_ty, llclosure,
                                 vec(0,
                                     abi.box_rc_field_body,
                                     abi.closure_elt_target));
    bcx = lltarget.bcx;
    auto lltargetclosure = bcx.build.GEP(lltarget.val,
3659 3660 3661
                                         vec(C_int(0),
                                             C_int(abi.fn_field_box)));
    lltargetclosure = bcx.build.Load(lltargetclosure);
3662 3663

    auto outgoing_ret_ty = ty.ty_fn_ret(outgoing_fty);
3664
    auto outgoing_args = ty.ty_fn_args(outgoing_fty);
3665 3666 3667 3668 3669 3670 3671

    auto llretptr = fcx.llretptr;
    if (ty.type_has_dynamic_size(outgoing_ret_ty)) {
        llretptr = bcx.build.PointerCast(llretptr, T_typaram_ptr(cx.tn));
    }

    let vec[ValueRef] llargs = vec(llretptr,
3672
                                   fcx.lltaskptr,
3673
                                   lltargetclosure);
3674 3675 3676 3677 3678

    // Copy in the type parameters.
    let uint i = 0u;
    while (i < ty_param_count) {
        auto lltyparam_ptr =
3679 3680 3681 3682 3683 3684 3685
            GEP_tup_like(bcx, closure_ty, llclosure,
                         vec(0,
                             abi.box_rc_field_body,
                             abi.closure_elt_ty_params,
                             (i as int)));
        bcx = lltyparam_ptr.bcx;
        llargs += vec(bcx.build.Load(lltyparam_ptr.val));
3686 3687 3688
        i += 1u;
    }

3689
    let uint a = 3u;    // retptr, task ptr, env come first
3690
    let int b = 0;
3691
    let uint outgoing_arg_index = 0u;
3692 3693 3694
    let vec[TypeRef] llout_arg_tys =
        type_of_explicit_args(cx, outgoing_args);

3695
    for (option.t[@ast.expr] arg in args) {
3696 3697 3698 3699

        auto out_arg = outgoing_args.(outgoing_arg_index);
        auto llout_arg_ty = llout_arg_tys.(outgoing_arg_index);

3700 3701 3702 3703
        alt (arg) {

            // Arg provided at binding time; thunk copies it from closure.
            case (some[@ast.expr](_)) {
3704 3705 3706 3707 3708 3709
                auto bound_arg =
                    GEP_tup_like(bcx, closure_ty, llclosure,
                                 vec(0,
                                     abi.box_rc_field_body,
                                     abi.closure_elt_bindings,
                                     b));
3710

3711
                bcx = bound_arg.bcx;
3712 3713 3714 3715 3716 3717 3718 3719 3720
                auto val = bound_arg.val;

                if (out_arg.mode == ast.val) {
                    val = bcx.build.Load(val);
                } else if (ty.count_ty_params(out_arg.ty) > 0u) {
                    check (out_arg.mode == ast.alias);
                    val = bcx.build.PointerCast(val, llout_arg_ty);
                }

3721
                llargs += vec(val);
3722 3723 3724 3725 3726 3727
                b += 1;
            }

            // Arg will be provided when the thunk is invoked.
            case (none[@ast.expr]) {
                let ValueRef passed_arg = llvm.LLVMGetParam(llthunk, a);
3728 3729 3730

                if (ty.count_ty_params(out_arg.ty) > 0u) {
                    check (out_arg.mode == ast.alias);
3731
                    passed_arg = bcx.build.PointerCast(passed_arg,
3732
                                                       llout_arg_ty);
3733
                }
3734

3735
                llargs += vec(passed_arg);
3736 3737 3738
                a += 1u;
            }
        }
3739

3740
        outgoing_arg_index += 1u;
3741 3742 3743
    }

    // FIXME: turn this call + ret into a tail call.
3744
    auto lltargetfn = bcx.build.GEP(lltarget.val,
3745 3746
                                    vec(C_int(0),
                                        C_int(abi.fn_field_code)));
3747 3748 3749 3750 3751 3752 3753 3754 3755 3756

    // Cast the outgoing function to the appropriate type (see the comments in
    // trans_bind below for why this is necessary).
    auto lltargetty = type_of_fn(bcx.fcx.ccx,
                                 ty.ty_fn_proto(outgoing_fty),
                                 outgoing_args,
                                 outgoing_ret_ty,
                                 ty_param_count);
    lltargetfn = bcx.build.PointerCast(lltargetfn, T_ptr(T_ptr(lltargetty)));

3757
    lltargetfn = bcx.build.Load(lltargetfn);
3758

3759
    auto r = bcx.build.FastCall(lltargetfn, llargs);
3760
    bcx.build.RetVoid();
3761 3762 3763 3764

    ret llthunk;
}

3765 3766 3767
fn trans_bind(@block_ctxt cx, @ast.expr f,
              vec[option.t[@ast.expr]] args,
              &ast.ann ann) -> result {
3768 3769 3770 3771
    auto f_res = trans_lval(cx, f);
    if (f_res.is_mem) {
        cx.fcx.ccx.sess.unimpl("re-binding existing function");
    } else {
3772 3773
        let vec[@ast.expr] bound = vec();

3774 3775 3776 3777 3778
        for (option.t[@ast.expr] argopt in args) {
            alt (argopt) {
                case (none[@ast.expr]) {
                }
                case (some[@ast.expr](?e)) {
3779
                    _vec.push[@ast.expr](bound, e);
3780 3781 3782
                }
            }
        }
3783 3784

        // Figure out which tydescs we need to pass, if any.
B
Brian Anderson 已提交
3785 3786
        let @ty.t outgoing_fty;
        let vec[ValueRef] lltydescs;
3787 3788 3789
        alt (f_res.generic) {
            case (none[generic_info]) {
                outgoing_fty = ty.expr_ty(f);
B
Brian Anderson 已提交
3790
                lltydescs = vec();
3791 3792 3793 3794 3795 3796 3797 3798 3799
            }
            case (some[generic_info](?ginfo)) {
                outgoing_fty = ginfo.item_type;
                lltydescs = ginfo.tydescs;
            }
        }
        auto ty_param_count = _vec.len[ValueRef](lltydescs);

        if (_vec.len[@ast.expr](bound) == 0u && ty_param_count == 0u) {
3800 3801 3802 3803 3804 3805
            // Trivial 'binding': just return the static pair-ptr.
            ret f_res.res;
        } else {
            auto bcx = f_res.res.bcx;
            auto pair_t = node_type(cx.fcx.ccx, ann);
            auto pair_v = bcx.build.Alloca(pair_t);
3806 3807 3808 3809

            // Translate the bound expressions.
            let vec[@ty.t] bound_tys = vec();
            let vec[ValueRef] bound_vals = vec();
3810
            auto i = 0u;
3811 3812 3813
            for (@ast.expr e in bound) {
                auto arg = trans_expr(bcx, e);
                bcx = arg.bcx;
3814

3815 3816
                _vec.push[ValueRef](bound_vals, arg.val);
                _vec.push[@ty.t](bound_tys, ty.expr_ty(e));
3817 3818

                i += 1u;
3819 3820 3821
            }

            // Synthesize a closure type.
3822
            let @ty.t bindings_ty = ty.plain_tup_ty(bound_tys);
3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835

            // 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.
            let @ty.t tydesc_ty = plain_ty(ty.ty_type);

            let vec[@ty.t] captured_tys =
                _vec.init_elt[@ty.t](tydesc_ty, ty_param_count);

            let vec[@ty.t] closure_tys =
                vec(tydesc_ty,
                    outgoing_fty,
                    bindings_ty,
3836
                    ty.plain_tup_ty(captured_tys));
3837

3838
            let @ty.t closure_ty = ty.plain_tup_ty(closure_tys);
3839 3840

            auto r = trans_malloc_boxed(bcx, closure_ty);
3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857
            auto box = r.val;
            bcx = r.bcx;
            auto rc = bcx.build.GEP(box,
                                    vec(C_int(0),
                                        C_int(abi.box_rc_field_refcnt)));
            auto closure =
                bcx.build.GEP(box,
                              vec(C_int(0),
                                  C_int(abi.box_rc_field_body)));
            bcx.build.Store(C_int(1), rc);

            // Store bindings tydesc.
            auto bound_tydesc =
                bcx.build.GEP(closure,
                              vec(C_int(0),
                                  C_int(abi.closure_elt_tydesc)));
            auto bindings_tydesc = get_tydesc(bcx, bindings_ty);
3858 3859
            bcx = bindings_tydesc.bcx;
            bcx.build.Store(bindings_tydesc.val, bound_tydesc);
3860

3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873
            // Determine the LLVM type for the outgoing function type. This
            // may be different from the type returned by trans_malloc_boxed()
            // since we have more information than that function does;
            // specifically, we know how many type descriptors the outgoing
            // function has, which type_of() doesn't, as only we know which
            // item the function refers to.
            auto llfnty = type_of_fn(bcx.fcx.ccx,
                                     ty.ty_fn_proto(outgoing_fty),
                                     ty.ty_fn_args(outgoing_fty),
                                     ty.ty_fn_ret(outgoing_fty),
                                     ty_param_count);
            auto llclosurety = T_ptr(T_fn_pair(bcx.fcx.ccx.tn, llfnty));

3874 3875
            // Store thunk-target.
            auto bound_target =
3876 3877
                bcx.build.GEP(closure,
                              vec(C_int(0),
3878
                                  C_int(abi.closure_elt_target)));
3879
            auto src = bcx.build.Load(f_res.res.val);
3880
            bound_target = bcx.build.PointerCast(bound_target, llclosurety);
3881
            bcx.build.Store(src, bound_target);
3882

3883
            // Copy expr values into boxed bindings.
3884
            i = 0u;
3885 3886 3887 3888
            auto bindings =
                bcx.build.GEP(closure,
                              vec(C_int(0),
                                  C_int(abi.closure_elt_bindings)));
3889 3890
            for (ValueRef v in bound_vals) {
                auto bound = bcx.build.GEP(bindings,
3891
                                           vec(C_int(0), C_int(i as int)));
3892
                bcx = copy_ty(r.bcx, INIT, bound, v, bound_tys.(i)).bcx;
3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912
                i += 1u;
            }

            // If necessary, copy tydescs describing type parameters into the
            // appropriate slot in the closure.
            alt (f_res.generic) {
                case (none[generic_info]) { /* nothing to do */ }
                case (some[generic_info](?ginfo)) {
                    auto ty_params_slot =
                        bcx.build.GEP(closure,
                                      vec(C_int(0),
                                          C_int(abi.closure_elt_ty_params)));
                    auto i = 0;
                    for (ValueRef td in ginfo.tydescs) {
                        auto ty_param_slot = bcx.build.GEP(ty_params_slot,
                                                           vec(C_int(0),
                                                               C_int(i)));
                        bcx.build.Store(td, ty_param_slot);
                        i += 1;
                    }
3913 3914

                    outgoing_fty = ginfo.item_type;
3915
                }
3916 3917
            }

3918 3919 3920 3921
            // Make thunk and store thunk-ptr in outer pair's code slot.
            auto pair_code = bcx.build.GEP(pair_v,
                                           vec(C_int(0),
                                               C_int(abi.fn_field_code)));
3922 3923

            let @ty.t pair_ty = node_ann_type(cx.fcx.ccx, ann);
3924

3925
            let ValueRef llthunk =
3926
                trans_bind_thunk(cx.fcx.ccx, pair_ty, outgoing_fty,
3927
                                 args, closure_ty, bound_tys,
3928
                                 ty_param_count);
3929 3930 3931 3932 3933 3934 3935

            bcx.build.Store(llthunk, pair_code);

            // Store box ptr in outer pair's box slot.
            auto pair_box = bcx.build.GEP(pair_v,
                                          vec(C_int(0),
                                              C_int(abi.fn_field_box)));
3936 3937 3938 3939 3940
            bcx.build.Store
                (bcx.build.PointerCast
                 (box,
                  T_opaque_closure_ptr(bcx.fcx.ccx.tn)),
                 pair_box);
3941

3942
            find_scope_cx(cx).cleanups +=
3943
                vec(clean(bind drop_slot(_, pair_v, pair_ty)));
3944

3945 3946
            ret res(bcx, pair_v);
        }
3947 3948 3949
    }
}

3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args

fn trans_args(@block_ctxt cx,
              ValueRef llenv,
              option.t[ValueRef] llobj,
              option.t[generic_info] gen,
3961
              option.t[ValueRef] lliterbody,
3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973
              &vec[@ast.expr] es,
              @ty.t fn_ty)
    -> tup(@block_ctxt, vec[ValueRef], ValueRef) {

    let vec[ty.arg] args = ty.ty_fn_args(fn_ty);
    let vec[ValueRef] llargs = vec();
    let vec[ValueRef] lltydescs = vec();
    let @block_ctxt bcx = cx;


    // Arg 0: Output pointer.
    auto retty = ty.ty_fn_ret(fn_ty);
3974 3975 3976 3977
    auto llretslot_res = alloc_ty(bcx, retty);
    bcx = llretslot_res.bcx;
    auto llretslot = llretslot_res.val;

3978 3979 3980 3981 3982 3983 3984 3985 3986 3987
    alt (gen) {
        case (some[generic_info](?g)) {
            lltydescs = g.tydescs;
            args = ty.ty_fn_args(g.item_type);
            retty = ty.ty_fn_ret(g.item_type);
        }
        case (_) {
        }
    }
    if (ty.type_has_dynamic_size(retty)) {
3988 3989
        llargs += vec(bcx.build.PointerCast(llretslot,
                                            T_typaram_ptr(cx.fcx.ccx.tn)));
3990 3991 3992 3993 3994 3995
    } else if (ty.count_ty_params(retty) != 0u) {
        // 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.
3996 3997 3998
        llargs +=
            vec(cx.build.PointerCast(llretslot,
                                     T_ptr(type_of(bcx.fcx.ccx, retty))));
3999
    } else {
4000
        llargs += vec(llretslot);
4001 4002 4003 4004
    }


    // Arg 1: Task pointer.
4005
    llargs += vec(bcx.fcx.lltaskptr);
4006 4007 4008 4009 4010 4011 4012

    // Arg 2: Env (closure-bindings / self-obj)
    alt (llobj) {
        case (some[ValueRef](?ob)) {
            // Every object is always found in memory,
            // and not-yet-loaded (as part of an lval x.y
            // doted method-call).
4013
            llargs += vec(bcx.build.Load(ob));
4014 4015
        }
        case (_) {
4016
            llargs += vec(llenv);
4017 4018 4019 4020 4021 4022
        }
    }

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

4023 4024 4025 4026
    // ... then possibly an lliterbody argument.
    alt (lliterbody) {
        case (none[ValueRef]) {}
        case (some[ValueRef](?lli)) {
4027
            llargs += vec(lli);
4028 4029 4030
        }
    }

4031
    // ... then explicit args.
4032 4033 4034 4035 4036 4037

    // 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.
    auto arg_tys = type_of_explicit_args(cx.fcx.ccx, args);

4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073
    auto i = 0u;
    for (@ast.expr e in es) {
        auto mode = args.(i).mode;

        auto val;
        if (ty.type_is_structural(ty.expr_ty(e))) {
            auto re = trans_expr(bcx, e);
            val = re.val;
            bcx = re.bcx;
        } else if (mode == ast.alias) {
            let lval_result lv;
            if (ty.is_lval(e)) {
                lv = trans_lval(bcx, e);
            } else {
                auto r = trans_expr(bcx, e);
                lv = lval_val(r.bcx, r.val);
            }
            bcx = lv.res.bcx;

            if (lv.is_mem) {
                val = lv.res.val;
            } else {
                // Non-mem but we're trying to alias; synthesize an
                // alloca, spill to it and pass its address.
                auto llty = val_ty(lv.res.val);
                auto llptr = lv.res.bcx.build.Alloca(llty);
                lv.res.bcx.build.Store(lv.res.val, llptr);
                val = llptr;
            }

        } else {
            auto re = trans_expr(bcx, e);
            val = re.val;
            bcx = re.bcx;
        }

4074 4075
        if (ty.count_ty_params(args.(i).ty) > 0u) {
            auto lldestty = arg_tys.(i);
4076 4077 4078 4079 4080 4081 4082
            if (mode == ast.val) {
                // FIXME: we'd prefer to use &&, but rustboot doesn't like it
                if (ty.type_is_structural(ty.expr_ty(e))) {
                    lldestty = T_ptr(lldestty);
                }
            }

4083
            val = bcx.build.PointerCast(val, lldestty);
4084 4085
        }

4086 4087 4088 4089 4090 4091 4092 4093 4094
        if (mode == ast.val) {
            // FIXME: we'd prefer to use &&, but rustboot doesn't like it
            if (ty.type_is_structural(ty.expr_ty(e))) {
                // Until here we've been treating structures by pointer;
                // we are now passing it as an arg, so need to load it.
                val = bcx.build.Load(val);
            }
        }

4095
        llargs += vec(val);
4096 4097 4098 4099 4100 4101
        i += 1u;
    }

    ret tup(bcx, llargs, llretslot);
}

4102
fn trans_call(@block_ctxt cx, @ast.expr f,
4103 4104 4105
              option.t[ValueRef] lliterbody,
              vec[@ast.expr] args,
              &ast.ann ann) -> result {
4106
    auto f_res = trans_lval(cx, f);
4107
    auto faddr = f_res.res.val;
4108
    auto llenv = C_null(T_opaque_closure_ptr(cx.fcx.ccx.tn));
4109 4110 4111 4112 4113 4114 4115 4116 4117

    alt (f_res.llobj) {
        case (some[ValueRef](_)) {
            // It's a vtbl entry.
            faddr = f_res.res.bcx.build.Load(faddr);
        }
        case (none[ValueRef]) {
            // It's a closure.
            auto bcx = f_res.res.bcx;
4118 4119
            auto pair = faddr;
            faddr = bcx.build.GEP(pair, vec(C_int(0),
G
Graydon Hoare 已提交
4120
                                            C_int(abi.fn_field_code)));
4121
            faddr = bcx.build.Load(faddr);
4122

4123 4124 4125 4126
            auto llclosure = bcx.build.GEP(pair,
                                           vec(C_int(0),
                                               C_int(abi.fn_field_box)));
            llenv = bcx.build.Load(llclosure);
4127
        }
4128
    }
4129 4130
    auto fn_ty = ty.expr_ty(f);
    auto ret_ty = ty.ann_to_type(ann);
G
Graydon Hoare 已提交
4131
    auto args_res = trans_args(f_res.res.bcx,
4132
                               llenv, f_res.llobj,
4133
                               f_res.generic,
4134
                               lliterbody,
4135
                               args, fn_ty);
G
Graydon Hoare 已提交
4136

4137
    auto bcx = args_res._0;
4138 4139 4140
    auto llargs = args_res._1;
    auto llretslot = args_res._2;

4141 4142 4143 4144 4145 4146 4147 4148
    /*
    log "calling: " + val_str(cx.fcx.ccx.tn, faddr);

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

4149 4150 4151 4152 4153 4154 4155 4156
    bcx.build.FastCall(faddr, llargs);
    auto retval = C_nil();

    if (!ty.type_is_nil(ret_ty)) {
        retval = load_scalar_or_boxed(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.
4157 4158
        find_scope_cx(cx).cleanups +=
            vec(clean(bind drop_ty(_, retval, ret_ty)));
4159
    }
G
Graydon Hoare 已提交
4160

4161
    ret res(bcx, retval);
4162 4163
}

4164 4165
fn trans_tup(@block_ctxt cx, vec[ast.elt] elts,
             &ast.ann ann) -> result {
4166 4167 4168 4169 4170 4171
    auto bcx = cx;
    auto t = node_ann_type(bcx.fcx.ccx, ann);
    auto tup_res = alloc_ty(bcx, t);
    auto tup_val = tup_res.val;
    bcx = tup_res.bcx;

4172 4173
    find_scope_cx(cx).cleanups +=
        vec(clean(bind drop_ty(_, tup_val, t)));
G
Graydon Hoare 已提交
4174
    let int i = 0;
4175

4176
    for (ast.elt e in elts) {
4177 4178 4179 4180 4181 4182
        auto e_ty = ty.expr_ty(e.expr);
        auto src_res = trans_expr(bcx, e.expr);
        bcx = src_res.bcx;
        auto dst_res = GEP_tup_like(bcx, t, tup_val, vec(0, i));
        bcx = dst_res.bcx;
        bcx = copy_ty(src_res.bcx, INIT, dst_res.val, src_res.val, e_ty).bcx;
G
Graydon Hoare 已提交
4183 4184
        i += 1;
    }
4185
    ret res(bcx, tup_val);
G
Graydon Hoare 已提交
4186 4187
}

4188 4189
fn trans_vec(@block_ctxt cx, vec[@ast.expr] args,
             &ast.ann ann) -> result {
4190 4191 4192
    auto t = node_ann_type(cx.fcx.ccx, ann);
    auto unit_ty = t;
    alt (t.struct) {
4193 4194
        case (ty.ty_vec(?mt)) {
            unit_ty = mt.ty;
G
Graydon Hoare 已提交
4195 4196 4197 4198 4199 4200
        }
        case (_) {
            cx.fcx.ccx.sess.bug("non-vec type in trans_vec");
        }
    }

4201 4202 4203
    auto bcx = cx;
    auto unit_sz = size_of(bcx, unit_ty);
    bcx = unit_sz.bcx;
4204 4205
    auto data_sz = bcx.build.Mul(C_int(_vec.len[@ast.expr](args) as int),
                                 unit_sz.val);
G
Graydon Hoare 已提交
4206 4207

    // FIXME: pass tydesc properly.
4208
    auto sub = trans_upcall(bcx, "upcall_new_vec", vec(data_sz, C_int(0)));
4209
    bcx = sub.bcx;
G
Graydon Hoare 已提交
4210

4211
    auto llty = type_of(bcx.fcx.ccx, t);
4212
    auto vec_val = vi2p(bcx, sub.val, llty);
4213 4214
    find_scope_cx(bcx).cleanups +=
        vec(clean(bind drop_ty(_, vec_val, t)));
G
Graydon Hoare 已提交
4215

4216 4217 4218 4219
    auto body = bcx.build.GEP(vec_val, vec(C_int(0),
                                           C_int(abi.vec_elt_data)));

    auto pseudo_tup_ty =
4220 4221
        ty.plain_tup_ty(_vec.init_elt[@ty.t](unit_ty,
                                             _vec.len[@ast.expr](args)));
G
Graydon Hoare 已提交
4222
    let int i = 0;
4223

G
Graydon Hoare 已提交
4224
    for (@ast.expr e in args) {
4225 4226 4227 4228
        auto src_res = trans_expr(bcx, e);
        bcx = src_res.bcx;
        auto dst_res = GEP_tup_like(bcx, pseudo_tup_ty, body, vec(0, i));
        bcx = dst_res.bcx;
4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243

        // Cast the destination type to the source type. This is needed to
        // make tags work, for a subtle combination of reasons:
        //
        // (1) "dst_res" above is derived from "body", which is in turn
        //     derived from "vec_val".
        // (2) "vec_val" has the LLVM type "llty".
        // (3) "llty" is the result of calling type_of() on a vector type.
        // (4) For tags, type_of() returns a different type depending on
        //     on whether the tag is behind a box or not. Vector types are
        //     considered boxes.
        // (5) "src_res" is derived from "unit_ty", which is not behind a box.

        auto dst_val;
        if (!ty.type_has_dynamic_size(unit_ty)) {
4244
            auto llunit_ty = type_of(cx.fcx.ccx, unit_ty);
4245 4246 4247 4248 4249 4250
            dst_val = bcx.build.PointerCast(dst_res.val, T_ptr(llunit_ty));
        } else {
            dst_val = dst_res.val;
        }

        bcx = copy_ty(bcx, INIT, dst_val, src_res.val, unit_ty).bcx;
G
Graydon Hoare 已提交
4251 4252
        i += 1;
    }
4253 4254 4255
    auto fill = bcx.build.GEP(vec_val,
                              vec(C_int(0), C_int(abi.vec_elt_fill)));
    bcx.build.Store(data_sz, fill);
4256

4257
    ret res(bcx, vec_val);
G
Graydon Hoare 已提交
4258 4259
}

4260
fn trans_rec(@block_ctxt cx, vec[ast.field] fields,
4261 4262
             option.t[@ast.expr] base, &ast.ann ann) -> result {

4263 4264 4265 4266 4267 4268 4269
    auto bcx = cx;
    auto t = node_ann_type(bcx.fcx.ccx, ann);
    auto llty = type_of(bcx.fcx.ccx, t);
    auto rec_res = alloc_ty(bcx, t);
    auto rec_val = rec_res.val;
    bcx = rec_res.bcx;

4270 4271
    find_scope_cx(cx).cleanups +=
        vec(clean(bind drop_ty(_, rec_val, t)));
4272
    let int i = 0;
4273

G
Graydon Hoare 已提交
4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290
    auto base_val = C_nil();

    alt (base) {
        case (none[@ast.expr]) { }
        case (some[@ast.expr](?bexp)) {
            auto base_res = trans_expr(bcx, bexp);
            bcx = base_res.bcx;
            base_val = base_res.val;
        }
    }

    let vec[ty.field] ty_fields = vec();
    alt (t.struct) {
        case (ty.ty_rec(?flds)) { ty_fields = flds; }
    }

    for (ty.field tf in ty_fields) {
4291
        auto e_ty = tf.mt.ty;
4292 4293
        auto dst_res = GEP_tup_like(bcx, t, rec_val, vec(0, i));
        bcx = dst_res.bcx;
G
Graydon Hoare 已提交
4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311

        auto expr_provided = false;
        auto src_res = res(bcx, C_nil());

        for (ast.field f in fields) {
            if (_str.eq(f.ident, tf.ident)) {
                expr_provided = true;
                src_res = trans_expr(bcx, f.expr);
            }
        }
        if (!expr_provided) {
            src_res = GEP_tup_like(bcx, t, base_val, vec(0, i));
            src_res = res(src_res.bcx,
                          load_scalar_or_boxed(bcx, src_res.val, e_ty));
        }

        bcx = src_res.bcx;
        bcx = copy_ty(bcx, INIT, dst_res.val, src_res.val, e_ty).bcx;
4312 4313
        i += 1;
    }
4314
    ret res(bcx, rec_val);
4315 4316
}

G
Graydon Hoare 已提交
4317

G
Graydon Hoare 已提交
4318

4319
fn trans_expr(@block_ctxt cx, @ast.expr e) -> result {
4320
    alt (e.node) {
4321
        case (ast.expr_lit(?lit, ?ann)) {
4322
            ret res(cx, trans_lit(cx.fcx.ccx, *lit, ann));
4323 4324
        }

4325
        case (ast.expr_unary(?op, ?x, ?ann)) {
4326
            ret trans_unary(cx, op, x, ann);
4327 4328
        }

P
Patrick Walton 已提交
4329
        case (ast.expr_binary(?op, ?x, ?y, _)) {
4330
            ret trans_binary(cx, op, x, y);
4331
        }
4332

P
Patrick Walton 已提交
4333
        case (ast.expr_if(?cond, ?thn, ?els, _)) {
4334
            ret trans_if(cx, cond, thn, els);
4335 4336
        }

G
Graydon Hoare 已提交
4337 4338 4339 4340
        case (ast.expr_for(?decl, ?seq, ?body, _)) {
            ret trans_for(cx, decl, seq, body);
        }

4341 4342 4343 4344
        case (ast.expr_for_each(?decl, ?seq, ?body, _)) {
            ret trans_for_each(cx, decl, seq, body);
        }

4345
        case (ast.expr_while(?cond, ?body, _)) {
4346
            ret trans_while(cx, cond, body);
4347 4348
        }

4349
        case (ast.expr_do_while(?body, ?cond, _)) {
4350
            ret trans_do_while(cx, body, cond);
4351 4352
        }

P
Patrick Walton 已提交
4353 4354 4355 4356
        case (ast.expr_alt(?expr, ?arms, _)) {
            ret trans_alt(cx, expr, arms);
        }

P
Patrick Walton 已提交
4357
        case (ast.expr_block(?blk, _)) {
4358
            ret trans_block(cx, blk);
4359
        }
4360

4361
        case (ast.expr_assign(?dst, ?src, ?ann)) {
4362
            auto lhs_res = trans_lval(cx, dst);
4363 4364
            check (lhs_res.is_mem);
            auto rhs_res = trans_expr(lhs_res.res.bcx, src);
4365
            auto t = node_ann_type(cx.fcx.ccx, ann);
G
Graydon Hoare 已提交
4366
            // FIXME: calculate copy init-ness in typestate.
4367 4368
            ret copy_ty(rhs_res.bcx, DROP_EXISTING,
                        lhs_res.res.val, rhs_res.val, t);
4369
        }
G
Graydon Hoare 已提交
4370

4371 4372 4373
        case (ast.expr_assign_op(?op, ?dst, ?src, ?ann)) {
            auto t = node_ann_type(cx.fcx.ccx, ann);
            auto lhs_res = trans_lval(cx, dst);
4374
            check (lhs_res.is_mem);
4375
            auto lhs_val = load_scalar_or_boxed(lhs_res.res.bcx,
G
Graydon Hoare 已提交
4376
                                                lhs_res.res.val, t);
4377
            auto rhs_res = trans_expr(lhs_res.res.bcx, src);
4378 4379
            auto v = trans_eager_binop(rhs_res.bcx, op, t,
                                       lhs_val, rhs_res.val);
4380
            // FIXME: calculate copy init-ness in typestate.
4381 4382
            ret copy_ty(v.bcx, DROP_EXISTING,
                        lhs_res.res.val, v.val, t);
4383 4384
        }

4385 4386 4387 4388
        case (ast.expr_bind(?f, ?args, ?ann)) {
            ret trans_bind(cx, f, args, ann);
        }

G
Graydon Hoare 已提交
4389
        case (ast.expr_call(?f, ?args, ?ann)) {
4390
            ret trans_call(cx, f, none[ValueRef], args, ann);
4391 4392
        }

4393
        case (ast.expr_cast(?e, _, ?ann)) {
4394
            ret trans_cast(cx, e, ann);
4395
        }
G
Graydon Hoare 已提交
4396

4397
        case (ast.expr_vec(?args, _, ?ann)) {
G
Graydon Hoare 已提交
4398 4399 4400
            ret trans_vec(cx, args, ann);
        }

G
Graydon Hoare 已提交
4401 4402 4403
        case (ast.expr_tup(?args, ?ann)) {
            ret trans_tup(cx, args, ann);
        }
G
Graydon Hoare 已提交
4404

4405 4406
        case (ast.expr_rec(?args, ?base, ?ann)) {
            ret trans_rec(cx, args, base, ann);
4407 4408
        }

4409
        case (ast.expr_ext(_, _, _, ?expanded, _)) {
4410
            ret trans_expr(cx, expanded);
4411 4412
        }

4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428
        case (ast.expr_fail) {
            ret trans_fail(cx, e.span, "explicit failure");
        }

        case (ast.expr_log(?a)) {
            ret trans_log(cx, a);
        }

        case (ast.expr_check_expr(?a)) {
            ret trans_check_expr(cx, a);
        }

        case (ast.expr_ret(?e)) {
            ret trans_ret(cx, e);
        }

4429
        case (ast.expr_put(?e)) {
4430 4431 4432
            ret trans_put(cx, e);
        }

4433 4434 4435 4436
        case (ast.expr_be(?e)) {
            ret trans_be(cx, e);
        }

4437 4438
        // lval cases fall through to trans_lval and then
        // possibly load the result (if it's non-structural).
G
Graydon Hoare 已提交
4439

4440
        case (_) {
4441
            auto t = ty.expr_ty(e);
4442
            auto sub = trans_lval(cx, e);
4443
            ret res(sub.res.bcx,
4444
                    load_scalar_or_boxed(sub.res.bcx, sub.res.val, t));
4445
        }
4446
    }
4447
    cx.fcx.ccx.sess.unimpl("expr variant in trans_expr");
4448 4449 4450
    fail;
}

4451
// We pass structural values around the compiler "by pointer" and
4452 4453
// non-structural values (scalars and boxes) "by value". This function selects
// whether to load a pointer or pass it.
4454

4455 4456 4457
fn load_scalar_or_boxed(@block_ctxt cx,
                        ValueRef v,
                        @ty.t t) -> ValueRef {
4458
    if (ty.type_is_scalar(t) || ty.type_is_boxed(t) || ty.type_is_native(t)) {
4459
        ret cx.build.Load(v);
4460 4461
    } else {
        ret v;
4462 4463 4464
    }
}

4465
fn trans_log(@block_ctxt cx, @ast.expr e) -> result {
4466

4467
    auto sub = trans_expr(cx, e);
4468
    auto e_ty = ty.expr_ty(e);
4469
    alt (e_ty.struct) {
4470
        case (ty.ty_str) {
4471
            auto v = vp2i(sub.bcx, sub.val);
4472 4473 4474
            ret trans_upcall(sub.bcx,
                             "upcall_log_str",
                             vec(v));
4475 4476
        }
        case (_) {
4477 4478 4479
            ret trans_upcall(sub.bcx,
                             "upcall_log_int",
                             vec(sub.val));
4480 4481
        }
    }
4482
    fail;
4483 4484
}

4485
fn trans_check_expr(@block_ctxt cx, @ast.expr e) -> result {
4486 4487 4488
    auto cond_res = trans_expr(cx, e);

    // FIXME: need pretty-printer.
B
Brian Anderson 已提交
4489
    auto expr_str = "<expr>";
4490
    auto fail_cx = new_sub_block_ctxt(cx, "fail");
B
Brian Anderson 已提交
4491
    auto fail_res = trans_fail(fail_cx, e.span, expr_str);
4492

4493
    auto next_cx = new_sub_block_ctxt(cx, "next");
4494 4495 4496 4497 4498 4499 4500
    fail_res.bcx.build.Br(next_cx.llbb);
    cond_res.bcx.build.CondBr(cond_res.val,
                              next_cx.llbb,
                              fail_cx.llbb);
    ret res(next_cx, C_nil());
}

B
Brian Anderson 已提交
4501 4502 4503 4504 4505 4506 4507 4508 4509
fn trans_fail(@block_ctxt cx, common.span sp, str fail_str) -> result {
    auto V_fail_str = p2i(C_cstr(cx.fcx.ccx, fail_str));
    auto V_filename = p2i(C_cstr(cx.fcx.ccx, sp.filename));
    auto V_line = sp.lo.line as int;
    auto args = vec(V_fail_str, V_filename, C_int(V_line));

    ret trans_upcall(cx, "upcall_fail", args);
}

4510
fn trans_put(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534
    auto llcallee = C_nil();
    auto llenv = C_nil();

    alt (cx.fcx.lliterbody) {
        case (some[ValueRef](?lli)) {
            auto slot = cx.build.Alloca(val_ty(lli));
            cx.build.Store(lli, slot);

            llcallee = cx.build.GEP(slot, vec(C_int(0),
                                              C_int(abi.fn_field_code)));
            llcallee = cx.build.Load(llcallee);

            llenv = cx.build.GEP(slot, vec(C_int(0),
                                           C_int(abi.fn_field_box)));
            llenv = cx.build.Load(llenv);
        }
    }
    auto bcx = cx;
    auto dummy_retslot = bcx.build.Alloca(T_nil());
    let vec[ValueRef] llargs = vec(dummy_retslot, cx.fcx.lltaskptr, llenv);
    alt (e) {
        case (none[@ast.expr]) { }
        case (some[@ast.expr](?x)) {
            auto r = trans_expr(bcx, x);
4535 4536

            auto llarg = r.val;
4537
            bcx = r.bcx;
4538 4539 4540 4541 4542 4543
            if (ty.type_is_structural(ty.expr_ty(x))) {
                // Until here we've been treating structures by pointer; we
                // are now passing it as an arg, so need to load it.
                llarg = bcx.build.Load(llarg);
            }

4544
            llargs += vec(llarg);
4545 4546
        }
    }
4547

4548
    ret res(bcx, bcx.build.FastCall(llcallee, llargs));
4549 4550
}

4551 4552 4553 4554
fn trans_ret(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
    auto bcx = cx;
    auto val = C_nil();

4555 4556
    alt (e) {
        case (some[@ast.expr](?x)) {
4557
            auto t = ty.expr_ty(x);
4558 4559 4560
            auto r = trans_expr(cx, x);
            bcx = r.bcx;
            val = r.val;
4561
            bcx = copy_ty(bcx, INIT, cx.fcx.llretptr, val, t).bcx;
4562
        }
4563
        case (_) { /* fall through */  }
4564 4565
    }

4566 4567
    // Run all cleanups and back out.
    let bool more_cleanups = true;
4568
    auto cleanup_cx = cx;
4569
    while (more_cleanups) {
4570
        bcx = trans_block_cleanups(bcx, cleanup_cx);
4571
        alt (cleanup_cx.parent) {
4572
            case (parent_some(?b)) {
4573
                cleanup_cx = b;
4574 4575 4576 4577 4578 4579 4580
            }
            case (parent_none) {
                more_cleanups = false;
            }
        }
    }

4581 4582
    bcx.build.RetVoid();
    ret res(bcx, C_nil());
4583 4584
}

4585
fn trans_be(@block_ctxt cx, @ast.expr e) -> result {
4586
    // FIXME: This should be a typestate precondition
4587
    check (ast.is_call_expr(e));
4588 4589
    // FIXME: Turn this into a real tail call once
    // calling convention issues are settled
4590 4591 4592
    ret trans_ret(cx, some(e));
}

4593 4594 4595 4596 4597 4598 4599 4600 4601
fn init_local(@block_ctxt cx, @ast.local local) -> result {

    // Make a note to drop this slot on the way out.
    check (cx.fcx.lllocals.contains_key(local.id));
    auto llptr = cx.fcx.lllocals.get(local.id);
    auto ty = node_ann_type(cx.fcx.ccx, local.ann);
    auto bcx = cx;

    find_scope_cx(cx).cleanups +=
4602
        vec(clean(bind drop_slot(_, llptr, ty)));
4603 4604 4605 4606

    alt (local.init) {
        case (some[@ast.expr](?e)) {
            auto sub = trans_expr(bcx, e);
4607
            bcx = copy_ty(sub.bcx, INIT, llptr, sub.val, ty).bcx;
4608 4609 4610
        }
        case (_) {
            if (middle.ty.type_has_dynamic_size(ty)) {
4611 4612
                auto llsz = size_of(bcx, ty);
                bcx = call_bzero(llsz.bcx, llptr, llsz.val).bcx;
4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625

            } else {
                auto llty = type_of(bcx.fcx.ccx, ty);
                auto null = lib.llvm.llvm.LLVMConstNull(llty);
                bcx.build.Store(null, llptr);
            }
        }
    }
    ret res(bcx, llptr);
}

fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
    auto bcx = cx;
4626
    alt (s.node) {
4627
        case (ast.stmt_expr(?e)) {
4628
            bcx = trans_expr(cx, e).bcx;
4629
        }
4630

4631 4632 4633
        case (ast.stmt_decl(?d)) {
            alt (d.node) {
                case (ast.decl_local(?local)) {
4634
                    bcx = init_local(bcx, local).bcx;
4635
                }
G
Graydon Hoare 已提交
4636 4637 4638
                case (ast.decl_item(?i)) {
                    trans_item(cx.fcx.ccx, *i);
                }
4639 4640
            }
        }
4641
        case (_) {
4642
            cx.fcx.ccx.sess.unimpl("stmt variant");
4643 4644
        }
    }
4645
    ret res(bcx, C_nil());
4646 4647
}

4648
fn new_builder(BasicBlockRef llbb) -> builder {
4649 4650 4651 4652 4653
    let BuilderRef llbuild = llvm.LLVMCreateBuilder();
    llvm.LLVMPositionBuilderAtEnd(llbuild, llbb);
    ret builder(llbuild);
}

4654 4655
// You probably don't want to use this one. See the
// next three functions instead.
4656
fn new_block_ctxt(@fn_ctxt cx, block_parent parent,
4657
                  block_kind kind,
4658
                  str name) -> @block_ctxt {
4659
    let vec[cleanup] cleanups = vec();
4660
    let BasicBlockRef llbb =
4661
        llvm.LLVMAppendBasicBlock(cx.llfn,
4662
                                  _str.buf(cx.ccx.names.next(name)));
4663

4664
    ret @rec(llbb=llbb,
4665
             build=new_builder(llbb),
4666
             parent=parent,
4667
             kind=kind,
4668
             mutable cleanups=cleanups,
4669 4670 4671
             fcx=cx);
}

4672 4673
// Use this when you're at the top block of a function or the like.
fn new_top_block_ctxt(@fn_ctxt fcx) -> @block_ctxt {
4674 4675 4676 4677 4678 4679 4680
    auto cx = new_block_ctxt(fcx, parent_none, SCOPE_BLOCK,
                             "function top level");

    // FIXME: hack to give us some spill room to make up for an LLVM
    // bug where it destroys its own callee-saves.
    cx.build.Alloca(T_array(T_int(), 10u));
    ret cx;
4681
}
4682

4683 4684
// Use this when you're at a curly-brace or similar lexical scope.
fn new_scope_block_ctxt(@block_ctxt bcx, str n) -> @block_ctxt {
4685
    ret new_block_ctxt(bcx.fcx, parent_some(bcx), SCOPE_BLOCK, n);
4686 4687
}

4688
// Use this when you're making a general CFG BB within a scope.
4689
fn new_sub_block_ctxt(@block_ctxt bcx, str n) -> @block_ctxt {
4690
    ret new_block_ctxt(bcx.fcx, parent_some(bcx), NON_SCOPE_BLOCK, n);
4691
}
4692

4693

4694 4695
fn trans_block_cleanups(@block_ctxt cx,
                        @block_ctxt cleanup_cx) -> @block_ctxt {
4696
    auto bcx = cx;
4697

4698
    if (cleanup_cx.kind != SCOPE_BLOCK) {
4699 4700 4701
        check (_vec.len[cleanup](cleanup_cx.cleanups) == 0u);
    }

4702 4703 4704 4705
    auto i = _vec.len[cleanup](cleanup_cx.cleanups);
    while (i > 0u) {
        i -= 1u;
        auto c = cleanup_cx.cleanups.(i);
4706
        alt (c) {
4707
            case (clean(?cfn)) {
4708
                bcx = cfn(bcx).bcx;
4709 4710 4711
            }
        }
    }
4712 4713 4714
    ret bcx;
}

4715 4716 4717 4718 4719 4720 4721 4722 4723 4724
iter block_locals(&ast.block b) -> @ast.local {
    // FIXME: putting from inside an iter block doesn't work, so we can't
    // use the index here.
    for (@ast.stmt s in b.node.stmts) {
        alt (s.node) {
            case (ast.stmt_decl(?d)) {
                alt (d.node) {
                    case (ast.decl_local(?local)) {
                        put local;
                    }
4725
                    case (_) { /* fall through */ }
4726 4727
                }
            }
4728
            case (_) { /* fall through */ }
4729 4730 4731 4732
        }
    }
}

4733
fn alloc_ty(@block_ctxt cx, @ty.t t) -> result {
4734
    auto val = C_int(0);
4735
    auto bcx = cx;
4736
    if (ty.type_has_dynamic_size(t)) {
4737 4738 4739
        auto n = size_of(bcx, t);
        bcx = n.bcx;
        val = bcx.build.ArrayAlloca(T_i8(), n.val);
4740
    } else {
4741
        val = bcx.build.Alloca(type_of(cx.fcx.ccx, t));
4742
    }
4743
    ret res(bcx, val);
4744 4745
}

4746 4747 4748 4749 4750 4751 4752
fn alloc_local(@block_ctxt cx, @ast.local local) -> result {
    auto t = node_ann_type(cx.fcx.ccx, local.ann);
    auto r = alloc_ty(cx, t);
    r.bcx.fcx.lllocals.insert(local.id, r.val);
    ret r;
}

4753
fn trans_block(@block_ctxt cx, &ast.block b) -> result {
4754 4755
    auto bcx = cx;

4756
    for each (@ast.local local in block_locals(b)) {
4757
        bcx = alloc_local(bcx, local).bcx;
4758
    }
4759
    auto r = res(bcx, C_nil());
4760

4761
    for (@ast.stmt s in b.node.stmts) {
4762 4763
        r = trans_stmt(bcx, *s);
        bcx = r.bcx;
4764 4765 4766 4767 4768
        // If we hit a terminator, control won't go any further so
        // we're in dead-code land. Stop here.
        if (is_terminated(bcx)) {
            ret r;
        }
4769
    }
4770

4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783
    alt (b.node.expr) {
        case (some[@ast.expr](?e)) {
            r = trans_expr(bcx, e);
            bcx = r.bcx;
            if (is_terminated(bcx)) {
                ret r;
            }
        }
        case (none[@ast.expr]) {
            r = res(bcx, C_nil());
        }
    }

4784
    bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
4785
    ret res(bcx, r.val);
4786 4787
}

4788 4789 4790 4791 4792 4793 4794
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args

4795
fn new_fn_ctxt(@crate_ctxt cx,
4796
               ValueRef llfndecl) -> @fn_ctxt {
4797

4798 4799 4800
    let ValueRef llretptr = llvm.LLVMGetParam(llfndecl, 0u);
    let ValueRef lltaskptr = llvm.LLVMGetParam(llfndecl, 1u);
    let ValueRef llenv = llvm.LLVMGetParam(llfndecl, 2u);
4801 4802

    let hashmap[ast.def_id, ValueRef] llargs = new_def_hash[ValueRef]();
4803 4804
    let hashmap[ast.def_id, ValueRef] llobjfields = new_def_hash[ValueRef]();
    let hashmap[ast.def_id, ValueRef] lllocals = new_def_hash[ValueRef]();
4805
    let hashmap[ast.def_id, ValueRef] llupvars = new_def_hash[ValueRef]();
4806
    let hashmap[ast.def_id, ValueRef] lltydescs = new_def_hash[ValueRef]();
4807

4808
    ret @rec(llfn=llfndecl,
4809
             lltaskptr=lltaskptr,
4810 4811
             llenv=llenv,
             llretptr=llretptr,
4812
             mutable llself=none[ValueRef],
4813
             mutable lliterbody=none[ValueRef],
4814
             llargs=llargs,
4815
             llobjfields=llobjfields,
4816
             lllocals=lllocals,
4817
             llupvars=llupvars,
4818
             lltydescs=lltydescs,
4819
             ccx=cx);
4820 4821
}

4822 4823 4824 4825 4826 4827 4828
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args

4829
fn create_llargs_for_fn_args(&@fn_ctxt cx,
4830
                             ast.proto proto,
4831
                             option.t[TypeRef] ty_self,
4832
                             @ty.t ret_ty,
4833
                             &vec[ast.arg] args,
4834
                             &vec[ast.ty_param] ty_params) {
4835 4836 4837 4838 4839 4840 4841 4842 4843 4844

    alt (ty_self) {
        case (some[TypeRef](_)) {
            cx.llself = some[ValueRef](cx.llenv);
        }
        case (_) {
        }
    }

    auto arg_n = 3u;
4845

4846 4847 4848 4849 4850 4851 4852
    if (ty_self == none[TypeRef]) {
        for (ast.ty_param tp in ty_params) {
            auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n);
            check (llarg as int != 0);
            cx.lltydescs.insert(tp.id, llarg);
            arg_n += 1u;
        }
4853 4854
    }

4855
    if (proto == ast.proto_iter) {
4856 4857 4858 4859 4860
        auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n);
        check (llarg as int != 0);
        cx.lliterbody = some[ValueRef](llarg);
        arg_n += 1u;
    }
4861

4862 4863 4864 4865 4866 4867 4868 4869
    for (ast.arg arg in args) {
        auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n);
        check (llarg as int != 0);
        cx.llargs.insert(arg.id, llarg);
        arg_n += 1u;
    }
}

4870 4871 4872 4873
// Recommended LLVM style, strange though this is, is to copy from args to
// allocas immediately upon entry; this permits us to GEP into structures we
// were passed and whatnot. Apparently mem2reg will mop up.

4874 4875 4876 4877
fn copy_args_to_allocas(@block_ctxt cx,
                        option.t[TypeRef] ty_self,
                        vec[ast.arg] args,
                        vec[ty.arg] arg_tys) {
4878 4879 4880

    let uint arg_n = 0u;

4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894
    alt (cx.fcx.llself) {
        case (some[ValueRef](?self_v)) {
            alt (ty_self) {
                case (some[TypeRef](?self_t)) {
                    auto alloca = cx.build.Alloca(self_t);
                    cx.build.Store(self_v, alloca);
                    cx.fcx.llself = some[ValueRef](alloca);
                }
            }
        }
        case (_) {
        }
    }

4895
    for (ast.arg aarg in args) {
4896 4897 4898 4899 4900 4901 4902 4903 4904
        if (aarg.mode != ast.alias) {
            auto arg_t = type_of_arg(cx.fcx.ccx, arg_tys.(arg_n));
            auto alloca = cx.build.Alloca(arg_t);
            auto argval = cx.fcx.llargs.get(aarg.id);
            cx.build.Store(argval, alloca);
            // Overwrite the llargs entry for this arg with its alloca.
            cx.fcx.llargs.insert(aarg.id, alloca);
        }

4905 4906 4907 4908
        arg_n += 1u;
    }
}

4909 4910 4911 4912 4913
fn is_terminated(@block_ctxt cx) -> bool {
    auto inst = llvm.LLVMGetLastInstruction(cx.llbb);
    ret llvm.LLVMIsATerminatorInst(inst) as int != 0;
}

4914 4915
fn arg_tys_of_fn(ast.ann ann) -> vec[ty.arg] {
    alt (ty.ann_to_type(ann).struct) {
4916
        case (ty.ty_fn(_, ?arg_tys, _)) {
4917 4918 4919 4920 4921 4922
            ret arg_tys;
        }
    }
    fail;
}

4923 4924
fn ret_ty_of_fn_ty(@ty.t t) -> @ty.t {
    alt (t.struct) {
4925
        case (ty.ty_fn(_, _, ?ret_ty)) {
4926 4927 4928 4929 4930 4931
            ret ret_ty;
        }
    }
    fail;
}

4932 4933 4934 4935 4936

fn ret_ty_of_fn(ast.ann ann) -> @ty.t {
    ret ret_ty_of_fn_ty(ty.ann_to_type(ann));
}

4937 4938
fn populate_fn_ctxt_from_llself(@block_ctxt cx, ValueRef llself) -> result {
    auto bcx = cx;
4939

4940
    let vec[@ty.t] field_tys = vec();
4941

4942 4943
    for (ast.obj_field f in bcx.fcx.ccx.obj_fields) {
        field_tys += vec(node_ann_type(bcx.fcx.ccx, f.ann));
4944 4945
    }

4946 4947
    // Synthesize a tuple type for the fields so that GEP_tup_like() can work
    // its magic.
4948
    auto fields_tup_ty = ty.plain_tup_ty(field_tys);
4949 4950 4951

    auto n_typarams = _vec.len[ast.ty_param](bcx.fcx.ccx.obj_typarams);
    let TypeRef llobj_box_ty = T_obj_ptr(bcx.fcx.ccx.tn, n_typarams);
4952 4953

    auto box_cell =
4954 4955 4956
        bcx.build.GEP(llself,
                      vec(C_int(0),
                          C_int(abi.obj_field_box)));
4957

4958
    auto box_ptr = bcx.build.Load(box_cell);
4959

4960
    box_ptr = bcx.build.PointerCast(box_ptr, llobj_box_ty);
4961

4962
    auto obj_typarams = bcx.build.GEP(box_ptr,
4963 4964 4965 4966
                                     vec(C_int(0),
                                         C_int(abi.box_rc_field_body),
                                         C_int(abi.obj_body_elt_typarams)));

4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981
    // The object fields immediately follow the type parameters, so we skip
    // over them to get the pointer.
    auto obj_fields = bcx.build.Add(vp2i(bcx, obj_typarams),
        llsize_of(llvm.LLVMGetElementType(val_ty(obj_typarams))));

    // If we can (i.e. the type is statically sized), then cast the resulting
    // fields pointer to the appropriate LLVM type. If not, just leave it as
    // i8 *.
    if (!ty.type_has_dynamic_size(fields_tup_ty)) {
        auto llfields_ty = type_of(bcx.fcx.ccx, fields_tup_ty);
        obj_fields = vi2p(bcx, obj_fields, T_ptr(llfields_ty));
    } else {
        obj_fields = vi2p(bcx, obj_fields, T_ptr(T_i8()));
    }

4982 4983

    let int i = 0;
4984

4985 4986 4987 4988 4989 4990
    for (ast.ty_param p in bcx.fcx.ccx.obj_typarams) {
        let ValueRef lltyparam = bcx.build.GEP(obj_typarams,
                                               vec(C_int(0),
                                                   C_int(i)));
        lltyparam = bcx.build.Load(lltyparam);
        bcx.fcx.lltydescs.insert(p.id, lltyparam);
4991 4992 4993 4994
        i += 1;
    }

    i = 0;
4995 4996 4997 4998
    for (ast.obj_field f in bcx.fcx.ccx.obj_fields) {
        auto rslt = GEP_tup_like(bcx, fields_tup_ty, obj_fields, vec(0, i));
        bcx = rslt.bcx;
        auto llfield = rslt.val;
4999 5000 5001
        cx.fcx.llobjfields.insert(f.id, llfield);
        i += 1;
    }
5002 5003

    ret res(bcx, C_nil());
5004 5005
}

5006 5007 5008
fn trans_fn(@crate_ctxt cx, &ast._fn f, ast.def_id fid,
            option.t[TypeRef] ty_self,
            &vec[ast.ty_param] ty_params, &ast.ann ann) {
5009

5010 5011 5012
    auto llfndecl = cx.item_ids.get(fid);
    cx.item_names.insert(cx.path, llfndecl);

5013
    auto fcx = new_fn_ctxt(cx, llfndecl);
5014
    create_llargs_for_fn_args(fcx, f.proto,
5015
                              ty_self, ret_ty_of_fn(ann),
5016
                              f.decl.inputs, ty_params);
5017
    auto bcx = new_top_block_ctxt(fcx);
5018

5019
    copy_args_to_allocas(bcx, ty_self, f.decl.inputs,
5020 5021 5022 5023
                         arg_tys_of_fn(ann));

    alt (fcx.llself) {
        case (some[ValueRef](?llself)) {
5024
            bcx = populate_fn_ctxt_from_llself(bcx, llself).bcx;
5025 5026 5027 5028
        }
        case (_) {
        }
    }
5029

5030 5031
    auto res = trans_block(bcx, f.body);
    if (!is_terminated(res.bcx)) {
5032 5033
        // FIXME: until LLVM has a unit type, we are moving around
        // C_nil values rather than their void type.
5034
        res.bcx.build.RetVoid();
5035
    }
5036 5037
}

5038 5039 5040
fn trans_vtbl(@crate_ctxt cx, TypeRef self_ty,
              &ast._obj ob,
              &vec[ast.ty_param] ty_params) -> ValueRef {
G
Graydon Hoare 已提交
5041
    let vec[ValueRef] methods = vec();
5042 5043 5044 5045 5046 5047 5048 5049 5050

    fn meth_lteq(&@ast.method a, &@ast.method b) -> bool {
        ret _str.lteq(a.node.ident, b.node.ident);
    }

    auto meths = std.sort.merge_sort[@ast.method](bind meth_lteq(_,_),
                                                  ob.methods);

    for (@ast.method m in meths) {
5051

5052 5053
        auto llfnty = T_nil();
        alt (node_ann_type(cx, m.node.ann).struct) {
5054 5055
            case (ty.ty_fn(?proto, ?inputs, ?output)) {
                llfnty = type_of_fn_full(cx, proto,
5056
                                         some[TypeRef](self_ty),
5057 5058
                                         inputs, output,
                                         _vec.len[ast.ty_param](ty_params));
5059 5060 5061
            }
        }

5062
        let @crate_ctxt mcx = @rec(path=cx.path + sep() + m.node.ident
5063 5064
                                   with *cx);

5065
        let str s = cx.names.next("_rust_method") + sep() + mcx.path;
5066 5067 5068
        let ValueRef llfn = decl_fastcall_fn(cx.llmod, s, llfnty);
        cx.item_ids.insert(m.node.id, llfn);

5069 5070
        trans_fn(mcx, m.node.meth, m.node.id, some[TypeRef](self_ty),
                 ty_params, m.node.ann);
5071
        methods += vec(llfn);
G
Graydon Hoare 已提交
5072
    }
5073 5074 5075
    auto vtbl = C_struct(methods);
    auto gvar = llvm.LLVMAddGlobal(cx.llmod,
                                   val_ty(vtbl),
5076
                                   _str.buf("_rust_vtbl" + sep() + cx.path));
5077 5078
    llvm.LLVMSetInitializer(gvar, vtbl);
    llvm.LLVMSetGlobalConstant(gvar, True);
5079 5080
    llvm.LLVMSetLinkage(gvar, lib.llvm.LLVMPrivateLinkage
                        as llvm.Linkage);
5081
    ret gvar;
G
Graydon Hoare 已提交
5082 5083
}

5084 5085
fn trans_obj(@crate_ctxt cx, &ast._obj ob, ast.def_id oid,
             &vec[ast.ty_param] ty_params, &ast.ann ann) {
5086 5087 5088 5089

    auto llctor_decl = cx.item_ids.get(oid);
    cx.item_names.insert(cx.path, llctor_decl);

5090
    // Translate obj ctor args to function arguments.
5091 5092 5093 5094 5095 5096 5097 5098
    let vec[ast.arg] fn_args = vec();
    for (ast.obj_field f in ob.fields) {
        fn_args += vec(rec(mode=ast.alias,
                           ty=f.ty,
                           ident=f.ident,
                           id=f.id));
    }

5099
    auto fcx = new_fn_ctxt(cx, llctor_decl);
5100
    create_llargs_for_fn_args(fcx, ast.proto_fn,
5101
                              none[TypeRef], ret_ty_of_fn(ann),
5102
                              fn_args, ty_params);
5103 5104 5105

    auto bcx = new_top_block_ctxt(fcx);

5106
    let vec[ty.arg] arg_tys = arg_tys_of_fn(ann);
5107
    copy_args_to_allocas(bcx, none[TypeRef], fn_args, arg_tys);
5108

5109
    auto llself_ty = type_of(cx, ret_ty_of_fn(ann));
5110
    auto pair = bcx.fcx.llretptr;
5111
    auto vtbl = trans_vtbl(cx, llself_ty, ob, ty_params);
5112 5113 5114
    auto pair_vtbl = bcx.build.GEP(pair,
                                   vec(C_int(0),
                                       C_int(abi.obj_field_vtbl)));
5115 5116 5117
    auto pair_box = bcx.build.GEP(pair,
                                  vec(C_int(0),
                                      C_int(abi.obj_field_box)));
5118
    bcx.build.Store(vtbl, pair_vtbl);
5119

5120
    let TypeRef llbox_ty = T_opaque_obj_ptr(cx.tn);
5121 5122 5123 5124

    if (_vec.len[ast.ty_param](ty_params) == 0u &&
        _vec.len[ty.arg](arg_tys) == 0u) {
        // Store null into pair, if no args or typarams.
5125 5126 5127 5128 5129
        bcx.build.Store(C_null(llbox_ty), pair_box);
    } else {
        // Malloc a box for the body and copy args in.
        let vec[@ty.t] obj_fields = vec();
        for (ty.arg a in arg_tys) {
5130
            _vec.push[@ty.t](obj_fields, a.ty);
5131
        }
5132 5133

        // Synthesize an obj body type.
5134 5135 5136
        auto tydesc_ty = plain_ty(ty.ty_type);
        let vec[@ty.t] tps = vec();
        for (ast.ty_param tp in ty_params) {
5137
            _vec.push[@ty.t](tps, tydesc_ty);
5138 5139
        }

5140 5141 5142 5143 5144 5145
        let @ty.t typarams_ty = ty.plain_tup_ty(tps);
        let @ty.t fields_ty = ty.plain_tup_ty(obj_fields);
        let @ty.t body_ty = ty.plain_tup_ty(vec(tydesc_ty,
                                                typarams_ty,
                                                fields_ty));
        let @ty.t boxed_body_ty = ty.plain_box_ty(body_ty);
5146

5147
        // Malloc a box for the body.
5148
        auto box = trans_malloc_boxed(bcx, body_ty);
5149 5150 5151 5152 5153 5154 5155 5156
        bcx = box.bcx;
        auto rc = GEP_tup_like(bcx, boxed_body_ty, box.val,
                               vec(0, abi.box_rc_field_refcnt));
        bcx = rc.bcx;
        auto body = GEP_tup_like(bcx, boxed_body_ty, box.val,
                                 vec(0, abi.box_rc_field_body));
        bcx = body.bcx;
        bcx.build.Store(C_int(1), rc.val);
5157

5158 5159
        // Store body tydesc.
        auto body_tydesc =
5160 5161 5162
            GEP_tup_like(bcx, body_ty, body.val,
                         vec(0, abi.obj_body_elt_tydesc));
        bcx = body_tydesc.bcx;
5163

5164 5165 5166
        auto body_td = get_tydesc(bcx, body_ty);
        bcx = body_td.bcx;
        bcx.build.Store(body_td.val, body_tydesc.val);
5167

5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182
        // Copy typarams into captured typarams.
        auto body_typarams =
            GEP_tup_like(bcx, body_ty, body.val,
                         vec(0, abi.obj_body_elt_typarams));
        bcx = body_typarams.bcx;
        let int i = 0;
        for (ast.ty_param tp in ty_params) {
            auto typaram = bcx.fcx.lltydescs.get(tp.id);
            auto capture = GEP_tup_like(bcx, typarams_ty, body_typarams.val,
                                        vec(0, i));
            bcx = capture.bcx;
            bcx = copy_ty(bcx, INIT, capture.val, typaram, tydesc_ty).bcx;
            i += 1;
        }

5183 5184
        // Copy args into body fields.
        auto body_fields =
5185 5186 5187
            GEP_tup_like(bcx, body_ty, body.val,
                         vec(0, abi.obj_body_elt_fields));
        bcx = body_fields.bcx;
5188

5189
        i = 0;
5190
        for (ast.obj_field f in ob.fields) {
5191 5192
            auto arg = bcx.fcx.llargs.get(f.id);
            arg = load_scalar_or_boxed(bcx, arg, arg_tys.(i).ty);
5193 5194 5195 5196
            auto field = GEP_tup_like(bcx, fields_ty, body_fields.val,
                                      vec(0, i));
            bcx = field.bcx;
            bcx = copy_ty(bcx, INIT, field.val, arg, arg_tys.(i).ty).bcx;
5197 5198 5199
            i += 1;
        }
        // Store box ptr in outer pair.
5200
        auto p = bcx.build.PointerCast(box.val, llbox_ty);
5201
        bcx.build.Store(p, pair_box);
5202
    }
5203
    bcx.build.RetVoid();
5204 5205
}

5206
fn trans_tag_variant(@crate_ctxt cx, ast.def_id tag_id,
5207 5208
                     &ast.variant variant, int index,
                     &vec[ast.ty_param] ty_params) {
5209
    if (_vec.len[ast.variant_arg](variant.args) == 0u) {
5210 5211 5212
        ret;    // nullary constructors are just constants
    }

5213 5214 5215 5216 5217 5218 5219 5220 5221 5222
    // Translate variant arguments to function arguments.
    let vec[ast.arg] fn_args = vec();
    auto i = 0u;
    for (ast.variant_arg varg in variant.args) {
        fn_args += vec(rec(mode=ast.alias,
                           ty=varg.ty,
                           ident="arg" + _uint.to_str(i, 10u),
                           id=varg.id));
    }

5223
    check (cx.item_ids.contains_key(variant.id));
5224 5225
    let ValueRef llfndecl = cx.item_ids.get(variant.id);

5226
    auto fcx = new_fn_ctxt(cx, llfndecl);
5227
    create_llargs_for_fn_args(fcx, ast.proto_fn,
5228
                              none[TypeRef], ret_ty_of_fn(variant.ann),
5229
                              fn_args, ty_params);
5230

5231 5232 5233 5234 5235
    let vec[@ty.t] ty_param_substs = vec();
    for (ast.ty_param tp in ty_params) {
        ty_param_substs += vec(plain_ty(ty.ty_param(tp.id)));
    }

5236 5237 5238
    auto bcx = new_top_block_ctxt(fcx);

    auto arg_tys = arg_tys_of_fn(variant.ann);
5239
    copy_args_to_allocas(bcx, none[TypeRef], fn_args, arg_tys);
5240

5241 5242 5243 5244 5245
    // Cast the tag to a type we can GEP into.
    auto lltagptr = bcx.build.PointerCast(fcx.llretptr,
                                          T_opaque_tag_ptr(fcx.ccx.tn));

    auto lldiscrimptr = bcx.build.GEP(lltagptr,
5246
                                      vec(C_int(0), C_int(0)));
5247 5248
    bcx.build.Store(C_int(index), lldiscrimptr);

5249
    auto llblobptr = bcx.build.GEP(lltagptr,
5250
                                   vec(C_int(0), C_int(1)));
5251 5252 5253

    i = 0u;
    for (ast.variant_arg va in variant.args) {
5254 5255
        auto rslt = GEP_tag(bcx, llblobptr, tag_id, variant.id,
                            ty_param_substs, i as int);
5256 5257
        bcx = rslt.bcx;
        auto lldestptr = rslt.val;
5258

5259 5260 5261 5262 5263 5264
        // 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.
        auto llargptr = bcx.build.PointerCast(fcx.llargs.get(va.id),
            val_ty(lldestptr));

5265 5266
        auto arg_ty = arg_tys.(i).ty;
        auto llargval;
5267 5268
        if (ty.type_is_structural(arg_ty) ||
                ty.type_has_dynamic_size(arg_ty)) {
5269 5270 5271 5272 5273 5274 5275 5276
            llargval = llargptr;
        } else {
            llargval = bcx.build.Load(llargptr);
        }

        rslt = copy_ty(bcx, INIT, lldestptr, llargval, arg_ty);
        bcx = rslt.bcx;

5277 5278 5279 5280
        i += 1u;
    }

    bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
5281
    bcx.build.RetVoid();
5282 5283
}

5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299
// 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?

fn trans_const_expr(@crate_ctxt cx, @ast.expr e) -> ValueRef {
    alt (e.node) {
        case (ast.expr_lit(?lit, ?ann)) {
            ret trans_lit(cx, *lit, ann);
        }
    }
}

fn trans_const(@crate_ctxt cx, @ast.expr e,
               &ast.def_id cid, &ast.ann ann) {
    auto t = node_ann_type(cx, ann);
    auto v = trans_const_expr(cx, e);
5300 5301 5302 5303 5304 5305

    // The scalars come back as 1st class LLVM vals
    // which we have to stick into global constants.
    auto g = cx.consts.get(cid);
    llvm.LLVMSetInitializer(g, v);
    llvm.LLVMSetGlobalConstant(g, True);
5306 5307
}

5308
fn trans_item(@crate_ctxt cx, &ast.item item) {
5309
    alt (item.node) {
5310
        case (ast.item_fn(?name, ?f, ?tps, ?fid, ?ann)) {
5311
            auto sub_cx = @rec(path=cx.path + sep() + name with *cx);
5312
            trans_fn(sub_cx, f, fid, none[TypeRef], tps, ann);
5313
        }
5314
        case (ast.item_obj(?name, ?ob, ?tps, ?oid, ?ann)) {
5315
            auto sub_cx = @rec(path=cx.path + sep() + name,
5316
                               obj_typarams=tps,
5317
                               obj_fields=ob.fields with *cx);
5318
            trans_obj(sub_cx, ob, oid, tps, ann);
5319
        }
5320
        case (ast.item_mod(?name, ?m, _)) {
5321
            auto sub_cx = @rec(path=cx.path + sep() + name with *cx);
5322
            trans_mod(sub_cx, m);
5323
        }
5324
        case (ast.item_tag(?name, ?variants, ?tps, ?tag_id)) {
5325
            auto sub_cx = @rec(path=cx.path + sep() + name with *cx);
5326
            auto i = 0;
5327
            for (ast.variant variant in variants) {
5328
                trans_tag_variant(sub_cx, tag_id, variant, i, tps);
5329
                i += 1;
5330 5331
            }
        }
5332
        case (ast.item_const(?name, _, ?expr, ?cid, ?ann)) {
5333
            auto sub_cx = @rec(path=cx.path + sep() + name with *cx);
5334 5335
            trans_const(sub_cx, expr, cid, ann);
        }
5336
        case (_) { /* fall through */ }
5337 5338 5339
    }
}

5340
fn trans_mod(@crate_ctxt cx, &ast._mod m) {
5341 5342
    for (@ast.item item in m.items) {
        trans_item(cx, *item);
5343 5344 5345
    }
}

5346 5347 5348 5349 5350 5351 5352 5353
fn get_pair_fn_ty(TypeRef llpairty) -> TypeRef {
    // Bit of a kludge: pick the fn typeref out of the pair.
    let vec[TypeRef] pair_tys = vec(T_nil(), T_nil());
    llvm.LLVMGetStructElementTypes(llpairty,
                                   _vec.buf[TypeRef](pair_tys));
    ret llvm.LLVMGetElementType(pair_tys.(0));
}

5354 5355 5356
fn decl_fn_and_pair(@crate_ctxt cx,
                    str kind,
                    str name,
5357
                    vec[ast.ty_param] ty_params,
5358 5359 5360
                    &ast.ann ann,
                    ast.def_id id) {

5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373
    auto llfty;
    auto llpairty;
    alt (node_ann_type(cx, ann).struct) {
        case (ty.ty_fn(?proto, ?inputs, ?output)) {
            llfty = type_of_fn(cx, proto, inputs, output,
                               _vec.len[ast.ty_param](ty_params));
            llpairty = T_fn_pair(cx.tn, llfty);
        }
        case (_) {
            cx.sess.bug("decl_fn_and_pair(): fn item doesn't have fn type?!");
            fail;
        }
    }
5374 5375

    // Declare the function itself.
5376
    let str s = cx.names.next("_rust_" + kind) + sep() + name;
5377 5378 5379
    let ValueRef llfn = decl_fastcall_fn(cx.llmod, s, llfty);

    // Declare the global constant pair that points to it.
5380
    let str ps = cx.names.next("_rust_" + kind + "_pair") + sep() + name;
5381 5382 5383 5384 5385 5386

    register_fn_pair(cx, ps, llpairty, llfn, id);
}

fn register_fn_pair(@crate_ctxt cx, str ps, TypeRef llpairty, ValueRef llfn,
                    ast.def_id id) {
5387 5388 5389
    let ValueRef gvar = llvm.LLVMAddGlobal(cx.llmod, llpairty,
                                           _str.buf(ps));
    auto pair = C_struct(vec(llfn,
5390
                             C_null(T_opaque_closure_ptr(cx.tn))));
5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401

    llvm.LLVMSetInitializer(gvar, pair);
    llvm.LLVMSetGlobalConstant(gvar, True);
    llvm.LLVMSetLinkage(gvar,
                        lib.llvm.LLVMPrivateLinkage
                        as llvm.Linkage);

    cx.item_ids.insert(id, llfn);
    cx.fn_pairs.insert(id, gvar);
}

5402 5403 5404 5405 5406 5407 5408 5409 5410 5411
// Returns the number of type parameters that the given native function has.
fn native_fn_ty_param_count(@crate_ctxt cx, &ast.def_id id) -> uint {
    auto count;
    auto native_item = cx.native_items.get(id);
    alt (native_item.node) {
        case (ast.native_item_ty(_,_)) {
            cx.sess.bug("decl_native_fn_and_pair(): native fn isn't " +
                        "actually a fn?!");
            fail;
        }
5412
        case (ast.native_item_fn(_, _, _, ?tps, _, _)) {
5413 5414 5415 5416 5417 5418 5419 5420
            count = _vec.len[ast.ty_param](tps);
        }
    }
    ret count;
}

fn native_fn_wrapper_type(@crate_ctxt cx, uint ty_param_count, &ast.ann ann)
        -> TypeRef {
5421 5422 5423
    auto x = node_ann_type(cx, ann);
    alt (x.struct) {
        case (ty.ty_native_fn(?abi, ?args, ?out)) {
5424
            ret type_of_fn(cx, ast.proto_fn, args, out, ty_param_count);
5425 5426 5427 5428 5429
        }
    }
    fail;
}

5430 5431 5432 5433
fn decl_native_fn_and_pair(@crate_ctxt cx,
                           str name,
                           &ast.ann ann,
                           ast.def_id id) {
5434 5435
    auto num_ty_param = native_fn_ty_param_count(cx, id);

5436
    // Declare the wrapper.
5437
    auto wrapper_type = native_fn_wrapper_type(cx, num_ty_param, ann);
5438 5439
    let str s = cx.names.next("_rust_wrapper") + sep() + name;
    let ValueRef wrapper_fn = decl_fastcall_fn(cx.llmod, s, wrapper_type);
5440

5441 5442 5443
    // Declare the global constant pair that points to it.
    auto wrapper_pair_type = T_fn_pair(cx.tn, wrapper_type);
    let str ps = cx.names.next("_rust_wrapper_pair") + sep() + name;
5444

5445 5446
    register_fn_pair(cx, ps, wrapper_pair_type, wrapper_fn, id);

5447 5448 5449 5450
    // Build the wrapper.
    auto fcx = new_fn_ctxt(cx, wrapper_fn);
    auto bcx = new_top_block_ctxt(fcx);

5451 5452 5453 5454
    // Declare the function itself.
    auto item = cx.native_items.get(id);
    auto fn_type = node_ann_type(cx, ann);  // NB: has no type params

5455
    auto abi = ty.ty_fn_abi(fn_type);
5456 5457
    auto llfnty = type_of_native_fn(cx, abi, ty.ty_fn_args(fn_type),
                                    ty.ty_fn_ret(fn_type), num_ty_param);
5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470

    // We can only declare a native function with a given name once; LLVM
    // unhelpfully mangles the names if we try to multiply declare one.
    auto function;
    if (!cx.native_fns.contains_key(name)) {
        function = decl_cdecl_fn(cx.llmod, name, llfnty);
        cx.native_fns.insert(name, function);
    } else {
        // We support type-punning a native function by giving it different
        // Rust types.
        auto llorigfn = cx.native_fns.get(name);
        function = bcx.build.PointerCast(llorigfn, T_ptr(llfnty));
    }
5471 5472

    let vec[ValueRef] call_args = vec();
5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493
    auto arg_n = 3u;
    alt (abi) {
        case (ast.native_abi_rust) {
            call_args += vec(fcx.lltaskptr);
            for each (uint i in _uint.range(0u, num_ty_param)) {
                auto llarg = llvm.LLVMGetParam(fcx.llfn, arg_n);
                check (llarg as int != 0);
                call_args += vec(llarg);
                arg_n += 1u;
            }
        }
        case (ast.native_abi_cdecl) {
        }
    }
    auto args = ty.ty_fn_args(fn_type);
    for (ty.arg arg in args) {
        auto llarg = llvm.LLVMGetParam(fcx.llfn, arg_n);
        check (llarg as int != 0);
        call_args += vec(llarg);
        arg_n += 1u;
    }
5494

5495 5496 5497
    auto r = bcx.build.Call(function, call_args);
    bcx.build.Store(r, fcx.llretptr);
    bcx.build.RetVoid();
5498 5499
}

5500 5501
fn collect_native_item(&@crate_ctxt cx, @ast.native_item i) -> @crate_ctxt {
    alt (i.node) {
5502
        case (ast.native_item_fn(?name, _, _, _, ?fid, ?ann)) {
5503 5504
            cx.native_items.insert(fid, i);
            if (! cx.obj_methods.contains_key(fid)) {
5505
                decl_native_fn_and_pair(cx, name, ann, fid);
5506 5507 5508 5509 5510 5511
            }
        }
        case (_) { /* fall through */ }
    }
    ret cx;
}
5512

5513
fn collect_item(&@crate_ctxt cx, @ast.item i) -> @crate_ctxt {
5514

5515
    alt (i.node) {
5516 5517 5518 5519 5520 5521
        case (ast.item_const(?name, _, _, ?cid, ?ann)) {
            auto typ = node_ann_type(cx, ann);
            auto g = llvm.LLVMAddGlobal(cx.llmod, type_of(cx, typ),
                                        _str.buf(cx.names.next(name)));
            llvm.LLVMSetLinkage(g, lib.llvm.LLVMPrivateLinkage
                                as llvm.Linkage);
5522
            cx.items.insert(cid, i);
5523
            cx.consts.insert(cid, g);
5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539
        }

        case (ast.item_mod(?name, ?m, ?mid)) {
            cx.items.insert(mid, i);
        }

        case (ast.item_tag(_, ?variants, ?tps, ?tag_id)) {
            cx.items.insert(tag_id, i);
        }

        case (_) { /* fall through */ }
    }
    ret cx;
}

fn collect_item_pass2(&@crate_ctxt cx, @ast.item i) -> @crate_ctxt {
5540
    alt (i.node) {
5541
        case (ast.item_fn(?name, ?f, ?tps, ?fid, ?ann)) {
5542
            cx.items.insert(fid, i);
5543
            if (! cx.obj_methods.contains_key(fid)) {
5544
                decl_fn_and_pair(cx, "fn", name, tps, ann, fid);
5545
            }
5546 5547
        }

5548
        case (ast.item_obj(?name, ?ob, ?tps, ?oid, ?ann)) {
5549
            cx.items.insert(oid, i);
5550
            decl_fn_and_pair(cx, "obj_ctor", name, tps, ann, oid);
5551 5552 5553
            for (@ast.method m in ob.methods) {
                cx.obj_methods.insert(m.node.id, ());
            }
5554 5555
        }

5556
        case (_) { /* fall through */ }
5557 5558 5559 5560 5561
    }
    ret cx;
}


5562
fn collect_items(@crate_ctxt cx, @ast.crate crate) {
5563

5564 5565
    let fold.ast_fold[@crate_ctxt] fld =
        fold.new_identity_fold[@crate_ctxt]();
5566

5567 5568
    // FIXME: It might be better to use a worklist for this. An item
    // would be added to it if it depends on a not yet seen tag for example.
5569 5570 5571 5572 5573 5574 5575 5576 5577 5578

    auto fld1 =
        @rec( update_env_for_item = bind collect_item(_,_),
              update_env_for_native_item = bind collect_native_item(_,_)
              with *fld );

    fold.fold_crate[@crate_ctxt](cx, fld1, crate);

    auto fld2 = @rec( update_env_for_item = bind collect_item_pass2(_,_)
                      with *fld );
5579

5580
    fold.fold_crate[@crate_ctxt](cx, fld2, crate);
5581 5582
}

5583 5584 5585 5586
fn collect_tag_ctor(&@crate_ctxt cx, @ast.item i) -> @crate_ctxt {

    alt (i.node) {

5587
        case (ast.item_tag(_, ?variants, ?tps, _)) {
5588 5589 5590
            for (ast.variant variant in variants) {
                if (_vec.len[ast.variant_arg](variant.args) != 0u) {
                    decl_fn_and_pair(cx, "tag", variant.name,
5591
                                     tps, variant.ann, variant.id);
5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612
                }
            }
        }

        case (_) { /* fall through */ }
    }
    ret cx;
}

fn collect_tag_ctors(@crate_ctxt cx, @ast.crate crate) {

    let fold.ast_fold[@crate_ctxt] fld =
        fold.new_identity_fold[@crate_ctxt]();

    fld = @rec( update_env_for_item = bind collect_tag_ctor(_,_)
                with *fld );

    fold.fold_crate[@crate_ctxt](cx, fld, crate);
}


5613 5614 5615 5616 5617 5618
// The constant translation pass.

fn trans_constant(&@crate_ctxt cx, @ast.item it) -> @crate_ctxt {
    alt (it.node) {
        case (ast.item_tag(_, ?variants, _, ?tag_id)) {
            auto i = 0u;
5619 5620 5621
            auto n_variants = _vec.len[ast.variant](variants);
            while (i < n_variants) {
                auto variant = variants.(i);
5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635

                auto discrim_val = C_int(i as int);

                // FIXME: better name.
                auto discrim_gvar = llvm.LLVMAddGlobal(cx.llmod, T_int(),
                    _str.buf("tag_discrim"));

                // FIXME: Eventually we do want to export these, but we need
                // to figure out what name they get first!
                llvm.LLVMSetInitializer(discrim_gvar, discrim_val);
                llvm.LLVMSetGlobalConstant(discrim_gvar, True);
                llvm.LLVMSetLinkage(discrim_gvar, lib.llvm.LLVMPrivateLinkage
                                    as llvm.Linkage);

5636
                cx.discrims.insert(variant.id, discrim_gvar);
5637 5638 5639 5640

                i += 1u;
            }
        }
5641 5642 5643 5644 5645 5646 5647 5648

        case (ast.item_const(?name, _, ?expr, ?cid, ?ann)) {
            // FIXME: The whole expr-translation system needs cloning to deal
            // with consts.
            auto v = C_int(1);
            cx.item_ids.insert(cid, v);
        }

5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665
        case (_) {
            // empty
        }
    }

    ret cx;
}

fn trans_constants(@crate_ctxt cx, @ast.crate crate) {
    let fold.ast_fold[@crate_ctxt] fld =
        fold.new_identity_fold[@crate_ctxt]();

    fld = @rec(update_env_for_item = bind trans_constant(_,_) with *fld);

    fold.fold_crate[@crate_ctxt](cx, fld, crate);
}

5666 5667 5668 5669 5670 5671 5672 5673 5674 5675

fn vp2i(@block_ctxt cx, ValueRef v) -> ValueRef {
    ret cx.build.PtrToInt(v, T_int());
}


fn vi2p(@block_ctxt cx, ValueRef v, TypeRef t) -> ValueRef {
    ret cx.build.IntToPtr(v, t);
}

5676 5677 5678 5679
fn p2i(ValueRef v) -> ValueRef {
    ret llvm.LLVMConstPtrToInt(v, T_int());
}

5680 5681 5682 5683
fn i2p(ValueRef v, TypeRef t) -> ValueRef {
    ret llvm.LLVMConstIntToPtr(v, t);
}

5684 5685 5686
fn trans_exit_task_glue(@glue_fns glues,
                        &hashmap[str, ValueRef] upcalls,
                        type_names tn, ModuleRef llmod) {
5687 5688 5689
    let vec[TypeRef] T_args = vec();
    let vec[ValueRef] V_args = vec();

5690
    auto llfn = glues.exit_task_glue;
5691
    let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 3u);
5692

5693 5694 5695 5696 5697 5698
    auto entrybb = llvm.LLVMAppendBasicBlock(llfn, _str.buf("entry"));
    auto build = new_builder(entrybb);

    trans_upcall2(build, glues, lltaskptr,
                  upcalls, tn, llmod, "upcall_exit", V_args);
    build.RetVoid();
5699 5700
}

5701
fn create_typedefs(@crate_ctxt cx) {
5702 5703 5704
    llvm.LLVMAddTypeName(cx.llmod, _str.buf("crate"), T_crate(cx.tn));
    llvm.LLVMAddTypeName(cx.llmod, _str.buf("task"), T_task(cx.tn));
    llvm.LLVMAddTypeName(cx.llmod, _str.buf("tydesc"), T_tydesc(cx.tn));
5705 5706
}

5707
fn create_crate_constant(ValueRef crate_ptr, @glue_fns glues) {
5708

5709
    let ValueRef crate_addr = p2i(crate_ptr);
5710 5711

    let ValueRef activate_glue_off =
5712
        llvm.LLVMConstSub(p2i(glues.activate_glue), crate_addr);
5713 5714

    let ValueRef yield_glue_off =
5715
        llvm.LLVMConstSub(p2i(glues.yield_glue), crate_addr);
5716

5717
    let ValueRef exit_task_glue_off =
5718
        llvm.LLVMConstSub(p2i(glues.exit_task_glue), crate_addr);
5719 5720 5721

    let ValueRef crate_val =
        C_struct(vec(C_null(T_int()),     // ptrdiff_t image_base_off
5722
                     p2i(crate_ptr),   // uintptr_t self_addr
5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733
                     C_null(T_int()),     // ptrdiff_t debug_abbrev_off
                     C_null(T_int()),     // size_t debug_abbrev_sz
                     C_null(T_int()),     // ptrdiff_t debug_info_off
                     C_null(T_int()),     // size_t debug_info_sz
                     activate_glue_off,   // size_t activate_glue_off
                     yield_glue_off,      // size_t yield_glue_off
                     C_null(T_int()),     // size_t unwind_glue_off
                     C_null(T_int()),     // size_t gc_glue_off
                     exit_task_glue_off,  // size_t main_exit_task_glue_off
                     C_null(T_int()),     // int n_rust_syms
                     C_null(T_int()),     // int n_c_syms
5734 5735
                     C_null(T_int()),     // int n_libs
                     C_int(abi.abi_x86_rustc_fastcall) // uintptr_t abi_tag
5736 5737
                     ));

5738
    llvm.LLVMSetInitializer(crate_ptr, crate_val);
5739 5740
}

5741 5742 5743 5744
fn find_main_fn(@crate_ctxt cx) -> ValueRef {
    auto e = sep() + "main";
    let ValueRef v = C_nil();
    let uint n = 0u;
5745
    for each (@tup(str,ValueRef) i in cx.item_names.items()) {
5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764
        if (_str.ends_with(i._0, e)) {
            n += 1u;
            v = i._1;
        }
    }
    alt (n) {
        case (0u) {
            cx.sess.err("main fn not found");
        }
        case (1u) {
            ret v;
        }
        case (_) {
            cx.sess.err("multiple main fns found");
        }
    }
    fail;
}

5765
fn trans_main_fn(@crate_ctxt cx, ValueRef llcrate) {
5766 5767 5768
    auto T_main_args = vec(T_int(), T_int());
    auto T_rust_start_args = vec(T_int(), T_int(), T_int(), T_int());

5769 5770 5771 5772 5773 5774 5775
    auto main_name;
    if (_str.eq(std.os.target_os(), "win32")) {
        main_name = "WinMain@16";
    } else {
        main_name = "main";
    }

5776
    auto llmain =
5777
        decl_cdecl_fn(cx.llmod, main_name, T_fn(T_main_args, T_int()));
5778

5779 5780
    auto llrust_start = decl_cdecl_fn(cx.llmod, "rust_start",
                                      T_fn(T_rust_start_args, T_int()));
5781 5782 5783

    auto llargc = llvm.LLVMGetParam(llmain, 0u);
    auto llargv = llvm.LLVMGetParam(llmain, 1u);
5784
    auto llrust_main = find_main_fn(cx);
5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795

    //
    // Emit the moral equivalent of:
    //
    // main(int argc, char **argv) {
    //     rust_start(&_rust.main, &crate, argc, argv);
    // }
    //

    let BasicBlockRef llbb =
        llvm.LLVMAppendBasicBlock(llmain, _str.buf(""));
5796
    auto b = new_builder(llbb);
5797 5798 5799 5800 5801 5802

    auto start_args = vec(p2i(llrust_main), p2i(llcrate), llargc, llargv);

    b.Ret(b.Call(llrust_start, start_args));
}

5803 5804
fn declare_intrinsics(ModuleRef llmod) -> hashmap[str,ValueRef] {

5805
    let vec[TypeRef] T_trap_args = vec();
5806 5807 5808 5809 5810 5811
    auto trap = decl_cdecl_fn(llmod, "llvm.trap",
                              T_fn(T_trap_args, T_void()));

    auto intrinsics = new_str_hash[ValueRef]();
    intrinsics.insert("llvm.trap", trap);
    ret intrinsics;
5812 5813
}

5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831

fn trace_str(@block_ctxt cx, str s) {
    trans_upcall(cx, "upcall_trace_str", vec(p2i(C_cstr(cx.fcx.ccx, s))));
}

fn trace_word(@block_ctxt cx, ValueRef v) {
    trans_upcall(cx, "upcall_trace_word", vec(v));
}

fn trace_ptr(@block_ctxt cx, ValueRef v) {
    trace_word(cx, cx.build.PtrToInt(v, T_int()));
}

fn trap(@block_ctxt bcx) {
    let vec[ValueRef] v = vec();
    bcx.build.Call(bcx.fcx.ccx.intrinsics.get("llvm.trap"), v);
}

5832 5833 5834 5835 5836 5837 5838 5839
fn check_module(ModuleRef llmod) {
    auto pm = mk_pass_manager();
    llvm.LLVMAddVerifierPass(pm.llpm);
    llvm.LLVMRunPassManager(pm.llpm, llmod);

    // TODO: run the linter here also, once there are llvm-c bindings for it.
}

5840
fn decl_no_op_type_glue(ModuleRef llmod, type_names tn) -> ValueRef {
5841
    auto ty = T_fn(vec(T_taskptr(tn), T_ptr(T_i8())), T_void());
5842 5843 5844 5845
    ret decl_fastcall_fn(llmod, abi.no_op_type_glue_name(), ty);
}

fn make_no_op_type_glue(ValueRef fun) {
5846 5847
    auto bb_name = _str.buf("_rust_no_op_type_glue_bb");
    auto llbb = llvm.LLVMAppendBasicBlock(fun, bb_name);
5848
    new_builder(llbb).RetVoid();
5849 5850
}

5851
fn decl_memcpy_glue(ModuleRef llmod) -> ValueRef {
5852 5853 5854
    auto p8 = T_ptr(T_i8());

    auto ty = T_fn(vec(p8, p8, T_int()), T_void());
5855 5856
    ret decl_fastcall_fn(llmod, abi.memcpy_glue_name(), ty);
}
5857

5858 5859 5860 5861
fn make_memcpy_glue(ValueRef fun) {
    // We're not using the LLVM memcpy intrinsic. It appears to call through
    // to the platform memcpy in some cases, which is not terribly safe to run
    // on a rust stack.
5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894
    auto initbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("init"));
    auto hdrbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("hdr"));
    auto loopbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("loop"));
    auto endbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("end"));

    auto dst = llvm.LLVMGetParam(fun, 0u);
    auto src = llvm.LLVMGetParam(fun, 1u);
    auto count = llvm.LLVMGetParam(fun, 2u);

    // Init block.
    auto ib = new_builder(initbb);
    auto ip = ib.Alloca(T_int());
    ib.Store(C_int(0), ip);
    ib.Br(hdrbb);

    // Loop-header block
    auto hb = new_builder(hdrbb);
    auto i = hb.Load(ip);
    hb.CondBr(hb.ICmp(lib.llvm.LLVMIntEQ, count, i), endbb, loopbb);

    // Loop-body block
    auto lb = new_builder(loopbb);
    i = lb.Load(ip);
    lb.Store(lb.Load(lb.GEP(src, vec(i))),
             lb.GEP(dst, vec(i)));
    lb.Store(lb.Add(i, C_int(1)), ip);
    lb.Br(hdrbb);

    // End block
    auto eb = new_builder(endbb);
    eb.RetVoid();
}

5895
fn decl_bzero_glue(ModuleRef llmod) -> ValueRef {
5896 5897 5898
    auto p8 = T_ptr(T_i8());

    auto ty = T_fn(vec(p8, T_int()), T_void());
5899 5900
    ret decl_fastcall_fn(llmod, abi.bzero_glue_name(), ty);
}
5901

5902 5903 5904
fn make_bzero_glue(ModuleRef llmod) -> ValueRef {
    // We're not using the LLVM memset intrinsic. Same as with memcpy.
    auto fun = decl_bzero_glue(llmod);
5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936
    auto initbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("init"));
    auto hdrbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("hdr"));
    auto loopbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("loop"));
    auto endbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("end"));

    auto dst = llvm.LLVMGetParam(fun, 0u);
    auto count = llvm.LLVMGetParam(fun, 1u);

    // Init block.
    auto ib = new_builder(initbb);
    auto ip = ib.Alloca(T_int());
    ib.Store(C_int(0), ip);
    ib.Br(hdrbb);

    // Loop-header block
    auto hb = new_builder(hdrbb);
    auto i = hb.Load(ip);
    hb.CondBr(hb.ICmp(lib.llvm.LLVMIntEQ, count, i), endbb, loopbb);

    // Loop-body block
    auto lb = new_builder(loopbb);
    i = lb.Load(ip);
    lb.Store(C_integral(0, T_i8()), lb.GEP(dst, vec(i)));
    lb.Store(lb.Add(i, C_int(1)), ip);
    lb.Br(hdrbb);

    // End block
    auto eb = new_builder(endbb);
    eb.RetVoid();
    ret fun;
}

5937
fn make_vec_append_glue(ModuleRef llmod, type_names tn) -> ValueRef {
5938
    /*
5939
     * Args to vec_append_glue:
5940 5941 5942 5943 5944 5945 5946 5947 5948 5949
     *
     *   0. (Implicit) task ptr
     *
     *   1. Pointer to the tydesc of the vec, so that we can tell if it's gc
     *      mem, and have a tydesc to pass to malloc if we're allocating anew.
     *
     *   2. Pointer to the tydesc of the vec's stored element type, so that
     *      elements can be copied to a newly alloc'ed vec if one must be
     *      created.
     *
5950
     *   3. Dst vec ptr (i.e. ptr to ptr to rust_vec).
5951 5952
     *
     *   4. Src vec (i.e. ptr to rust_vec).
5953
     *
5954
     *   5. Flag indicating whether to skip trailing null on dst.
5955 5956 5957 5958 5959 5960
     *
     */

    auto ty = T_fn(vec(T_taskptr(tn),
                       T_ptr(T_tydesc(tn)),
                       T_ptr(T_tydesc(tn)),
5961 5962 5963
                       T_ptr(T_opaque_vec_ptr()),
                       T_opaque_vec_ptr(), T_bool()),
                   T_void());
5964

5965
    auto llfn = decl_fastcall_fn(llmod, abi.vec_append_glue_name(), ty);
5966 5967 5968
    ret llfn;
}

5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007

fn vec_fill(@block_ctxt bcx, ValueRef v) -> ValueRef {
    ret bcx.build.Load(bcx.build.GEP(v, vec(C_int(0),
                                            C_int(abi.vec_elt_fill))));
}

fn put_vec_fill(@block_ctxt bcx, ValueRef v, ValueRef fill) -> ValueRef {
    ret bcx.build.Store(fill,
                        bcx.build.GEP(v,
                                      vec(C_int(0),
                                          C_int(abi.vec_elt_fill))));
}

fn vec_fill_adjusted(@block_ctxt bcx, ValueRef v,
                     ValueRef skipnull) -> ValueRef {
    auto f = bcx.build.Load(bcx.build.GEP(v,
                                          vec(C_int(0),
                                              C_int(abi.vec_elt_fill))));
    ret bcx.build.Select(skipnull, bcx.build.Sub(f, C_int(1)), f);
}

fn vec_p0(@block_ctxt bcx, ValueRef v) -> ValueRef {
    auto p = bcx.build.GEP(v, vec(C_int(0),
                                  C_int(abi.vec_elt_data)));
    ret bcx.build.PointerCast(p, T_ptr(T_i8()));
}


fn vec_p1(@block_ctxt bcx, ValueRef v) -> ValueRef {
    auto len = vec_fill(bcx, v);
    ret bcx.build.GEP(vec_p0(bcx, v), vec(len));
}

fn vec_p1_adjusted(@block_ctxt bcx, ValueRef v,
                   ValueRef skipnull) -> ValueRef {
    auto len = vec_fill_adjusted(bcx, v, skipnull);
    ret bcx.build.GEP(vec_p0(bcx, v), vec(len));
}

6008
fn trans_vec_append_glue(@crate_ctxt cx) {
6009

6010
    auto llfn = cx.glues.vec_append_glue;
6011 6012 6013 6014

    let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 0u);
    let ValueRef llvec_tydesc = llvm.LLVMGetParam(llfn, 1u);
    let ValueRef llelt_tydesc = llvm.LLVMGetParam(llfn, 2u);
6015 6016 6017
    let ValueRef lldst_vec_ptr = llvm.LLVMGetParam(llfn, 3u);
    let ValueRef llsrc_vec = llvm.LLVMGetParam(llfn, 4u);
    let ValueRef llskipnull = llvm.LLVMGetParam(llfn, 5u);
6018 6019 6020 6021 6022 6023 6024 6025 6026 6027

    auto fcx = @rec(llfn=llfn,
                    lltaskptr=lltaskptr,
                    llenv=C_null(T_ptr(T_nil())),
                    llretptr=C_null(T_ptr(T_nil())),
                    mutable llself=none[ValueRef],
                    mutable lliterbody=none[ValueRef],
                    llargs=new_def_hash[ValueRef](),
                    llobjfields=new_def_hash[ValueRef](),
                    lllocals=new_def_hash[ValueRef](),
6028
                    llupvars=new_def_hash[ValueRef](),
6029 6030 6031 6032 6033
                    lltydescs=new_def_hash[ValueRef](),
                    ccx=cx);

    auto bcx = new_top_block_ctxt(fcx);

6034 6035
    auto lldst_vec = bcx.build.Load(lldst_vec_ptr);

6036 6037
    // First the dst vec needs to grow to accommodate the src vec.
    // To do this we have to figure out how many bytes to add.
6038

6039
    auto llcopy_dst_ptr = bcx.build.Alloca(T_int());
6040 6041
    auto llnew_vec_res =
        trans_upcall(bcx, "upcall_vec_grow",
6042 6043 6044
                     vec(vp2i(bcx, lldst_vec),
                         vec_fill_adjusted(bcx, llsrc_vec, llskipnull),
                         vp2i(bcx, llcopy_dst_ptr),
6045 6046 6047
                         vp2i(bcx, llvec_tydesc)));

    bcx = llnew_vec_res.bcx;
6048 6049
    auto llnew_vec = vi2p(bcx, llnew_vec_res.val,
                          T_opaque_vec_ptr());
6050

6051
    put_vec_fill(bcx, llnew_vec, C_int(0));
6052

6053 6054
    auto copy_dst_cx = new_sub_block_ctxt(bcx, "copy new <- dst");
    auto copy_src_cx = new_sub_block_ctxt(bcx, "copy new <- src");
6055

6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079
    auto pp0 = bcx.build.Alloca(T_ptr(T_i8()));
    bcx.build.Store(vec_p0(bcx, llnew_vec), pp0);

    bcx.build.CondBr(bcx.build.TruncOrBitCast
                     (bcx.build.Load(llcopy_dst_ptr),
                      T_i1()),
                     copy_dst_cx.llbb,
                     copy_src_cx.llbb);


    fn copy_elts(@block_ctxt cx,
                 ValueRef elt_tydesc,
                 ValueRef dst,
                 ValueRef src,
                 ValueRef n_bytes) -> result {

        auto src_lim = cx.build.GEP(src, vec(n_bytes));

        auto elt_llsz =
            cx.build.Load(cx.build.GEP(elt_tydesc,
                                       vec(C_int(0),
                                           C_int(abi.tydesc_field_size))));

        fn take_one(ValueRef elt_tydesc,
6080 6081 6082
                    @block_ctxt cx,
                    ValueRef dst, ValueRef src) -> result {
            call_tydesc_glue_full(cx, src,
6083 6084
                                  elt_tydesc,
                                  abi.tydesc_field_take_glue_off);
6085
            ret res(cx, src);
6086 6087
        }

6088
        auto bcx = iter_sequence_raw(cx, dst, src, src_lim,
6089
                                     elt_llsz, bind take_one(elt_tydesc,
6090
                                                             _, _, _)).bcx;
6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103

        ret call_memcpy(bcx, dst, src, n_bytes);
    }

    // Copy any dst elements in, omitting null if doing str.
    auto n_bytes = vec_fill_adjusted(copy_dst_cx, lldst_vec, llskipnull);
    copy_dst_cx = copy_elts(copy_dst_cx,
                            llelt_tydesc,
                            copy_dst_cx.build.Load(pp0),
                            vec_p0(copy_dst_cx, lldst_vec),
                            n_bytes).bcx;

    put_vec_fill(copy_dst_cx, llnew_vec, n_bytes);
6104
    copy_dst_cx.build.Store(vec_p1(copy_dst_cx, llnew_vec), pp0);
6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123
    copy_dst_cx.build.Br(copy_src_cx.llbb);


    // Copy any src elements in, carrying along null if doing str.
    n_bytes = vec_fill(copy_src_cx, llsrc_vec);
    copy_src_cx = copy_elts(copy_src_cx,
                            llelt_tydesc,
                            copy_src_cx.build.Load(pp0),
                            vec_p0(copy_src_cx, llsrc_vec),
                            n_bytes).bcx;

    put_vec_fill(copy_src_cx, llnew_vec,
                 copy_src_cx.build.Add(vec_fill(copy_src_cx,
                                                llnew_vec),
                                        n_bytes));

    // Write new_vec back through the alias we were given.
    copy_src_cx.build.Store(llnew_vec, lldst_vec_ptr);
    copy_src_cx.build.RetVoid();
6124 6125 6126
}


6127 6128 6129
fn make_glues(ModuleRef llmod, type_names tn) -> @glue_fns {
    ret @rec(activate_glue = decl_glue(llmod, tn, abi.activate_glue_name()),
             yield_glue = decl_glue(llmod, tn, abi.yield_glue_name()),
6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140
             /*
              * Note: the signature passed to decl_cdecl_fn here looks unusual
              * because it is. It corresponds neither to an upcall signature
              * nor a normal rust-ABI signature. In fact it is a fake
              * signature, that exists solely to acquire the task pointer as
              * an argument to the upcall. It so happens that the runtime sets
              * up the task pointer as the sole incoming argument to the frame
              * that we return into when returning to the exit task glue. So
              * this is the signature required to retrieve it.
              */
             exit_task_glue = decl_cdecl_fn(llmod, abi.exit_task_glue_name(),
6141 6142 6143 6144
                                            T_fn(vec(T_int(),
                                                     T_int(),
                                                     T_int(),
                                                     T_taskptr(tn)),
6145
                                                 T_void())),
6146 6147

             upcall_glues =
6148
             _vec.init_fn[ValueRef](bind decl_upcall_glue(llmod, tn, _),
6149
                                    abi.n_upcall_glues + 1 as uint),
6150 6151 6152
             no_op_type_glue = decl_no_op_type_glue(llmod, tn),
             memcpy_glue = decl_memcpy_glue(llmod),
             bzero_glue = decl_bzero_glue(llmod),
6153
             vec_append_glue = make_vec_append_glue(llmod, tn));
6154 6155
}

6156 6157 6158 6159
fn make_common_glue(str output) {
    // FIXME: part of this is repetitive and is probably a good idea
    // to autogen it, but things like the memcpy implementation are not
    // and it might be better to just check in a .ll file.
6160 6161 6162 6163
    auto llmod =
        llvm.LLVMModuleCreateWithNameInContext(_str.buf("rust_out"),
                                               llvm.LLVMGetGlobalContext());

6164 6165
    llvm.LLVMSetDataLayout(llmod, _str.buf(x86.get_data_layout()));
    llvm.LLVMSetTarget(llmod, _str.buf(x86.get_target_triple()));
6166
    auto td = mk_target_data(x86.get_data_layout());
6167
    auto tn = mk_type_names();
6168
    let ValueRef crate_ptr =
6169
        llvm.LLVMAddGlobal(llmod, T_crate(tn), _str.buf("rust_crate"));
6170

6171 6172
    auto intrinsics = declare_intrinsics(llmod);

6173
    llvm.LLVMSetModuleInlineAsm(llmod, _str.buf(x86.get_module_asm()));
6174

6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199
    auto glues = make_glues(llmod, tn);
    create_crate_constant(crate_ptr, glues);
    make_memcpy_glue(glues.memcpy_glue);

    trans_exit_task_glue(glues, new_str_hash[ValueRef](), tn, llmod);

    check_module(llmod);

    llvm.LLVMWriteBitcodeToFile(llmod, _str.buf(output));
    llvm.LLVMDisposeModule(llmod);
}

fn trans_crate(session.session sess, @ast.crate crate, str output,
               bool shared) {
    auto llmod =
        llvm.LLVMModuleCreateWithNameInContext(_str.buf("rust_out"),
                                               llvm.LLVMGetGlobalContext());

    llvm.LLVMSetDataLayout(llmod, _str.buf(x86.get_data_layout()));
    llvm.LLVMSetTarget(llmod, _str.buf(x86.get_target_triple()));
    auto td = mk_target_data(x86.get_data_layout());
    auto tn = mk_type_names();
    let ValueRef crate_ptr =
        llvm.LLVMAddGlobal(llmod, T_crate(tn), _str.buf("rust_crate"));

6200
    auto intrinsics = declare_intrinsics(llmod);
6201

6202
    auto glues = make_glues(llmod, tn);
6203 6204
    auto hasher = ty.hash_ty;
    auto eqer = ty.eq_ty;
6205
    auto tag_sizes = map.mk_hashmap[@ty.t,uint](hasher, eqer);
6206
    auto tydescs = map.mk_hashmap[@ty.t,@tydesc_info](hasher, eqer);
6207
    let vec[ast.ty_param] obj_typarams = vec();
6208
    let vec[ast.obj_field] obj_fields = vec();
6209

6210 6211
    auto cx = @rec(sess = sess,
                   llmod = llmod,
6212
                   td = td,
6213
                   tn = tn,
6214
                   crate_ptr = crate_ptr,
6215
                   upcalls = new_str_hash[ValueRef](),
6216
                   intrinsics = intrinsics,
6217
                   item_names = new_str_hash[ValueRef](),
6218
                   native_fns = new_str_hash[ValueRef](),
6219
                   item_ids = new_def_hash[ValueRef](),
6220
                   items = new_def_hash[@ast.item](),
6221
                   native_items = new_def_hash[@ast.native_item](),
6222
                   tag_sizes = tag_sizes,
6223
                   discrims = new_def_hash[ValueRef](),
6224
                   fn_pairs = new_def_hash[ValueRef](),
6225
                   consts = new_def_hash[ValueRef](),
6226
                   obj_methods = new_def_hash[()](),
6227
                   tydescs = tydescs,
6228
                   obj_typarams = obj_typarams,
6229
                   obj_fields = obj_fields,
6230
                   glues = glues,
6231
                   names = namegen(0),
6232
                   path = "_rust");
6233

6234 6235
    create_typedefs(cx);

6236
    collect_items(cx, crate);
6237
    collect_tag_ctors(cx, crate);
6238
    trans_constants(cx, crate);
6239

6240
    trans_mod(cx, crate.node.module);
6241
    trans_vec_append_glue(cx);
6242
    if (!shared) {
6243
        trans_main_fn(cx, cx.crate_ptr);
6244
    }
6245

6246 6247 6248
    // Translate the metadata.
    middle.metadata.write_metadata(cx, crate);

6249 6250
    check_module(llmod);

6251
    llvm.LLVMWriteBitcodeToFile(llmod, _str.buf(output));
6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264
    llvm.LLVMDisposeModule(llmod);
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//