trans.rs 263.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
import std.Int;
import std.Str;
import std.UInt;
import std.Vec;
import std.Str.rustrt.sbuf;
import std.Vec.rustrt.vbuf;
import std.Map;
import std.Map.hashmap;
import std.Option;
import std.Option.some;
import std.Option.none;
12

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

21
import middle.ty.pat_ty;
P
Patrick Walton 已提交
22

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

import lib.llvm.llvm;
import lib.llvm.builder;
30
import lib.llvm.target_data;
31
import lib.llvm.type_handle;
32
import lib.llvm.type_names;
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
import lib.llvm.Bool;
46

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

54 55
type glue_fns = rec(ValueRef activate_glue,
                    ValueRef yield_glue,
56
                    ValueRef exit_task_glue,
57
                    vec[ValueRef] native_glues_rust,
58
                    vec[ValueRef] native_glues_pure_rust,
59
                    vec[ValueRef] native_glues_cdecl,
60
                    ValueRef no_op_type_glue,
61
                    ValueRef vec_append_glue);
62

63 64
type tydesc_info = rec(ValueRef tydesc,
                       ValueRef take_glue,
65 66
                       ValueRef drop_glue,
                       ValueRef cmp_glue);
67

68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
/*
 * A note on nomenclature of linking: "upcall", "extern" and "native".
 *
 * An "extern" is an LLVM symbol we wind up emitting an undefined external
 * reference to. This means "we don't have the thing in this compilation unit,
 * please make sure you link it in at runtime". This could be a reference to
 * C code found in a C library, or rust code found in a rust crate.
 *
 * A "native" is a combination of an extern that references C code, plus a
 * glue-code stub that "looks like" a rust function, emitted here, plus a
 * generic N-ary bit of asm glue (found over in back/x86.rs) that performs a
 * control transfer into C from rust. Natives may be normal C library code.
 *
 * An upcall is a native call generated by the compiler (not corresponding to
 * any user-written call in the code) into librustrt, to perform some helper
 * task such as bringing a task to life, allocating memory, etc.
 *
 */

87
state type crate_ctxt = rec(session.session sess,
88
                            ModuleRef llmod,
89
                            target_data td,
90
                            type_names tn,
91
                            ValueRef crate_ptr,
92
                            hashmap[str, ValueRef] externs,
93
                            hashmap[str, ValueRef] intrinsics,
94
                            hashmap[ast.def_id, ValueRef] item_ids,
95
                            hashmap[ast.def_id, @ast.item] items,
G
Graydon Hoare 已提交
96 97
                            hashmap[ast.def_id,
                                    @ast.native_item] native_items,
98
                            ty.type_cache type_cache,
P
Patrick Walton 已提交
99
                            hashmap[ast.def_id, str] item_symbols,
100
                            // TODO: hashmap[tup(tag_id,subtys), @tag_info]
101
                            hashmap[ty.t, uint] tag_sizes,
102
                            hashmap[ast.def_id, ValueRef] discrims,
P
Patrick Walton 已提交
103
                            hashmap[ast.def_id, str] discrim_symbols,
104
                            hashmap[ast.def_id, ValueRef] fn_pairs,
105
                            hashmap[ast.def_id, ValueRef] consts,
106
                            hashmap[ast.def_id,()] obj_methods,
107
                            hashmap[ty.t, @tydesc_info] tydescs,
108
                            hashmap[str, ValueRef] module_data,
109
                            hashmap[ty.t, TypeRef] lltypes,
110 111
                            @glue_fns glues,
                            namegen names,
112
                            std.SHA1.sha1 sha,
113
                            hashmap[ty.t, str] type_sha1s,
114
                            hashmap[ty.t, metadata.ty_abbrev] type_abbrevs,
115
                            ty.ctxt tcx);
116

117
type local_ctxt = rec(vec[str] path,
118
                      vec[str] module_path,
119 120 121
                      vec[ast.ty_param] obj_typarams,
                      vec[ast.obj_field] obj_fields,
                      @crate_ctxt ccx);
122

123

124
type self_vt = rec(ValueRef v, ty.t t);
125

126 127
state type fn_ctxt = rec(ValueRef llfn,
                         ValueRef lltaskptr,
128 129
                         ValueRef llenv,
                         ValueRef llretptr,
130
                         mutable BasicBlockRef llallocas,
131 132
                         mutable Option.t[self_vt] llself,
                         mutable Option.t[ValueRef] lliterbody,
133
                         hashmap[ast.def_id, ValueRef] llargs,
134
                         hashmap[ast.def_id, ValueRef] llobjfields,
135
                         hashmap[ast.def_id, ValueRef] lllocals,
136
                         hashmap[ast.def_id, ValueRef] llupvars,
137
                         mutable vec[ValueRef] lltydescs,
138
                         @local_ctxt lcx);
139

140
tag cleanup {
141
    clean(fn(@block_ctxt cx) -> result);
142 143
}

144 145 146

tag block_kind {
    SCOPE_BLOCK;
147
    LOOP_SCOPE_BLOCK(Option.t[@block_ctxt], @block_ctxt);
148 149 150
    NON_SCOPE_BLOCK;
}

151 152
state type block_ctxt = rec(BasicBlockRef llbb,
                            builder build,
153
                            block_parent parent,
154
                            block_kind kind,
155 156 157
                            mutable vec[cleanup] cleanups,
                            @fn_ctxt fcx);

158
// FIXME: we should be able to use Option.t[@block_parent] here but
159 160 161 162 163 164 165
// the infinite-tag check in rustboot gets upset.

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

166

167 168 169
state type result = rec(mutable @block_ctxt bcx,
                        mutable ValueRef val);

170 171 172 173
fn sep() -> str {
    ret "_";
}

174
fn extend_path(@local_ctxt cx, str name) -> @local_ctxt {
175
  ret @rec(path = cx.path + vec(name) with *cx);
176 177 178
}

fn path_name(vec[str] path) -> str {
179
    ret Str.connect(path, sep());
180 181 182
}


P
Patrick Walton 已提交
183
fn get_type_sha1(@crate_ctxt ccx, ty.t t) -> str {
184 185 186 187 188 189
    auto hash = "";
    alt (ccx.type_sha1s.find(t)) {
        case (some[str](?h)) { hash = h; }
        case (none[str]) {
            ccx.sha.reset();
            auto f = metadata.def_to_str;
190 191
            // NB: do *not* use abbrevs here as we want the symbol names
            // to be independent of one another in the crate.
192
            auto cx = @rec(ds=f, tcx=ccx.tcx, abbrevs=metadata.ac_no_abbrevs);
193
            ccx.sha.input_str(metadata.Encode.ty_str(cx, t));
194
            hash = Str.substr(ccx.sha.result_str(), 0u, 16u);
195 196 197
            ccx.type_sha1s.insert(t, hash);
        }
    }
P
Patrick Walton 已提交
198 199 200 201 202
    ret hash;
}

fn mangle_name_by_type(@crate_ctxt ccx, vec[str] path, ty.t t) -> str {
    auto hash = get_type_sha1(ccx, t);
203
    ret sep() + "rust" + sep() + hash + sep() + path_name(path);
204 205
}

P
Patrick Walton 已提交
206 207
fn mangle_name_by_type_only(@crate_ctxt ccx, ty.t t, str name) -> str {
    auto f = metadata.def_to_str;
208
    auto cx = @rec(ds=f, tcx=ccx.tcx, abbrevs=metadata.ac_no_abbrevs);
P
Patrick Walton 已提交
209 210 211 212 213 214
    auto s = metadata.Encode.ty_str(cx, t);

    auto hash = get_type_sha1(ccx, t);
    ret sep() + "rust" + sep() + hash + sep() + name + "_" + s;
}

215
fn mangle_name_by_seq(@crate_ctxt ccx, vec[str] path, str flav) -> str {
216
    ret sep() + "rust" + sep()
217 218
        + ccx.names.next(flav) + sep()
        + path_name(path);
219 220
}

221 222 223 224 225
fn res(@block_ctxt bcx, ValueRef val) -> result {
    ret rec(mutable bcx = bcx,
            mutable val = val);
}

226 227
fn ty_str(type_names tn, TypeRef t) -> str {
    ret lib.llvm.type_to_str(tn, t);
228 229 230 231 232 233
}

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

234 235
fn val_str(type_names tn, ValueRef v) -> str {
    ret ty_str(tn, val_ty(v));
236
}
237 238 239 240


// LLVM type constructors.

241 242 243 244 245 246 247 248 249 250 251
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.
252 253 254
    ret llvm.LLVMVoidType();
}

255 256 257 258 259
fn T_nil() -> TypeRef {
    // NB: See above in T_void().
    ret llvm.LLVMInt1Type();
}

260 261 262 263
fn T_i1() -> TypeRef {
    ret llvm.LLVMInt1Type();
}

264 265 266 267 268 269 270 271 272
fn T_i8() -> TypeRef {
    ret llvm.LLVMInt8Type();
}

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

fn T_i32() -> TypeRef {
273 274 275
    ret llvm.LLVMInt32Type();
}

276 277 278 279
fn T_i64() -> TypeRef {
    ret llvm.LLVMInt64Type();
}

280 281 282 283 284 285 286 287
fn T_f32() -> TypeRef {
    ret llvm.LLVMFloatType();
}

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

288 289 290 291
fn T_bool() -> TypeRef {
    ret T_i1();
}

292 293 294 295 296
fn T_int() -> TypeRef {
    // FIXME: switch on target type.
    ret T_i32();
}

297 298 299 300 301
fn T_float() -> TypeRef {
    // FIXME: switch on target type.
    ret T_f64();
}

302 303 304 305
fn T_char() -> TypeRef {
    ret T_i32();
}

306 307 308 309 310
fn T_size_t() -> TypeRef {
    // FIXME: switch on target type.
    ret T_i32();
}

311 312
fn T_fn(vec[TypeRef] inputs, TypeRef output) -> TypeRef {
    ret llvm.LLVMFunctionType(output,
313 314
                              Vec.buf[TypeRef](inputs),
                              Vec.len[TypeRef](inputs),
315 316 317
                              False);
}

318
fn T_fn_pair(type_names tn, TypeRef tfn) -> TypeRef {
319
    ret T_struct(vec(T_ptr(tfn),
320
                     T_opaque_closure_ptr(tn)));
321 322
}

323 324 325 326 327
fn T_ptr(TypeRef t) -> TypeRef {
    ret llvm.LLVMPointerType(t, 0u);
}

fn T_struct(vec[TypeRef] elts) -> TypeRef {
328 329
    ret llvm.LLVMStructType(Vec.buf[TypeRef](elts),
                            Vec.len[TypeRef](elts),
330 331 332 333 334 335 336
                            False);
}

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

337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
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;
354 355
}

356 357 358
fn T_tydesc_field(type_names tn, int field) -> TypeRef {
    // Bit of a kludge: pick the fn typeref out of the tydesc..
    let vec[TypeRef] tydesc_elts =
359
        Vec.init_elt[TypeRef](T_nil(), abi.n_tydesc_fields as uint);
360
    llvm.LLVMGetStructElementTypes(T_tydesc(tn),
361
                                   Vec.buf[TypeRef](tydesc_elts));
362 363 364 365
    auto t = llvm.LLVMGetElementType(tydesc_elts.(field));
    ret t;
}

366 367 368 369 370 371
fn T_glue_fn(type_names tn) -> TypeRef {
    auto s = "glue_fn";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }

372 373 374 375 376
    auto t = T_tydesc_field(tn, abi.tydesc_field_drop_glue);
    tn.associate(s, t);
    ret t;
}

377 378
fn T_dtor(@crate_ctxt ccx, TypeRef llself_ty) -> TypeRef {
    ret type_of_fn_full(ccx, ast.proto_fn, some[TypeRef](llself_ty),
379
                        Vec.empty[ty.arg](), ty.mk_nil(ccx.tcx), 0u);
380 381
}

382 383 384 385 386 387 388
fn T_cmp_glue_fn(type_names tn) -> TypeRef {
    auto s = "cmp_glue_fn";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }

    auto t = T_tydesc_field(tn, abi.tydesc_field_cmp_glue);
389 390
    tn.associate(s, t);
    ret t;
391 392
}

393 394 395 396 397 398
fn T_tydesc(type_names tn) -> TypeRef {

    auto s = "tydesc";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }
399 400 401

    auto th = mk_type_handle();
    auto abs_tydesc = llvm.LLVMResolveTypeHandle(th.llth);
402
    auto tydescpp = T_ptr(T_ptr(abs_tydesc));
403
    auto pvoid = T_ptr(T_i8());
404
    auto glue_fn_ty = T_ptr(T_fn(vec(T_ptr(T_nil()),
405
                                     T_taskptr(tn),
406
                                     T_ptr(T_nil()),
407
                                     tydescpp,
408
                                     pvoid), T_void()));
409
    auto cmp_glue_fn_ty = T_ptr(T_fn(vec(T_ptr(T_i1()),
410 411 412 413
                                         T_taskptr(tn),
                                         T_ptr(T_nil()),
                                         tydescpp,
                                         pvoid,
414 415
                                         pvoid,
                                         T_i8()), T_void()));
416
    auto tydesc = T_struct(vec(tydescpp,          // first_param
417 418
                               T_int(),           // size
                               T_int(),           // align
419 420 421 422 423 424
                               glue_fn_ty,        // take_glue
                               glue_fn_ty,        // drop_glue
                               glue_fn_ty,        // free_glue
                               glue_fn_ty,        // sever_glue
                               glue_fn_ty,        // mark_glue
                               glue_fn_ty,        // obj_drop_glue
425 426
                               glue_fn_ty,        // is_stateful
                               cmp_glue_fn_ty));  // cmp_glue
427 428

    llvm.LLVMRefineType(abs_tydesc, tydesc);
429 430 431
    auto t = llvm.LLVMResolveTypeHandle(th.llth);
    tn.associate(s, t);
    ret t;
432 433
}

434
fn T_array(TypeRef t, uint n) -> TypeRef {
435
    assert (n != 0u);
436 437 438
    ret llvm.LLVMArrayType(t, n);
}

439 440 441 442
fn T_vec(TypeRef t) -> TypeRef {
    ret T_struct(vec(T_int(),       // Refcount
                     T_int(),       // Alloc
                     T_int(),       // Fill
443
                     T_int(),       // Pad
444
                     T_array(t, 1u) // Body elements
445 446 447
                     ));
}

448 449 450 451
fn T_opaque_vec_ptr() -> TypeRef {
    ret T_ptr(T_vec(T_int()));
}

452 453
fn T_str() -> TypeRef {
    ret T_vec(T_i8());
454 455
}

456 457 458 459
fn T_box(TypeRef t) -> TypeRef {
    ret T_struct(vec(T_int(), t));
}

B
Brian Anderson 已提交
460 461 462 463 464 465 466 467
fn T_port(TypeRef t) -> TypeRef {
    ret T_struct(vec(T_int())); // Refcount
}

fn T_chan(TypeRef t) -> TypeRef {
    ret T_struct(vec(T_int())); // Refcount
}

468 469 470 471 472 473 474 475 476 477 478 479
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
480 481 482 483 484
                          T_int(),      // size_t activate_glue
                          T_int(),      // size_t yield_glue
                          T_int(),      // size_t unwind_glue
                          T_int(),      // size_t gc_glue
                          T_int(),      // size_t main_exit_task_glue
485 486
                          T_int(),      // int n_rust_syms
                          T_int(),      // int n_c_syms
487
                          T_int(),      // int n_libs
488
                          T_int()       // uintptr_t abi_tag
489 490 491
                          ));
    tn.associate(s, t);
    ret t;
492 493
}

494 495
fn T_taskptr(type_names tn) -> TypeRef {
    ret T_ptr(T_task(tn));
496 497
}

498 499
// This type must never be used directly; it must always be cast away.
fn T_typaram(type_names tn) -> TypeRef {
500 501 502 503 504
    auto s = "typaram";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }

505
    auto t = T_i8();
506 507
    tn.associate(s, t);
    ret t;
508 509
}

510 511 512 513
fn T_typaram_ptr(type_names tn) -> TypeRef {
    ret T_ptr(T_typaram(tn));
}

514 515
fn T_closure_ptr(type_names tn,
                 TypeRef lltarget_ty,
516 517
                 TypeRef llbindings_ty,
                 uint n_ty_params) -> TypeRef {
518 519 520 521

    // 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.
522
    ret T_ptr(T_box(T_struct(vec(T_ptr(T_tydesc(tn)),
523
                                 lltarget_ty,
524 525
                                 llbindings_ty,
                                 T_captured_tydescs(tn, n_ty_params))
526 527 528
                             )));
}

529 530 531 532 533 534 535
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()))),
536 537
                           T_nil(),
                           0u);
538 539
    tn.associate(s, t);
    ret t;
540 541
}

542
fn T_tag(type_names tn, uint size) -> TypeRef {
543
    auto s = "tag_" + UInt.to_str(size, 10u);
544 545 546
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }
547 548 549 550 551 552 553 554

    auto t;
    if (size == 0u) {
        t = T_struct(vec(T_int()));
    } else {
        t = T_struct(vec(T_int(), T_array(T_i8(), size)));
    }

555 556 557 558 559
    tn.associate(s, t);
    ret t;
}

fn T_opaque_tag(type_names tn) -> TypeRef {
560
    auto s = "opaque_tag";
561 562 563
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }
564
    auto t = T_struct(vec(T_int(), T_i8()));
565 566 567 568
    tn.associate(s, t);
    ret t;
}

569 570 571 572
fn T_opaque_tag_ptr(type_names tn) -> TypeRef {
    ret T_ptr(T_opaque_tag(tn));
}

573
fn T_captured_tydescs(type_names tn, uint n) -> TypeRef {
574
    ret T_struct(Vec.init_elt[TypeRef](T_ptr(T_tydesc(tn)), n));
575 576
}

577 578 579 580 581 582 583
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)));
    }
584

585
    ret T_ptr(T_box(T_obj(tn, n_captured_tydescs)));
586 587
}

588
fn T_opaque_obj_ptr(type_names tn) -> TypeRef {
589
    ret T_obj_ptr(tn, 0u);
590 591
}

592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
fn T_opaque_port_ptr(type_names tn) -> TypeRef {
    auto s = "*port";
    if (tn.name_has_type(s)) { ret tn.get_type(s); }

    auto t = T_ptr(T_i8());

    tn.associate(s, t);
    ret t;
}

fn T_opaque_chan_ptr(type_names tn) -> TypeRef {
    auto s = "*chan";
    if (tn.name_has_type(s)) { ret tn.get_type(s); }

    auto t = T_ptr(T_i8());

    tn.associate(s, t);
    ret t;
}

612

613 614 615 616
// 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.
617
fn type_of(@crate_ctxt cx, ty.t t) -> TypeRef {
618
    if (ty.type_has_dynamic_size(cx.tcx, t)) {
619
        log_err "type_of() called on a type with dynamic size: " +
620
            ty.ty_to_str(cx.tcx, t);
621 622 623
        fail;
    }

624
    ret type_of_inner(cx, t);
625 626
}

627
fn type_of_explicit_args(@crate_ctxt cx, vec[ty.arg] inputs) -> vec[TypeRef] {
628 629
    let vec[TypeRef] atys = vec();
    for (ty.arg arg in inputs) {
630
        if (ty.type_has_dynamic_size(cx.tcx, arg.ty)) {
631
            assert (arg.mode == ty.mo_alias);
632
            atys += vec(T_typaram_ptr(cx.tn));
633
        } else {
634
            let TypeRef t;
635
            alt (arg.mode) {
636
                case (ty.mo_alias) {
637
                    t = T_ptr(type_of_inner(cx, arg.ty));
638 639
                }
                case (_) {
640
                    t = type_of_inner(cx, arg.ty);
641 642
                }
            }
643
            atys += vec(t);
644 645 646 647
        }
    }
    ret atys;
}
648 649 650 651 652 653 654 655

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

656
fn type_of_fn_full(@crate_ctxt cx,
657
                   ast.proto proto,
658
                   Option.t[TypeRef] obj_self,
659
                   vec[ty.arg] inputs,
660
                   ty.t output,
661
                   uint ty_param_count) -> TypeRef {
662
    let vec[TypeRef] atys = vec();
663

664
    // Arg 0: Output pointer.
665
    if (ty.type_has_dynamic_size(cx.tcx, output)) {
666
        atys += vec(T_typaram_ptr(cx.tn));
667
    } else {
668
        atys += vec(T_ptr(type_of_inner(cx, output)));
669 670
    }

671
    // Arg 1: Task pointer.
672
    atys += vec(T_taskptr(cx.tn));
673 674

    // Arg 2: Env (closure-bindings / self-obj)
675 676
    alt (obj_self) {
        case (some[TypeRef](?t)) {
677
            assert (t as int != 0);
678
            atys += vec(t);
679
        }
680
        case (_) {
681
            atys += vec(T_opaque_closure_ptr(cx.tn));
682
        }
683 684
    }

685 686 687 688
    // Args >3: ty params, if not acquired via capture...
    if (obj_self == none[TypeRef]) {
        auto i = 0u;
        while (i < ty_param_count) {
689
            atys += vec(T_ptr(T_tydesc(cx.tn)));
690 691
            i += 1u;
        }
692 693
    }

694
    if (proto == ast.proto_iter) {
695 696 697
        // 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.
698 699
        atys +=
            vec(T_fn_pair(cx.tn,
700
                          type_of_fn_full(cx, ast.proto_fn, none[TypeRef],
701 702
                                          vec(rec(mode=ty.mo_alias,
                                                  ty=output)),
703
                                          ty.mk_nil(cx.tcx), 0u)));
704 705
    }

706
    // ... then explicit args.
707
    atys += type_of_explicit_args(cx, inputs);
708

709
    ret T_fn(atys, llvm.LLVMVoidType());
710 711
}

712
fn type_of_fn(@crate_ctxt cx,
713
              ast.proto proto,
714
              vec[ty.arg] inputs,
715
              ty.t output,
716 717 718
              uint ty_param_count) -> TypeRef {
    ret type_of_fn_full(cx, proto, none[TypeRef], inputs, output,
                        ty_param_count);
719 720
}

721 722
fn type_of_native_fn(@crate_ctxt cx, ast.native_abi abi,
                     vec[ty.arg] inputs,
723
                     ty.t output,
724
                     uint ty_param_count) -> TypeRef {
725 726
    let vec[TypeRef] atys = vec();
    if (abi == ast.native_abi_rust) {
727
        atys += vec(T_taskptr(cx.tn));
728 729 730
        auto t = ty.ty_native_fn(abi, inputs, output);
        auto i = 0u;
        while (i < ty_param_count) {
731
            atys += vec(T_ptr(T_tydesc(cx.tn)));
732 733 734 735
            i += 1u;
        }
    }
    atys += type_of_explicit_args(cx, inputs);
736
    ret T_fn(atys, type_of_inner(cx, output));
737 738
}

739
fn type_of_inner(@crate_ctxt cx, ty.t t) -> TypeRef {
740 741 742 743 744
    // Check the cache.
    if (cx.lltypes.contains_key(t)) {
        ret cx.lltypes.get(t);
    }

745 746
    let TypeRef llty = 0 as TypeRef;

747
    alt (ty.struct(cx.tcx, t)) {
748 749 750 751
        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(); }
752
        case (ty.ty_float) { llty = T_float(); }
753
        case (ty.ty_uint) { llty = T_int(); }
754
        case (ty.ty_machine(?tm)) {
755
            alt (tm) {
756 757 758 759 760 761 762 763 764 765
                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(); }
766 767
            }
        }
768 769
        case (ty.ty_char) { llty = T_char(); }
        case (ty.ty_str) { llty = T_ptr(T_str()); }
770
        case (ty.ty_tag(_, _)) {
771
            if (ty.type_has_dynamic_size(cx.tcx, t)) {
772 773 774 775 776
                llty = T_opaque_tag(cx.tn);
            } else {
                auto size = static_size_of_tag(cx, t);
                llty = T_tag(cx.tn, size);
            }
777
        }
778
        case (ty.ty_box(?mt)) {
779
            llty = T_ptr(T_box(type_of_inner(cx, mt.ty)));
780
        }
781
        case (ty.ty_vec(?mt)) {
782
            llty = T_ptr(T_vec(type_of_inner(cx, mt.ty)));
783
        }
B
Brian Anderson 已提交
784
        case (ty.ty_port(?t)) {
785
            llty = T_ptr(T_port(type_of_inner(cx, t)));
B
Brian Anderson 已提交
786 787
        }
        case (ty.ty_chan(?t)) {
788
            llty = T_ptr(T_chan(type_of_inner(cx, t)));
B
Brian Anderson 已提交
789
        }
790
        case (ty.ty_tup(?elts)) {
791
            let vec[TypeRef] tys = vec();
792
            for (ty.mt elt in elts) {
793
                tys += vec(type_of_inner(cx, elt.ty));
794
            }
795
            llty = T_struct(tys);
796
        }
797
        case (ty.ty_rec(?fields)) {
798
            let vec[TypeRef] tys = vec();
799
            for (ty.field f in fields) {
800
                tys += vec(type_of_inner(cx, f.mt.ty));
801
            }
802
            llty = T_struct(tys);
803
        }
804
        case (ty.ty_fn(?proto, ?args, ?out)) {
805
            llty = T_fn_pair(cx.tn, type_of_fn(cx, proto, args, out, 0u));
806
        }
807
        case (ty.ty_native_fn(?abi, ?args, ?out)) {
808
            auto nft = native_fn_wrapper_type(cx, 0u, t);
809
            llty = T_fn_pair(cx.tn, nft);
810
        }
811
        case (ty.ty_obj(?meths)) {
812 813 814
            auto th = mk_type_handle();
            auto self_ty = llvm.LLVMResolveTypeHandle(th.llth);

815
            let vec[TypeRef] mtys = vec(T_ptr(T_i8()));
816
            for (ty.method m in meths) {
817
                let TypeRef mty =
818
                    type_of_fn_full(cx, m.proto,
819
                                    some[TypeRef](self_ty),
820
                                    m.inputs, m.output, 0u);
821
                mtys += vec(T_ptr(mty));
822
            }
823
            let TypeRef vtbl = T_struct(mtys);
824
            let TypeRef pair = T_struct(vec(T_ptr(vtbl),
825
                                            T_opaque_obj_ptr(cx.tn)));
826

827 828 829
            auto abs_pair = llvm.LLVMResolveTypeHandle(th.llth);
            llvm.LLVMRefineType(abs_pair, pair);
            abs_pair = llvm.LLVMResolveTypeHandle(th.llth);
830
            llty = abs_pair;
831
        }
832
        case (ty.ty_var(_)) {
833
            log_err "ty_var in trans.type_of";
834 835
            fail;
        }
836
        case (ty.ty_param(_)) {
837
            llty = T_i8();
838
        }
839
        case (ty.ty_bound_param(_)) {
840
            log_err "ty_bound_param in trans.type_of";
841 842
            fail;
        }
843
        case (ty.ty_type) { llty = T_ptr(T_tydesc(cx.tn)); }
844
    }
845

846
    assert (llty as int != 0);
847
    llvm.LLVMAddTypeName(cx.llmod, Str.buf(ty.ty_to_short_str(cx.tcx, t)),
848
                         llty);
849
    cx.lltypes.insert(t, llty);
850
    ret llty;
851 852
}

853
fn type_of_arg(@local_ctxt cx, &ty.arg arg) -> TypeRef {
854
    alt (ty.struct(cx.ccx.tcx, arg.ty)) {
855
        case (ty.ty_param(_)) {
856
            if (arg.mode == ty.mo_alias) {
857
                ret T_typaram_ptr(cx.ccx.tn);
858 859 860 861 862 863 864
            }
        }
        case (_) {
            // fall through
        }
    }

865
    auto typ;
866
    if (arg.mode == ty.mo_alias) {
867
        typ = T_ptr(type_of_inner(cx.ccx, arg.ty));
868
    } else {
869
        typ = type_of_inner(cx.ccx, arg.ty);
870
    }
871
    ret typ;
872 873
}

874
fn type_of_ty_param_count_and_ty(@local_ctxt lcx,
875
                                 ty.ty_param_count_and_ty tpt) -> TypeRef {
876
    alt (ty.struct(lcx.ccx.tcx, tpt._1)) {
877
        case (ty.ty_fn(?proto, ?inputs, ?output)) {
878 879
            auto llfnty = type_of_fn(lcx.ccx, proto, inputs, output, tpt._0);
            ret T_fn_pair(lcx.ccx.tn, llfnty);
880 881 882 883 884
        }
        case (_) {
            // fall through
        }
    }
885
    ret type_of(lcx.ccx, tpt._1);
886 887 888
}


889 890 891 892 893 894 895 896 897
// 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 {
898 899 900 901 902 903 904
            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 已提交
905 906
                        c != (' ' as u8) && c != ('\t' as u8) &&
                        c != (';' as u8)) {
907
                        auto v = vec(c);
908
                        result += Str.from_bytes(v);
909 910 911
                    }
                }
            }
912 913 914 915 916
        }
    }
    ret result;
}

917 918 919 920 921 922
// LLVM constant constructors.

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

923
fn C_integral(TypeRef t, uint u, Bool sign_extend) -> ValueRef {
924
    // FIXME. We can't use LLVM.ULongLong with our existing minimal native
925
    // API, which only knows word-sized args.
926 927 928
    //
    // ret llvm.LLVMConstInt(T_int(), t as LLVM.ULongLong, False);
    //
929
    ret llvm.LLVMRustConstSmallInt(t, u, sign_extend);
930 931
}

932
fn C_float(str s) -> ValueRef {
933
    ret llvm.LLVMConstRealOfString(T_float(), Str.buf(s));
934 935
}

936
fn C_floating(str s, TypeRef t) -> ValueRef {
937
    ret llvm.LLVMConstRealOfString(t, Str.buf(s));
938 939
}

940 941
fn C_nil() -> ValueRef {
    // NB: See comment above in T_void().
942
    ret C_integral(T_i1(), 0u, False);
943 944
}

945 946
fn C_bool(bool b) -> ValueRef {
    if (b) {
947
        ret C_integral(T_bool(), 1u, False);
948
    } else {
949
        ret C_integral(T_bool(), 0u, False);
950 951 952
    }
}

953
fn C_int(int i) -> ValueRef {
954
    ret C_integral(T_int(), i as uint, True);
955 956
}

957 958
fn C_u8(uint i) -> ValueRef {
    ret C_integral(T_i8(), i, False);
959 960
}

961 962 963
// 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 {
964
    auto sc = llvm.LLVMConstString(Str.buf(s), Str.byte_len(s), False);
965
    auto g = llvm.LLVMAddGlobal(cx.llmod, val_ty(sc),
966
                                Str.buf(cx.names.next("str")));
967
    llvm.LLVMSetInitializer(g, sc);
968
    llvm.LLVMSetGlobalConstant(g, True);
969
    llvm.LLVMSetLinkage(g, lib.llvm.LLVMInternalLinkage
970
                        as llvm.Linkage);
971
    ret g;
972 973
}

974 975
// A rust boxed-and-length-annotated string.
fn C_str(@crate_ctxt cx, str s) -> ValueRef {
976
    auto len = Str.byte_len(s);
977 978 979
    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'
980
                            C_int(0),               // 'pad'
981
                            llvm.LLVMConstString(Str.buf(s),
982 983
                                                 len, False)));
    auto g = llvm.LLVMAddGlobal(cx.llmod, val_ty(box),
984
                                Str.buf(cx.names.next("str")));
985 986
    llvm.LLVMSetInitializer(g, box);
    llvm.LLVMSetGlobalConstant(g, True);
987
    llvm.LLVMSetLinkage(g, lib.llvm.LLVMInternalLinkage
988 989 990 991
                        as llvm.Linkage);
    ret llvm.LLVMConstPointerCast(g, T_ptr(T_str()));
}

992 993 994 995
fn C_zero_byte_arr(uint size) -> ValueRef {
    auto i = 0u;
    let vec[ValueRef] elts = vec();
    while (i < size) {
996
        elts += vec(C_u8(0u));
997 998
        i += 1u;
    }
999 1000
    ret llvm.LLVMConstArray(T_i8(), Vec.buf[ValueRef](elts),
                            Vec.len[ValueRef](elts));
1001 1002
}

1003
fn C_struct(vec[ValueRef] elts) -> ValueRef {
1004 1005
    ret llvm.LLVMConstStruct(Vec.buf[ValueRef](elts),
                             Vec.len[ValueRef](elts),
1006 1007 1008
                             False);
}

1009
fn C_array(TypeRef ty, vec[ValueRef] elts) -> ValueRef {
1010 1011
    ret llvm.LLVMConstArray(ty, Vec.buf[ValueRef](elts),
                            Vec.len[ValueRef](elts));
1012 1013
}

1014
fn decl_fn(ModuleRef llmod, str name, uint cc, TypeRef llty) -> ValueRef {
1015
    let ValueRef llfn =
1016
        llvm.LLVMAddFunction(llmod, Str.buf(name), llty);
1017
    llvm.LLVMSetFunctionCallConv(llfn, cc);
1018 1019 1020
    ret llfn;
}

1021 1022
fn decl_cdecl_fn(ModuleRef llmod, str name, TypeRef llty) -> ValueRef {
    ret decl_fn(llmod, name, lib.llvm.LLVMCCallConv, llty);
1023 1024
}

1025 1026
fn decl_fastcall_fn(ModuleRef llmod, str name, TypeRef llty) -> ValueRef {
    ret decl_fn(llmod, name, lib.llvm.LLVMFastCallConv, llty);
1027 1028
}

1029
fn decl_internal_fastcall_fn(ModuleRef llmod,
1030
                            str name, TypeRef llty) -> ValueRef {
1031
    auto llfn = decl_fn(llmod, name, lib.llvm.LLVMFastCallConv, llty);
1032
    llvm.LLVMSetLinkage(llfn, lib.llvm.LLVMInternalLinkage as llvm.Linkage);
1033 1034 1035
    ret llfn;
}

1036 1037
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()));
1038 1039
}

1040
fn decl_native_glue(ModuleRef llmod, type_names tn,
1041 1042 1043 1044 1045 1046 1047 1048
                    abi.native_glue_type ngt, uint _n) -> ValueRef {
    let bool pass_task;
    alt (ngt) {
        case (abi.ngt_rust)         { pass_task = true; }
        case (abi.ngt_pure_rust)    { pass_task = true; }
        case (abi.ngt_cdecl)        { pass_task = false; }
    }

1049
    // It doesn't actually matter what type we come up with here, at the
1050 1051
    // moment, as we cast the native function pointers to int before passing
    // them to the indirect native-invocation glue.  But eventually we'd like
1052
    // to call them directly, once we have a calling convention worked out.
1053
    let int n = _n as int;
1054
    let str s = abi.native_glue_name(n, ngt);
1055
    let vec[TypeRef] args = vec(T_int()); // callee
1056

1057 1058
    if (!pass_task) {
        args += vec(T_int()); // taskptr, will not be passed
1059
    }
1060

1061
    args += Vec.init_elt[TypeRef](T_int(), n as uint);
1062

1063
    ret decl_fastcall_fn(llmod, s, T_fn(args, T_int()));
1064 1065
}

1066 1067 1068
fn get_extern_fn(&hashmap[str, ValueRef] externs,
                 ModuleRef llmod, str name,
                 uint cc, TypeRef ty) -> ValueRef {
1069 1070
    if (externs.contains_key(name)) {
        ret externs.get(name);
1071
    }
1072
    auto f = decl_fn(llmod, name, cc, ty);
1073
    externs.insert(name, f);
1074 1075 1076
    ret f;
}

1077 1078 1079 1080 1081
fn get_extern_const(&hashmap[str, ValueRef] externs,
                    ModuleRef llmod, str name, TypeRef ty) -> ValueRef {
    if (externs.contains_key(name)) {
        ret externs.get(name);
    }
1082
    auto c = llvm.LLVMAddGlobal(llmod, ty, Str.buf(name));
1083 1084 1085 1086 1087
    externs.insert(name, c);
    ret c;
}

fn get_simple_extern_fn(&hashmap[str, ValueRef] externs,
1088
                     ModuleRef llmod, str name, int n_args) -> ValueRef {
1089
    auto inputs = Vec.init_elt[TypeRef](T_int(), n_args as uint);
1090 1091 1092 1093 1094
    auto output = T_int();
    auto t = T_fn(inputs, output);
    ret get_extern_fn(externs, llmod, name, lib.llvm.LLVMCCallConv, t);
}

1095 1096
fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args, bool pure)
        -> result {
1097
    auto cxx = cx.fcx.lcx.ccx;
1098 1099
    auto lltaskptr = cx.build.PtrToInt(cx.fcx.lltaskptr, T_int());
    auto args2 = vec(lltaskptr) + args;
1100 1101 1102
    auto t = trans_native_call(cx.build, cxx.glues, lltaskptr,
                               cxx.externs, cxx.tn, cxx.llmod, name,
                               true, args2);
1103 1104 1105
    ret res(cx, t);
}

1106 1107 1108 1109
fn trans_native_call(builder b, @glue_fns glues, ValueRef lltaskptr,
                     &hashmap[str, ValueRef] externs,
                     type_names tn, ModuleRef llmod, str name,
                     bool pass_task, vec[ValueRef] args) -> ValueRef {
1110
    let int n = (Vec.len[ValueRef](args) as int);
1111
    let ValueRef llnative = get_simple_extern_fn(externs, llmod, name, n);
1112
    llnative = llvm.LLVMConstPointerCast(llnative, T_int());
1113

1114 1115
    let ValueRef llglue;
    if (pass_task) {
1116
        llglue = glues.native_glues_rust.(n);
1117
    } else {
1118
        llglue = glues.native_glues_cdecl.(n);
1119
    }
1120
    let vec[ValueRef] call_args = vec(llnative);
1121

1122 1123 1124
    if (!pass_task) {
        call_args += vec(lltaskptr);
    }
1125

1126
    for (ValueRef a in args) {
1127
        call_args += vec(b.ZExtOrBitCast(a, T_int()));
1128
    }
1129

1130
    ret b.FastCall(llglue, call_args);
1131 1132
}

1133
fn trans_non_gc_free(@block_ctxt cx, ValueRef v) -> result {
1134
    ret trans_upcall(cx, "upcall_free", vec(vp2i(cx, v), C_int(0)), false);
1135 1136
}

1137
fn find_scope_cx(@block_ctxt cx) -> @block_ctxt {
1138
    if (cx.kind != NON_SCOPE_BLOCK) {
1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150
        ret cx;
    }
    alt (cx.parent) {
        case (parent_some(?b)) {
            be find_scope_cx(b);
        }
        case (parent_none) {
            fail;
        }
    }
}

1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162
fn find_outer_scope_cx(@block_ctxt cx) -> @block_ctxt {
    auto scope_cx = find_scope_cx(cx);
    alt (cx.parent) {
        case (parent_some(?b)) {
            be find_scope_cx(b);
        }
        case (parent_none) {
            fail;
        }
    }
}

1163 1164 1165 1166 1167
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);
}

1168 1169 1170 1171 1172
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);
}

1173 1174 1175 1176 1177 1178
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));
}

1179 1180 1181 1182 1183
// 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);
}

1184
fn llsize_of(TypeRef t) -> ValueRef {
1185 1186 1187
    ret llvm.LLVMConstIntCast(lib.llvm.llvm.LLVMSizeOf(t), T_int(), False);
}

1188
fn llalign_of(TypeRef t) -> ValueRef {
1189 1190 1191
    ret llvm.LLVMConstIntCast(lib.llvm.llvm.LLVMAlignOf(t), T_int(), False);
}

1192
fn size_of(@block_ctxt cx, ty.t t) -> result {
1193
    if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
1194
        ret res(cx, llsize_of(type_of(cx.fcx.lcx.ccx, t)));
1195 1196 1197 1198
    }
    ret dynamic_size_of(cx, t);
}

1199
fn align_of(@block_ctxt cx, ty.t t) -> result {
1200
    if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
1201
        ret res(cx, llalign_of(type_of(cx.fcx.lcx.ccx, t)));
1202 1203 1204 1205
    }
    ret dynamic_align_of(cx, t);
}

1206 1207 1208 1209 1210 1211 1212 1213 1214
fn alloca(@block_ctxt cx, TypeRef t) -> ValueRef {
    ret new_builder(cx.fcx.llallocas).Alloca(t);
}

fn array_alloca(@block_ctxt cx, TypeRef t, ValueRef n) -> ValueRef {
    ret new_builder(cx.fcx.llallocas).ArrayAlloca(t, n);
}


1215 1216 1217 1218
// Creates a simpler, size-equivalent type. The resulting type is guaranteed
// to have (a) the same size as the type that was passed in; (b) to be non-
// recursive. This is done by replacing all boxes in a type with boxed unit
// types.
1219 1220
fn simplify_type(@crate_ctxt ccx, ty.t typ) -> ty.t {
    fn simplifier(@crate_ctxt ccx, ty.t typ) -> ty.t {
1221
        alt (ty.struct(ccx.tcx, typ)) {
1222
            case (ty.ty_box(_)) {
1223
                ret ty.mk_imm_box(ccx.tcx, ty.mk_nil(ccx.tcx));
1224 1225 1226 1227
            }
            case (_) { ret typ; }
        }
    }
1228
    auto f = bind simplifier(ccx, _);
1229
    ret ty.fold_ty(ccx.tcx, f, typ);
1230 1231
}

1232
// Computes the size of the data part of a non-dynamically-sized tag.
1233
fn static_size_of_tag(@crate_ctxt cx, ty.t t) -> uint {
1234
    if (ty.type_has_dynamic_size(cx.tcx, t)) {
1235
        log_err "dynamically sized type passed to static_size_of_tag()";
1236 1237 1238 1239 1240 1241 1242
        fail;
    }

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

B
Brian Anderson 已提交
1243
    auto tid;
1244
    let vec[ty.t] subtys;
1245
    alt (ty.struct(cx.tcx, t)) {
1246 1247 1248 1249 1250
        case (ty.ty_tag(?tid_, ?subtys_)) {
            tid = tid_;
            subtys = subtys_;
        }
        case (_) {
1251
            log_err "non-tag passed to static_size_of_tag()";
1252 1253 1254 1255 1256 1257 1258
            fail;
        }
    }

    // Compute max(variant sizes).
    auto max_size = 0u;
    auto variants = tag_variants(cx, tid);
1259
    for (variant_info variant in variants) {
1260
        auto tup_ty = simplify_type(cx, ty.mk_imm_tup(cx.tcx, variant.args));
1261

1262
        // Perform any type parameter substitutions.
1263 1264
        tup_ty = ty.bind_params_in_type(cx.tcx, tup_ty);
        tup_ty = ty.substitute_type_params(cx.tcx, subtys, tup_ty);
1265

1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277
        // 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;
}

1278 1279
fn dynamic_size_of(@block_ctxt cx, ty.t t) -> result {
    fn align_elements(@block_ctxt cx, vec[ty.t] elts) -> result {
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290
        //
        // 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;
1291
        for (ty.t e in elts) {
1292 1293 1294 1295 1296
            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);
1297
            off = bcx.build.Add(aligned_off, elt_size.val);
1298 1299 1300 1301 1302 1303
            max_align = umax(bcx, max_align, elt_align.val);
        }
        off = align_to(bcx, off, max_align);
        ret res(bcx, off);
    }

1304
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
1305
        case (ty.ty_param(?p)) {
1306
            auto szptr = field_of_tydesc(cx, t, false, abi.tydesc_field_size);
1307
            ret res(szptr.bcx, szptr.bcx.build.Load(szptr.val));
1308 1309
        }
        case (ty.ty_tup(?elts)) {
1310
            let vec[ty.t] tys = vec();
1311 1312 1313 1314
            for (ty.mt mt in elts) {
                tys += vec(mt.ty);
            }
            ret align_elements(cx, tys);
1315 1316
        }
        case (ty.ty_rec(?flds)) {
1317
            let vec[ty.t] tys = vec();
1318
            for (ty.field f in flds) {
1319
                tys += vec(f.mt.ty);
1320
            }
1321
            ret align_elements(cx, tys);
1322
        }
1323 1324 1325 1326
        case (ty.ty_tag(?tid, ?tps)) {
            auto bcx = cx;

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

1330
            auto variants = tag_variants(bcx.fcx.lcx.ccx, tid);
1331 1332
            for (variant_info variant in variants) {
                // Perform type substitution on the raw argument types.
1333 1334 1335
                let vec[ty.t] raw_tys = variant.args;
                let vec[ty.t] tys = vec();
                for (ty.t raw_ty in raw_tys) {
1336
                    auto t = ty.bind_params_in_type(cx.fcx.lcx.ccx.tcx,
1337
                                                    raw_ty);
1338
                    t = ty.substitute_type_params(cx.fcx.lcx.ccx.tcx, tps, t);
1339 1340 1341
                    tys += vec(t);
                }

1342 1343 1344 1345 1346 1347 1348 1349
                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);
            }

1350 1351 1352
            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);
1353
        }
1354 1355 1356
    }
}

1357
fn dynamic_align_of(@block_ctxt cx, ty.t t) -> result {
1358
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
1359
        case (ty.ty_param(?p)) {
1360
            auto aptr = field_of_tydesc(cx, t, false, abi.tydesc_field_align);
1361
            ret res(aptr.bcx, aptr.bcx.build.Load(aptr.val));
1362 1363 1364
        }
        case (ty.ty_tup(?elts)) {
            auto a = C_int(1);
1365
            auto bcx = cx;
1366 1367
            for (ty.mt e in elts) {
                auto align = align_of(bcx, e.ty);
1368 1369
                bcx = align.bcx;
                a = umax(bcx, a, align.val);
1370
            }
1371
            ret res(bcx, a);
1372 1373 1374
        }
        case (ty.ty_rec(?flds)) {
            auto a = C_int(1);
1375
            auto bcx = cx;
1376
            for (ty.field f in flds) {
1377
                auto align = align_of(bcx, f.mt.ty);
1378 1379
                bcx = align.bcx;
                a = umax(bcx, a, align.val);
1380
            }
1381
            ret res(bcx, a);
1382
        }
1383 1384 1385
        case (ty.ty_tag(_, _)) {
            ret res(cx, C_int(1)); // FIXME: stub
        }
1386 1387 1388
    }
}

1389
// Replacement for the LLVM 'GEP' instruction when field-indexing into a
1390 1391 1392 1393
// 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.
1394

1395
fn GEP_tup_like(@block_ctxt cx, ty.t t,
1396
                ValueRef base, vec[int] ixs) -> result {
1397

1398
    assert (ty.type_is_tup_like(cx.fcx.lcx.ccx.tcx, t));
1399 1400 1401

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

1402
    if (! ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
1403 1404
        let vec[ValueRef] v = vec();
        for (int i in ixs) {
1405
            v += vec(C_int(i));
1406
        }
1407
        ret res(cx, cx.build.GEP(base, v));
1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426
    }

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

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

1430
        let uint len = Vec.len[int](ixs);
1431 1432 1433 1434 1435

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

1436
        assert (len > 1u);
1437 1438 1439 1440 1441

        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.
1442
            assert (ixs.(n) == 0);
1443
            ret split_type(ccx, t, ixs, n+1u);
1444 1445
        }

1446
        assert (n < len);
1447 1448

        let int ix = ixs.(n);
1449
        let vec[ty.t] prefix = vec();
1450 1451
        let int i = 0;
        while (i < ix) {
1452
            Vec.push[ty.t](prefix,
1453
                            ty.get_element_type(ccx.tcx, t, i as uint));
1454
            i += 1 ;
1455 1456
        }

1457
        auto selected = ty.get_element_type(ccx.tcx, t, i as uint);
1458 1459 1460 1461 1462 1463 1464 1465 1466

        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.
1467
            auto inner = split_type(ccx, selected, ixs, n+1u);
1468 1469 1470 1471 1472 1473 1474 1475 1476
            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.

1477
    auto s = split_type(cx.fcx.lcx.ccx, t, ixs, 0u);
1478
    auto prefix_ty = ty.mk_imm_tup(cx.fcx.lcx.ccx.tcx, s.prefix);
1479 1480 1481 1482 1483
    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));
1484

1485
    if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, s.target)) {
1486
        ret res(bcx, bumped);
1487
    }
1488

1489
    auto typ = T_ptr(type_of(bcx.fcx.lcx.ccx, s.target));
1490
    ret res(bcx, bcx.build.PointerCast(bumped, typ));
1491 1492
}

1493 1494 1495 1496
// 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.
1497 1498 1499 1500
fn GEP_tag(@block_ctxt cx,
           ValueRef llblobptr,
           &ast.def_id tag_id,
           &ast.def_id variant_id,
1501
           vec[ty.t] ty_substs,
1502
           int ix)
1503
        -> result {
1504
    auto variant = tag_variant_with_id(cx.fcx.lcx.ccx, tag_id, variant_id);
1505

1506 1507
    // Synthesize a tuple type so that GEP_tup_like() can work its magic.
    // Separately, store the type of the element we're interested in.
1508
    auto arg_tys = variant.args;
1509
    auto elem_ty = ty.mk_nil(cx.fcx.lcx.ccx.tcx); // typestate infelicity
1510
    auto i = 0;
1511 1512
    let vec[ty.t] true_arg_tys = vec();
    for (ty.t aty in arg_tys) {
1513 1514
        auto arg_ty = ty.bind_params_in_type(cx.fcx.lcx.ccx.tcx, aty);
        arg_ty = ty.substitute_type_params(cx.fcx.lcx.ccx.tcx, ty_substs,
1515
                                           arg_ty);
1516
        true_arg_tys += vec(arg_ty);
1517
        if (i == ix) {
1518
            elem_ty = arg_ty;
1519 1520 1521 1522
        }

        i += 1;
    }
1523

1524
    auto tup_ty = ty.mk_imm_tup(cx.fcx.lcx.ccx.tcx, true_arg_tys);
1525 1526 1527 1528

    // 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;
1529
    if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, tup_ty)) {
1530
        auto llty = type_of(cx.fcx.lcx.ccx, tup_ty);
1531 1532 1533 1534 1535 1536 1537 1538 1539 1540
        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;
1541
    if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, elem_ty)) {
1542
        auto llelemty = type_of(rslt.bcx.fcx.lcx.ccx, elem_ty);
1543 1544 1545 1546 1547 1548 1549 1550
        val = rslt.bcx.build.PointerCast(rslt.val, T_ptr(llelemty));
    } else {
        val = rslt.val;
    }

    ret res(rslt.bcx, val);
}

1551

1552
fn trans_raw_malloc(@block_ctxt cx, TypeRef llptr_ty, ValueRef llsize)
1553
        -> result {
1554 1555
    // FIXME: need a table to collect tydesc globals.
    auto tydesc = C_int(0);
1556
    auto rslt = trans_upcall(cx, "upcall_malloc", vec(llsize, tydesc), false);
1557
    rslt = res(rslt.bcx, vi2p(rslt.bcx, rslt.val, llptr_ty));
1558 1559 1560
    ret rslt;
}

1561
fn trans_malloc_boxed(@block_ctxt cx, ty.t t) -> result {
1562 1563
    // Synthesize a fake box type structurally so we have something
    // to measure the size of.
1564 1565 1566
    auto boxed_body = ty.mk_imm_tup(cx.fcx.lcx.ccx.tcx,
                                    vec(ty.mk_int(cx.fcx.lcx.ccx.tcx), t));
    auto box_ptr = ty.mk_imm_box(cx.fcx.lcx.ccx.tcx, t);
1567
    auto sz = size_of(cx, boxed_body);
1568
    auto llty = type_of(cx.fcx.lcx.ccx, box_ptr);
1569
    ret trans_raw_malloc(sz.bcx, llty, sz.val);
1570 1571 1572
}


1573 1574 1575 1576 1577
// 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.
1578 1579 1580
fn field_of_tydesc(@block_ctxt cx, ty.t t, bool escapes, int field)
        -> result {
    auto tydesc = get_tydesc(cx, t, escapes);
1581 1582
    ret res(tydesc.bcx,
            tydesc.bcx.build.GEP(tydesc.val, vec(C_int(0), C_int(field))));
1583
}
1584

1585
// Given a type containing ty params, build a vector containing a ValueRef for
1586 1587
// each of the ty params it uses (from the current frame) and a vector of the
// indices of the ty params present in the type. This is used solely for
1588
// constructing derived tydescs.
1589
fn linearize_ty_params(@block_ctxt cx, ty.t t) ->
1590
        tup(vec[uint], vec[ValueRef]) {
1591
    let vec[ValueRef] param_vals = vec();
1592
    let vec[uint] param_defs = vec();
1593
    type rr = rec(@block_ctxt cx,
1594
                  mutable vec[ValueRef] vals,
1595
                  mutable vec[uint] defs);
1596

1597
    fn linearizer(@rr r, ty.t t) {
1598
        alt(ty.struct(r.cx.fcx.lcx.ccx.tcx, t)) {
1599 1600 1601 1602 1603
            case (ty.ty_param(?pid)) {
                let bool seen = false;
                for (uint d in r.defs) {
                    if (d == pid) {
                        seen = true;
1604 1605
                    }
                }
1606
                if (!seen) {
1607
                    r.vals += vec(r.cx.fcx.lltydescs.(pid));
1608 1609
                    r.defs += vec(pid);
                }
1610
            }
1611
            case (_) { }
1612 1613 1614 1615 1616 1617 1618 1619
        }
    }


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

1620
    auto f = bind linearizer(x, _);
1621
    ty.walk_ty(cx.fcx.lcx.ccx.tcx, f, t);
1622 1623 1624 1625

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

1626
fn trans_stack_local_derived_tydesc(@block_ctxt cx, ValueRef llsz,
1627 1628
        ValueRef llalign, ValueRef llroottydesc,
        Option.t[ValueRef] llparamtydescs) -> result {
1629
    auto llmyroottydesc = alloca(cx, T_tydesc(cx.fcx.lcx.ccx.tn));
1630 1631 1632

    // By convention, desc 0 is the root descriptor.
    llroottydesc = cx.build.Load(llroottydesc);
1633
    cx.build.Store(llroottydesc, llmyroottydesc);
1634 1635

    // Store a pointer to the rest of the descriptors.
1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648
    auto llrootfirstparam = cx.build.GEP(llmyroottydesc,
                                         vec(C_int(0), C_int(0)));

    auto llfirstparam;
    alt (llparamtydescs) {
        case (none[ValueRef]) {
            llfirstparam = C_null(val_ty(llrootfirstparam));
        }
        case (some[ValueRef](?llparamtydescs)) {
            llfirstparam = cx.build.GEP(llparamtydescs,
                                        vec(C_int(0), C_int(0)));
        }
    }
1649
    cx.build.Store(llfirstparam,
1650
                   cx.build.GEP(llmyroottydesc, vec(C_int(0), C_int(0))));
1651

1652 1653 1654 1655
    cx.build.Store(llsz,
                   cx.build.GEP(llmyroottydesc, vec(C_int(0), C_int(1))));
    cx.build.Store(llalign,
                   cx.build.GEP(llmyroottydesc, vec(C_int(0), C_int(2))));
1656

1657
    ret res(cx, llmyroottydesc);
1658 1659
}

1660 1661 1662 1663
fn mk_derived_tydesc(@block_ctxt cx, ty.t t, bool escapes) -> result {
    let uint n_params = ty.count_ty_params(cx.fcx.lcx.ccx.tcx, t);
    auto tys = linearize_ty_params(cx, t);

1664 1665
    assert (n_params == Vec.len[uint](tys._0));
    assert (n_params == Vec.len[ValueRef](tys._1));
1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676

    auto root = get_static_tydesc(cx, t, tys._0).tydesc;

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

    auto v;
    if (escapes) {
1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689
        auto tydescs = alloca(cx, T_array(T_ptr(T_tydesc(cx.fcx.lcx.ccx.tn)),
                                          1u /* for root*/ + n_params));

        auto i = 0;
        auto tdp = cx.build.GEP(tydescs, vec(C_int(0), C_int(i)));
        cx.build.Store(root, tdp);
        i += 1;
        for (ValueRef td in tys._1) {
            auto tdp = cx.build.GEP(tydescs, vec(C_int(0), C_int(i)));
            cx.build.Store(td, tdp);
            i += 1;
        }

1690 1691 1692 1693 1694 1695 1696
        v = trans_upcall(bcx, "upcall_get_type_desc",
                         vec(p2i(bcx.fcx.lcx.ccx.crate_ptr),
                             sz.val,
                             align.val,
                             C_int((1u + n_params) as int),
                             vp2i(bcx, tydescs)), true);
    } else {
1697 1698 1699 1700 1701 1702
        auto llparamtydescs_opt;
        if (n_params == 0u) {
            llparamtydescs_opt = none[ValueRef];
        } else {
            auto llparamtydescs = alloca(cx,
                T_array(T_ptr(T_tydesc(cx.fcx.lcx.ccx.tn)), n_params));
1703

1704 1705 1706 1707 1708 1709 1710 1711 1712
            auto i = 0;
            for (ValueRef td in tys._1) {
                auto tdp = cx.build.GEP(llparamtydescs,
                                        vec(C_int(0), C_int(i)));
                cx.build.Store(td, tdp);
                i += 1;
            }

            llparamtydescs_opt = some[ValueRef](llparamtydescs);
1713 1714 1715
        }

        v = trans_stack_local_derived_tydesc(bcx, sz.val, align.val, root,
1716
                                             llparamtydescs_opt);
1717 1718 1719 1720 1721
    }

    ret res(v.bcx, vi2p(v.bcx, v.val, T_ptr(T_tydesc(cx.fcx.lcx.ccx.tn))));
}

1722
fn get_tydesc(&@block_ctxt cx, ty.t t, bool escapes) -> result {
1723
    // Is the supplied type a type param? If so, return the passed-in tydesc.
1724
    alt (ty.type_param(cx.fcx.lcx.ccx.tcx, t)) {
1725
        case (some[uint](?id)) { ret res(cx, cx.fcx.lltydescs.(id)); }
1726
        case (none[uint])      { /* fall through */ }
1727
    }
1728 1729

    // Does it contain a type param? If so, generate a derived tydesc.
1730

1731
    if (ty.type_contains_params(cx.fcx.lcx.ccx.tcx, t)) {
1732
        ret mk_derived_tydesc(cx, t, escapes);
1733 1734 1735
    }

    // Otherwise, generate a tydesc if necessary, and return it.
1736
    let vec[uint] tps = vec();
1737 1738
    auto st = get_static_tydesc(cx, t, tps).tydesc;
    ret res(cx, st);
1739 1740 1741 1742 1743 1744 1745 1746 1747
}

fn get_static_tydesc(&@block_ctxt cx,
                     ty.t t, vec[uint] ty_params) -> @tydesc_info {
    alt (cx.fcx.lcx.ccx.tydescs.find(t)) {
        case (some[@tydesc_info](?info)) {
            ret info;
        }
        case (none[@tydesc_info]) {
1748 1749 1750 1751 1752 1753 1754

            // FIXME: Use of a simplified tydesc (w/o names) removes a lot of
            // generated glue, but the compile time goes way down due to
            // greatly increasing the miss rate on the type_of cache elsewhere
            // in this file. Experiment with other approaches to this.

            /*
1755 1756 1757 1758 1759 1760 1761
            fn simplifier(ty.t typ) -> ty.t {
                ret @rec(cname=none[str] with *typ);
            }
            auto f = simplifier;
            auto t_simplified = ty.fold_ty(cx.fcx.lcx.ccx.tcx, f, t);
            auto info = declare_tydesc(cx.fcx.lcx, t_simplified);
            cx.fcx.lcx.ccx.tydescs.insert(t_simplified, info);
1762 1763 1764 1765
            */

            auto info = declare_tydesc(cx.fcx.lcx, t);
            cx.fcx.lcx.ccx.tydescs.insert(t, info);
1766 1767 1768
            define_tydesc(cx.fcx.lcx, t, ty_params);
            ret info;
        }
1769
    }
1770 1771
}

1772 1773 1774
// 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.
1775
fn declare_tydesc(@local_ctxt cx, ty.t t) -> @tydesc_info {
1776 1777 1778 1779 1780 1781
    auto take_glue = declare_generic_glue(cx, t, T_glue_fn(cx.ccx.tn),
                                          "take");
    auto drop_glue = declare_generic_glue(cx, t, T_glue_fn(cx.ccx.tn),
                                          "drop");
    auto cmp_glue = declare_generic_glue(cx, t, T_cmp_glue_fn(cx.ccx.tn),
                                         "cmp");
1782
    auto ccx = cx.ccx;
1783

1784 1785
    auto llsize;
    auto llalign;
1786
    if (!ty.type_has_dynamic_size(ccx.tcx, t)) {
1787
        auto llty = type_of(ccx, t);
1788 1789 1790 1791 1792 1793 1794 1795 1796
        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);
    }

1797
    auto glue_fn_ty = T_ptr(T_glue_fn(ccx.tn));
1798

1799
    auto name = mangle_name_by_type_only(ccx, t, "tydesc");
1800
    auto gvar = llvm.LLVMAddGlobal(ccx.llmod, T_tydesc(ccx.tn),
1801
                                   Str.buf(name));
1802
    auto tydesc = C_struct(vec(C_null(T_ptr(T_ptr(T_tydesc(ccx.tn)))),
1803 1804
                               llsize,
                               llalign,
1805 1806 1807 1808 1809 1810
                               take_glue,             // take_glue
                               drop_glue,             // drop_glue
                               C_null(glue_fn_ty),    // free_glue
                               C_null(glue_fn_ty),    // sever_glue
                               C_null(glue_fn_ty),    // mark_glue
                               C_null(glue_fn_ty),    // obj_drop_glue
1811 1812
                               C_null(glue_fn_ty),    // is_stateful
                               cmp_glue));            // cmp_glue
1813 1814 1815

    llvm.LLVMSetInitializer(gvar, tydesc);
    llvm.LLVMSetGlobalConstant(gvar, True);
1816
    llvm.LLVMSetLinkage(gvar, lib.llvm.LLVMInternalLinkage
1817
                        as llvm.Linkage);
1818

1819
    auto info = @rec(
1820 1821
        tydesc=gvar,
        take_glue=take_glue,
1822 1823
        drop_glue=drop_glue,
        cmp_glue=cmp_glue
1824
    );
1825

1826
    ret info;
1827 1828
}

1829
tag make_generic_glue_helper_fn {
1830
    mgghf_single(fn(@block_ctxt cx, ValueRef v, ty.t t));
1831
    mgghf_cmp;
1832 1833
}

1834
// declare_tydesc() above must have been called first.
1835
fn define_tydesc(@local_ctxt cx, ty.t t, vec[uint] ty_params) {
1836
    auto info = cx.ccx.tydescs.get(t);
1837 1838 1839
    auto gvar = info.tydesc;

    auto tg = make_take_glue;
1840
    make_generic_glue(cx, t, info.take_glue, mgghf_single(tg), ty_params);
1841
    auto dg = make_drop_glue;
1842
    make_generic_glue(cx, t, info.drop_glue, mgghf_single(dg), ty_params);
1843
    make_generic_glue(cx, t, info.cmp_glue, mgghf_cmp, ty_params);
1844 1845
}

1846
fn declare_generic_glue(@local_ctxt cx,
1847
                        ty.t t,
1848 1849
                        TypeRef llfnty,
                        str name) -> ValueRef {
1850
    auto fn_nm;
1851
    if (cx.ccx.sess.get_opts().debuginfo) {
1852 1853 1854 1855 1856
        fn_nm = mangle_name_by_type_only(cx.ccx, t, "glue_" + name);
        fn_nm = sanitize(fn_nm);
    } else {
        fn_nm = mangle_name_by_seq(cx.ccx, cx.path,  "glue_" + name);
    }
1857
    auto llfn = decl_internal_fastcall_fn(cx.ccx.llmod, fn_nm, llfnty);
1858
    ret llfn;
1859
}
1860

1861
fn make_generic_glue(@local_ctxt cx,
1862
                     ty.t t,
1863 1864 1865
                     ValueRef llfn,
                     make_generic_glue_helper_fn helper,
                     vec[uint] ty_params) -> ValueRef {
1866
    auto fcx = new_fn_ctxt(cx, llfn);
1867
    auto bcx = new_top_block_ctxt(fcx);
1868
    auto lltop = bcx.llbb;
1869

1870 1871 1872 1873
    // Any nontrivial glue is with values passed *by alias*; this is a
    // requirement since in many contexts glue is invoked indirectly and
    // the caller has no idea if it's dealing with something that can be
    // passed by value.
1874

1875
    auto llty;
1876
    if (ty.type_has_dynamic_size(cx.ccx.tcx, t)) {
1877 1878 1879 1880
        llty = T_ptr(T_i8());
    } else {
        llty = T_ptr(type_of(cx.ccx, t));
    }
1881

1882
    auto ty_param_count = Vec.len[uint](ty_params);
1883

1884
    auto lltyparams = llvm.LLVMGetParam(llfn, 3u);
1885

1886
    auto lltydescs = Vec.empty_mut[ValueRef]();
1887 1888 1889 1890
    auto p = 0u;
    while (p < ty_param_count) {
        auto llparam = bcx.build.GEP(lltyparams, vec(C_int(p as int)));
        llparam = bcx.build.Load(llparam);
1891
        Vec.grow_set[ValueRef](lltydescs, ty_params.(p), 0 as ValueRef,
1892 1893 1894
                                llparam);
        p += 1u;
    }
1895
    bcx.fcx.lltydescs = Vec.freeze[ValueRef](lltydescs);
1896

1897 1898
    auto llrawptr0 = llvm.LLVMGetParam(llfn, 4u);
    auto llval0 = bcx.build.BitCast(llrawptr0, llty);
G
Graydon Hoare 已提交
1899

1900 1901 1902 1903 1904 1905
    alt (helper) {
        case (mgghf_single(?single_fn)) {
            single_fn(bcx, llval0, t);
        }
        case (mgghf_cmp) {
            auto llrawptr1 = llvm.LLVMGetParam(llfn, 5u);
1906
            auto llval1 = bcx.build.BitCast(llrawptr1, llty);
1907

1908
            auto llcmpval = llvm.LLVMGetParam(llfn, 6u);
1909

1910
            make_cmp_glue(bcx, llval0, llval1, t, llcmpval);
1911
        }
1912
    }
1913

1914 1915 1916
    // Tie up the llallocas -> lltop edge.
    new_builder(fcx.llallocas).Br(lltop);

1917 1918 1919
    ret llfn;
}

1920
fn make_take_glue(@block_ctxt cx, ValueRef v, ty.t t) {
1921
    // NB: v is an *alias* of type t here, not a direct value.
1922
    auto bcx;
1923
    if (ty.type_is_boxed(cx.fcx.lcx.ccx.tcx, t)) {
1924
        bcx = incr_refcnt_of_boxed(cx, cx.build.Load(v)).bcx;
1925

1926
    } else if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, t)) {
1927 1928 1929 1930
        bcx = iter_structural_ty(cx, v, t,
                                 bind take_ty(_, _, _)).bcx;
    } else {
        bcx = cx;
1931
    }
1932
    bcx.build.RetVoid();
1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953
}

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());
}

1954
fn make_drop_glue(@block_ctxt cx, ValueRef v0, ty.t t) {
1955
    // NB: v0 is an *alias* of type t here, not a direct value.
1956
    auto rslt;
1957
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
1958
        case (ty.ty_str) {
1959
            auto v = cx.build.Load(v0);
1960
            rslt = decr_refcnt_and_if_zero
G
Graydon Hoare 已提交
1961 1962 1963
                (cx, v, bind trans_non_gc_free(_, v),
                 "free string",
                 T_int(), C_int(0));
1964 1965
        }

1966
        case (ty.ty_vec(_)) {
G
Graydon Hoare 已提交
1967
            fn hit_zero(@block_ctxt cx, ValueRef v,
1968
                        ty.t t) -> result {
G
Graydon Hoare 已提交
1969 1970
                auto res = iter_sequence(cx, v, t,
                                         bind drop_ty(_,_,_));
1971 1972 1973
                // FIXME: switch gc/non-gc on layer of the type.
                ret trans_non_gc_free(res.bcx, v);
            }
1974
            auto v = cx.build.Load(v0);
1975 1976 1977 1978
            rslt = decr_refcnt_and_if_zero(cx, v,
                                          bind hit_zero(_, v, t),
                                          "free vector",
                                          T_int(), C_int(0));
1979 1980
        }

1981
        case (ty.ty_box(?body_mt)) {
G
Graydon Hoare 已提交
1982
            fn hit_zero(@block_ctxt cx, ValueRef v,
1983
                        ty.t body_ty) -> result {
1984 1985 1986 1987
                auto body = cx.build.GEP(v,
                                         vec(C_int(0),
                                             C_int(abi.box_rc_field_body)));

1988
                auto body_val = load_if_immediate(cx, body, body_ty);
1989 1990 1991 1992
                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);
            }
1993
            auto v = cx.build.Load(v0);
1994 1995 1996 1997
            rslt = decr_refcnt_and_if_zero(cx, v,
                                           bind hit_zero(_, v, body_mt.ty),
                                           "free box",
                                           T_int(), C_int(0));
1998 1999
        }

B
Brian Anderson 已提交
2000 2001 2002
        case (ty.ty_port(_)) {
            fn hit_zero(@block_ctxt cx, ValueRef v) -> result {
                ret trans_upcall(cx, "upcall_del_port",
2003
                                 vec(vp2i(cx, v)), true);
B
Brian Anderson 已提交
2004
            }
2005
            auto v = cx.build.Load(v0);
2006 2007 2008 2009
            rslt = decr_refcnt_and_if_zero(cx, v,
                                           bind hit_zero(_, v),
                                           "free port",
                                           T_int(), C_int(0));
B
Brian Anderson 已提交
2010 2011 2012 2013 2014
        }

        case (ty.ty_chan(_)) {
            fn hit_zero(@block_ctxt cx, ValueRef v) -> result {
                ret trans_upcall(cx, "upcall_del_chan",
2015
                                 vec(vp2i(cx, v)), true);
B
Brian Anderson 已提交
2016
            }
2017
            auto v = cx.build.Load(v0);
2018 2019 2020 2021
            rslt = decr_refcnt_and_if_zero(cx, v,
                                           bind hit_zero(_, v),
                                           "free chan",
                                           T_int(), C_int(0));
B
Brian Anderson 已提交
2022 2023
        }

2024
        case (ty.ty_obj(_)) {
2025
            fn hit_zero(@block_ctxt cx, ValueRef b, ValueRef o) -> result {
2026
                auto body =
2027
                    cx.build.GEP(b,
2028 2029 2030 2031 2032 2033
                                 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)));
2034
                auto tydesc = cx.build.Load(tydescptr);
2035

M
Marijn Haverbeke 已提交
2036
                auto cx_ = maybe_call_dtor(cx, o);
2037 2038 2039

                // Call through the obj's own fields-drop glue first.
                call_tydesc_glue_full(cx_, body, tydesc,
2040
                                      abi.tydesc_field_drop_glue);
2041 2042 2043

                // Then free the body.
                // FIXME: switch gc/non-gc on layer of the type.
2044
                ret trans_non_gc_free(cx_, b);
2045 2046
            }
            auto box_cell =
2047
                cx.build.GEP(v0,
2048 2049 2050 2051 2052
                             vec(C_int(0),
                                 C_int(abi.obj_field_box)));

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

2053
            rslt = decr_refcnt_and_if_zero(cx, boxptr,
2054
                                           bind hit_zero(_, boxptr, v0),
2055 2056
                                           "free obj",
                                           T_int(), C_int(0));
2057 2058
        }

2059
        case (ty.ty_fn(_,_,_)) {
2060 2061 2062 2063 2064 2065 2066
            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)));
2067 2068 2069 2070
                auto bindings =
                    cx.build.GEP(body,
                                 vec(C_int(0),
                                     C_int(abi.closure_elt_bindings)));
2071 2072 2073 2074 2075

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

2077
                call_tydesc_glue_full(cx, bindings, cx.build.Load(tydescptr),
2078
                                      abi.tydesc_field_drop_glue);
2079

2080 2081 2082 2083 2084 2085

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

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

2092 2093 2094 2095
            rslt = decr_refcnt_and_if_zero(cx, boxptr,
                                           bind hit_zero(_, boxptr),
                                           "free fn",
                                           T_int(), C_int(0));
2096 2097
        }

2098
        case (_) {
2099
            if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, t)) {
2100 2101
                rslt = iter_structural_ty(cx, v0, t,
                                          bind drop_ty(_, _, _));
2102

2103 2104 2105
            } else if (ty.type_is_scalar(cx.fcx.lcx.ccx.tcx, t) ||
                       ty.type_is_native(cx.fcx.lcx.ccx.tcx, t) ||
                       ty.type_is_nil(cx.fcx.lcx.ccx.tcx, t)) {
2106
                rslt = res(cx, C_nil());
2107 2108
            } else {
                rslt = res(cx, C_nil());
2109 2110 2111
            }
        }
    }
2112 2113

    rslt.bcx.build.RetVoid();
2114 2115
}

2116 2117
fn decr_refcnt_and_if_zero(@block_ctxt cx,
                           ValueRef box_ptr,
2118
                           fn(@block_ctxt cx) -> result inner,
2119
                           str inner_name,
2120
                           TypeRef t_else, ValueRef v_else) -> result {
2121

2122
    auto load_rc_cx = new_sub_block_ctxt(cx, "load rc");
2123 2124 2125 2126
    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");

2127 2128
    auto null_test = cx.build.IsNull(box_ptr);
    cx.build.CondBr(null_test, next_cx.llbb, load_rc_cx.llbb);
2129

2130 2131 2132 2133 2134 2135 2136 2137 2138 2139

    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);
2140 2141 2142 2143

    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);
2144 2145 2146 2147
    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);
2148

2149
    auto phi = next_cx.build.Phi(t_else,
2150
                                 vec(v_else, v_else, v_else, inner_res.val),
2151
                                 vec(cx.llbb,
2152
                                     load_rc_cx.llbb,
2153
                                     rc_adj_cx.llbb,
2154 2155
                                     inner_res.bcx.llbb));

2156
    ret res(next_cx, phi);
2157 2158
}

2159 2160 2161 2162 2163
// Structural comparison: a rather involved form of glue.

fn make_cmp_glue(@block_ctxt cx,
                 ValueRef lhs0,
                 ValueRef rhs0,
2164
                 ty.t t,
2165 2166 2167 2168
                 ValueRef llop) {
    auto lhs = load_if_immediate(cx, lhs0, t);
    auto rhs = load_if_immediate(cx, rhs0, t);

2169
    if (ty.type_is_scalar(cx.fcx.lcx.ccx.tcx, t)) {
2170 2171
        make_scalar_cmp_glue(cx, lhs, rhs, t, llop);

2172
    } else if (ty.type_is_box(cx.fcx.lcx.ccx.tcx, t)) {
2173 2174 2175 2176 2177 2178 2179
        lhs = cx.build.GEP(lhs, vec(C_int(0), C_int(abi.box_rc_field_body)));
        rhs = cx.build.GEP(rhs, vec(C_int(0), C_int(abi.box_rc_field_body)));
        auto rslt = call_cmp_glue(cx, lhs, rhs, t, llop);

        rslt.bcx.build.Store(rslt.val, cx.fcx.llretptr);
        rslt.bcx.build.RetVoid();

2180 2181
    } else if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, t)
               || ty.type_is_sequence(cx.fcx.lcx.ccx.tcx, t)) {
2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211

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

        /*
         * We're doing lexicographic comparison here. We start with the
         * assumption that the two input elements are equal. Depending on
         * operator, this means that the result is either true or false;
         * equality produces 'true' for ==, <= and >=. It produces 'false' for
         * !=, < and >.
         *
         * We then move one element at a time through the structure checking
         * 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.
         */

        auto flag = alloca(scx, T_i1());
2212
        llvm.LLVMSetValueName(flag, Str.buf("flag"));
2213 2214

        auto r;
2215
        if (ty.type_is_sequence(cx.fcx.lcx.ccx.tcx, t)) {
2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229

            // If we hit == all the way through the minimum-shared-length
            // section, default to judging the relative sequence lengths.
            r = compare_integral_values(scx,
                                        vec_fill(scx, lhs),
                                        vec_fill(scx, rhs),
                                        false,
                                        llop);
            r.bcx.build.Store(r.val, flag);

        } else {
            // == and <= default to true if they find == all the way. <
            // defaults to false if it finds == all the way.
            auto result_if_equal = scx.build.ICmp(lib.llvm.LLVMIntNE, llop,
2230
                                                  C_u8(abi.cmp_glue_op_lt));
2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241
            scx.build.Store(result_if_equal, flag);
            r = res(scx, C_nil());
        }

        fn inner(@block_ctxt last_cx,
                 bool load_inner,
                 ValueRef flag,
                 ValueRef llop,
                 @block_ctxt cx,
                 ValueRef av0,
                 ValueRef bv0,
2242
                 ty.t t) -> result {
2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253

            auto cnt_cx = new_sub_block_ctxt(cx, "continue_comparison");
            auto stop_cx = new_sub_block_ctxt(cx, "stop_comparison");

            auto av = av0;
            auto bv = bv0;
            if (load_inner) {
                // If `load_inner` is true, then the pointer type will always
                // be i8, because the data part of a vector always has type
                // i8[]. So we need to cast it to the proper type.

2254
                if (!ty.type_has_dynamic_size(last_cx.fcx.lcx.ccx.tcx, t)) {
2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265
                    auto llelemty = T_ptr(type_of(last_cx.fcx.lcx.ccx, t));
                    av = cx.build.PointerCast(av, llelemty);
                    bv = cx.build.PointerCast(bv, llelemty);
                }

                av = load_if_immediate(cx, av, t);
                bv = load_if_immediate(cx, bv, t);
            }

            // First 'eq' comparison: if so, continue to next elts.
            auto eq_r = call_cmp_glue(cx, av, bv, t,
2266
                                      C_u8(abi.cmp_glue_op_eq));
2267 2268 2269 2270 2271 2272 2273 2274 2275
            eq_r.bcx.build.CondBr(eq_r.val, cnt_cx.llbb, stop_cx.llbb);

            // Second 'op' comparison: find out how this elt-pair decides.
            auto stop_r = call_cmp_glue(stop_cx, av, bv, t, llop);
            stop_r.bcx.build.Store(stop_r.val, flag);
            stop_r.bcx.build.Br(last_cx.llbb);
            ret res(cnt_cx, C_nil());
        }

2276
        if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, t)) {
2277 2278 2279 2280 2281 2282 2283 2284 2285
            r = iter_structural_ty_full(r.bcx, lhs, rhs, t,
                                        bind inner(next, false, flag, llop,
                                                   _, _, _, _));
        } else {
            auto lhs_p0 = vec_p0(r.bcx, lhs);
            auto rhs_p0 = vec_p0(r.bcx, rhs);
            auto min_len = umin(r.bcx, vec_fill(r.bcx, lhs),
                                vec_fill(r.bcx, rhs));
            auto rhs_lim = r.bcx.build.GEP(rhs_p0, vec(min_len));
2286
            auto elt_ty = ty.sequence_element_type(cx.fcx.lcx.ccx.tcx, t);
2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302
            r = size_of(r.bcx, elt_ty);
            r = iter_sequence_raw(r.bcx, lhs_p0, rhs_p0, rhs_lim, r.val,
                                  bind inner(next, true, flag, llop,
                                             _, _, _, elt_ty));
        }

        r.bcx.build.Br(next.llbb);
        auto v = next.build.Load(flag);

        next.build.Store(v, cx.fcx.llretptr);
        next.build.RetVoid();


    } else {
        // FIXME: compare obj, fn by pointer?
        trans_fail(cx, none[common.span],
2303
                   "attempt to compare values of type " +
2304
                   ty.ty_to_str(cx.fcx.lcx.ccx.tcx, t));
2305 2306 2307 2308
    }
}

// A helper function to create scalar comparison glue.
2309
fn make_scalar_cmp_glue(@block_ctxt cx, ValueRef lhs, ValueRef rhs, ty.t t,
2310
                        ValueRef llop) {
2311
    if (ty.type_is_fp(cx.fcx.lcx.ccx.tcx, t)) {
2312 2313 2314 2315
        make_fp_cmp_glue(cx, lhs, rhs, t, llop);
        ret;
    }

2316 2317
    if (ty.type_is_integral(cx.fcx.lcx.ccx.tcx, t) ||
            ty.type_is_bool(cx.fcx.lcx.ccx.tcx, t)) {
2318 2319 2320 2321
        make_integral_cmp_glue(cx, lhs, rhs, t, llop);
        ret;
    }

2322
    if (ty.type_is_nil(cx.fcx.lcx.ccx.tcx, t)) {
2323 2324 2325 2326 2327 2328
        cx.build.Store(C_bool(true), cx.fcx.llretptr);
        cx.build.RetVoid();
        ret;
    }

    trans_fail(cx, none[common.span],
2329
               "attempt to compare values of type " +
2330
               ty.ty_to_str(cx.fcx.lcx.ccx.tcx, t));
2331 2332 2333
}

// A helper function to create floating point comparison glue.
2334
fn make_fp_cmp_glue(@block_ctxt cx, ValueRef lhs, ValueRef rhs, ty.t fptype,
2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353
                    ValueRef llop) {
    auto last_cx = new_sub_block_ctxt(cx, "last");

    auto eq_cx = new_sub_block_ctxt(cx, "eq");
    auto eq_result = eq_cx.build.FCmp(lib.llvm.LLVMRealUEQ, lhs, rhs);
    eq_cx.build.Br(last_cx.llbb);

    auto lt_cx = new_sub_block_ctxt(cx, "lt");
    auto lt_result = lt_cx.build.FCmp(lib.llvm.LLVMRealULT, lhs, rhs);
    lt_cx.build.Br(last_cx.llbb);

    auto le_cx = new_sub_block_ctxt(cx, "le");
    auto le_result = le_cx.build.FCmp(lib.llvm.LLVMRealULE, lhs, rhs);
    le_cx.build.Br(last_cx.llbb);

    auto unreach_cx = new_sub_block_ctxt(cx, "unreach");
    unreach_cx.build.Unreachable();

    auto llswitch = cx.build.Switch(llop, unreach_cx.llbb, 3u);
2354 2355 2356
    llvm.LLVMAddCase(llswitch, C_u8(abi.cmp_glue_op_eq), eq_cx.llbb);
    llvm.LLVMAddCase(llswitch, C_u8(abi.cmp_glue_op_lt), lt_cx.llbb);
    llvm.LLVMAddCase(llswitch, C_u8(abi.cmp_glue_op_le), le_cx.llbb);
2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395

    auto last_result =
        last_cx.build.Phi(T_i1(), vec(eq_result, lt_result, le_result),
                          vec(eq_cx.llbb, lt_cx.llbb, le_cx.llbb));
    last_cx.build.Store(last_result, cx.fcx.llretptr);
    last_cx.build.RetVoid();
}

// A helper function to compare integral values. This is used by both
// `make_integral_cmp_glue` and `make_cmp_glue`.
fn compare_integral_values(@block_ctxt cx, ValueRef lhs, ValueRef rhs,
                           bool signed, ValueRef llop) -> result {
    auto lt_cmp; auto le_cmp;
    if (signed) {
        lt_cmp = lib.llvm.LLVMIntSLT;
        le_cmp = lib.llvm.LLVMIntSLE;
    } else {
        lt_cmp = lib.llvm.LLVMIntULT;
        le_cmp = lib.llvm.LLVMIntULE;
    }

    auto last_cx = new_sub_block_ctxt(cx, "last");

    auto eq_cx = new_sub_block_ctxt(cx, "eq");
    auto eq_result = eq_cx.build.ICmp(lib.llvm.LLVMIntEQ, lhs, rhs);
    eq_cx.build.Br(last_cx.llbb);

    auto lt_cx = new_sub_block_ctxt(cx, "lt");
    auto lt_result = lt_cx.build.ICmp(lt_cmp, lhs, rhs);
    lt_cx.build.Br(last_cx.llbb);

    auto le_cx = new_sub_block_ctxt(cx, "le");
    auto le_result = le_cx.build.ICmp(le_cmp, lhs, rhs);
    le_cx.build.Br(last_cx.llbb);

    auto unreach_cx = new_sub_block_ctxt(cx, "unreach");
    unreach_cx.build.Unreachable();

    auto llswitch = cx.build.Switch(llop, unreach_cx.llbb, 3u);
2396 2397 2398
    llvm.LLVMAddCase(llswitch, C_u8(abi.cmp_glue_op_eq), eq_cx.llbb);
    llvm.LLVMAddCase(llswitch, C_u8(abi.cmp_glue_op_lt), lt_cx.llbb);
    llvm.LLVMAddCase(llswitch, C_u8(abi.cmp_glue_op_le), le_cx.llbb);
2399 2400 2401 2402 2403 2404 2405 2406 2407

    auto last_result =
        last_cx.build.Phi(T_i1(), vec(eq_result, lt_result, le_result),
                          vec(eq_cx.llbb, lt_cx.llbb, le_cx.llbb));
    ret res(last_cx, last_result);
}

// A helper function to create integral comparison glue.
fn make_integral_cmp_glue(@block_ctxt cx, ValueRef lhs, ValueRef rhs,
2408
                          ty.t intype, ValueRef llop) {
2409
    auto r = compare_integral_values(cx, lhs, rhs,
2410
        ty.type_is_signed(cx.fcx.lcx.ccx.tcx, intype), llop);
2411 2412
    r.bcx.build.Store(r.val, r.bcx.fcx.llretptr);
    r.bcx.build.RetVoid();
2413 2414 2415
}


2416 2417
// Tag information

2418
type variant_info = rec(vec[ty.t] args, ty.t ctor_ty, ast.def_id id);
2419 2420 2421

// Returns information about the variants in a tag.
fn tag_variants(@crate_ctxt cx, ast.def_id id) -> vec[variant_info] {
2422
    if (cx.sess.get_targ_crate_num() != id._0) {
2423
        ret creader.get_tag_variants(cx.sess, cx.tcx, id);
2424 2425
    }

2426
    assert (cx.items.contains_key(id));
2427
    alt (cx.items.get(id).node) {
2428 2429 2430 2431
        case (ast.item_tag(_, ?variants, _, _, _)) {
            let vec[variant_info] result = vec();
            for (ast.variant variant in variants) {
                auto ctor_ty = node_ann_type(cx, variant.node.ann);
2432
                let vec[ty.t] arg_tys = vec();
2433
                if (Vec.len[ast.variant_arg](variant.node.args) > 0u) {
2434
                    for (ty.arg a in ty.ty_fn_args(cx.tcx, ctor_ty)) {
2435 2436 2437 2438 2439 2440 2441 2442
                        arg_tys += vec(a.ty);
                    }
                }
                auto did = variant.node.id;
                result += vec(rec(args=arg_tys, ctor_ty=ctor_ty, id=did));
            }
            ret result;
        }
2443 2444 2445 2446
    }
    fail;   // not reached
}

2447
// Returns information about the tag variant with the given ID.
2448 2449
fn tag_variant_with_id(@crate_ctxt cx,
                       &ast.def_id tag_id,
2450
                       &ast.def_id variant_id) -> variant_info {
2451 2452 2453
    auto variants = tag_variants(cx, tag_id);

    auto i = 0u;
2454
    while (i < Vec.len[variant_info](variants)) {
2455
        auto variant = variants.(i);
2456
        if (common.def_eq(variant.id, variant_id)) {
2457 2458 2459 2460 2461
            ret variant;
        }
        i += 1u;
    }

2462
    log_err "tag_variant_with_id(): no variant exists with that ID";
2463 2464 2465
    fail;
}

2466

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

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

2471
type val_pair_and_ty_fn =
2472
    fn(@block_ctxt cx, ValueRef av, ValueRef bv, ty.t t) -> result;
2473

2474
// Iterates through the elements of a structural type.
2475 2476
fn iter_structural_ty(@block_ctxt cx,
                      ValueRef v,
2477
                      ty.t t,
2478 2479
                      val_and_ty_fn f)
    -> result {
2480 2481 2482 2483
    fn adaptor_fn(val_and_ty_fn f,
                  @block_ctxt cx,
                  ValueRef av,
                  ValueRef bv,
2484
                  ty.t t) -> result {
2485 2486 2487 2488 2489 2490 2491 2492 2493 2494
        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,
2495
                           ty.t t,
2496 2497
                           val_pair_and_ty_fn f)
    -> result {
2498
    let result r = res(cx, C_nil());
2499

2500
    fn iter_boxpp(@block_ctxt cx,
2501 2502 2503 2504 2505
                  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);
2506 2507
        auto tnil = ty.mk_nil(cx.fcx.lcx.ccx.tcx);
        auto tbox = ty.mk_imm_box(cx.fcx.lcx.ccx.tcx, tnil);
2508 2509 2510

        auto inner_cx = new_sub_block_ctxt(cx, "iter box");
        auto next_cx = new_sub_block_ctxt(cx, "next");
2511
        auto null_test = cx.build.IsNull(box_a_ptr);
2512 2513
        cx.build.CondBr(null_test, next_cx.llbb, inner_cx.llbb);

2514
        auto r = f(inner_cx, box_a_ptr, box_b_ptr, tbox);
2515
        r.bcx.build.Br(next_cx.llbb);
2516
        ret res(next_cx, C_nil());
2517 2518
    }

2519
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
2520
        case (ty.ty_tup(?args)) {
2521
            let int i = 0;
2522
            for (ty.mt arg in args) {
2523 2524 2525 2526
                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;
2527
                r = f(r.bcx,
2528 2529
                      load_if_immediate(r.bcx, elt_a, arg.ty),
                      load_if_immediate(r.bcx, elt_b, arg.ty),
2530
                      arg.ty);
2531 2532 2533
                i += 1;
            }
        }
2534
        case (ty.ty_rec(?fields)) {
2535
            let int i = 0;
2536
            for (ty.field fld in fields) {
2537 2538 2539 2540
                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;
2541
                r = f(r.bcx,
2542 2543
                      load_if_immediate(r.bcx, llfld_a, fld.mt.ty),
                      load_if_immediate(r.bcx, llfld_b, fld.mt.ty),
2544
                      fld.mt.ty);
2545 2546 2547
                i += 1;
            }
        }
2548
        case (ty.ty_tag(?tid, ?tps)) {
2549
            auto variants = tag_variants(cx.fcx.lcx.ccx, tid);
2550
            auto n_variants = Vec.len[variant_info](variants);
2551

2552
            // Cast the tags to types we can GEP into.
2553
            auto lltagty = T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn);
2554 2555 2556 2557 2558 2559 2560
            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)));
2561 2562
            auto lldiscrim_a = cx.build.Load(lldiscrim_a_ptr);

2563 2564 2565 2566
            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)));
2567
            auto lldiscrim_b = cx.build.Load(lldiscrim_b_ptr);
G
Graydon Hoare 已提交
2568

2569 2570 2571
            // NB: we must hit the discriminant first so that structural
            // comparison know not to proceed when the discriminants differ.
            auto bcx = cx;
2572
            bcx = f(bcx, lldiscrim_a, lldiscrim_b,
2573
                    ty.mk_int(cx.fcx.lcx.ccx.tcx)).bcx;
2574 2575

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

2578
            auto llswitch = bcx.build.Switch(lldiscrim_a, unr_cx.llbb,
2579
                                             n_variants);
G
Graydon Hoare 已提交
2580

2581
            auto next_cx = new_sub_block_ctxt(bcx, "tag-iter-next");
2582 2583

            auto i = 0u;
2584
            for (variant_info variant in variants) {
2585
                auto variant_cx = new_sub_block_ctxt(bcx,
2586
                                                     "tag-iter-variant-" +
2587
                                                     UInt.to_str(i, 10u));
2588 2589
                llvm.LLVMAddCase(llswitch, C_int(i as int), variant_cx.llbb);

2590
                if (Vec.len[ty.t](variant.args) > 0u) {
2591
                    // N-ary variant.
2592
                    auto fn_ty = variant.ctor_ty;
2593
                    alt (ty.struct(bcx.fcx.lcx.ccx.tcx, fn_ty)) {
2594
                        case (ty.ty_fn(_, ?args, _)) {
2595
                            auto j = 0;
2596 2597
                            for (ty.arg a in args) {
                                auto v = vec(C_int(0), C_int(j as int));
2598

2599
                                auto rslt = GEP_tag(variant_cx, llunion_a_ptr,
2600
                                    tid, variant.id, tps, j);
2601 2602
                                auto llfldp_a = rslt.val;
                                variant_cx = rslt.bcx;
2603

2604
                                rslt = GEP_tag(variant_cx, llunion_b_ptr, tid,
2605
                                    variant.id, tps, j);
2606 2607
                                auto llfldp_b = rslt.val;
                                variant_cx = rslt.bcx;
2608

2609
                                auto ty_subst = ty.bind_params_in_type(
2610
                                    cx.fcx.lcx.ccx.tcx, a.ty);
2611
                                ty_subst = ty.substitute_type_params(
2612
                                    cx.fcx.lcx.ccx.tcx, tps, ty_subst);
2613

2614
                                auto llfld_a =
2615
                                    load_if_immediate(variant_cx,
2616
                                                         llfldp_a,
2617 2618
                                                         ty_subst);

2619
                                auto llfld_b =
2620
                                    load_if_immediate(variant_cx,
2621 2622 2623 2624 2625
                                                         llfldp_b,
                                                         ty_subst);

                                auto res = f(variant_cx,
                                             llfld_a, llfld_b, ty_subst);
2626
                                variant_cx = res.bcx;
2627
                                j += 1;
2628 2629
                            }
                        }
2630
                        case (_) { fail; }
2631
                    }
2632 2633 2634 2635 2636

                    variant_cx.build.Br(next_cx.llbb);
                } else {
                    // Nullary variant; nothing to do.
                    variant_cx.build.Br(next_cx.llbb);
2637 2638 2639 2640 2641 2642 2643
                }

                i += 1u;
            }

            ret res(next_cx, C_nil());
        }
2644
        case (ty.ty_fn(_,_,_)) {
2645 2646 2647 2648 2649 2650
            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,
2651 2652
                             vec(C_int(0),
                                 C_int(abi.fn_field_box)));
2653
            ret iter_boxpp(cx, box_cell_a, box_cell_b, f);
2654
        }
2655
        case (ty.ty_obj(_)) {
2656 2657 2658 2659 2660 2661
            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,
2662 2663
                             vec(C_int(0),
                                 C_int(abi.obj_field_box)));
2664
            ret iter_boxpp(cx, box_cell_a, box_cell_b, f);
2665
        }
2666
        case (_) {
2667
            cx.fcx.lcx.ccx.sess.unimpl("type in iter_structural_ty_full");
2668
        }
2669
    }
2670
    ret r;
2671 2672
}

2673 2674
// Iterates through a pointer range, until the src* hits the src_lim*.
fn iter_sequence_raw(@block_ctxt cx,
2675
                     ValueRef dst,     // elt*
2676 2677 2678
                     ValueRef src,     // elt*
                     ValueRef src_lim, // elt*
                     ValueRef elt_sz,
2679
                     val_pair_fn f) -> result {
2680 2681 2682

    auto bcx = cx;

2683
    let ValueRef dst_int = vp2i(bcx, dst);
2684 2685 2686 2687 2688 2689 2690 2691 2692
    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);

2693 2694
    let ValueRef dst_curr = cond_cx.build.Phi(T_int(),
                                              vec(dst_int), vec(bcx.llbb));
2695 2696 2697
    let ValueRef src_curr = cond_cx.build.Phi(T_int(),
                                              vec(src_int), vec(bcx.llbb));

2698
    auto end_test = cond_cx.build.ICmp(lib.llvm.LLVMIntULT,
2699 2700 2701 2702
                                       src_curr, src_lim_int);

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

2703
    auto dst_curr_ptr = vi2p(body_cx, dst_curr, T_ptr(T_i8()));
2704
    auto src_curr_ptr = vi2p(body_cx, src_curr, T_ptr(T_i8()));
2705

2706
    auto body_res = f(body_cx, dst_curr_ptr, src_curr_ptr);
2707 2708
    body_cx = body_res.bcx;

2709
    auto dst_next = body_cx.build.Add(dst_curr, elt_sz);
2710
    auto src_next = body_cx.build.Add(src_curr, elt_sz);
2711 2712
    body_cx.build.Br(cond_cx.llbb);

2713 2714
    cond_cx.build.AddIncomingToPhi(dst_curr, vec(dst_next),
                                   vec(body_cx.llbb));
2715 2716 2717 2718 2719 2720 2721 2722 2723 2724
    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*
2725
                       ty.t elt_ty,
2726 2727
                       val_and_ty_fn f) -> result {
    fn adaptor_fn(val_and_ty_fn f,
2728
                  ty.t elt_ty,
2729
                  @block_ctxt cx,
2730 2731
                  ValueRef dst,
                  ValueRef src) -> result {
2732
        auto llptrty;
2733
        if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, elt_ty)) {
2734
            auto llty = type_of(cx.fcx.lcx.ccx, elt_ty);
2735 2736 2737 2738 2739 2740
            llptrty = T_ptr(llty);
        } else {
            llptrty = T_ptr(T_ptr(T_i8()));
        }

        auto p = cx.build.PointerCast(src, llptrty);
2741
        ret f(cx, load_if_immediate(cx, p, elt_ty), elt_ty);
2742 2743
    }

2744
    auto elt_sz = size_of(cx, elt_ty);
2745 2746
    be iter_sequence_raw(elt_sz.bcx, src, src, src_lim, elt_sz.val,
                         bind adaptor_fn(f, elt_ty, _, _, _));
2747 2748 2749
}


2750 2751 2752
// Iterates through the elements of a vec or str.
fn iter_sequence(@block_ctxt cx,
                 ValueRef v,
2753
                 ty.t t,
2754 2755 2756 2757
                 val_and_ty_fn f) -> result {

    fn iter_sequence_body(@block_ctxt cx,
                          ValueRef v,
2758
                          ty.t elt_ty,
2759 2760 2761 2762 2763 2764 2765
                          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)));
2766

2767
        auto llunit_ty;
2768
        if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, elt_ty)) {
2769 2770
            llunit_ty = T_i8();
        } else {
2771
            llunit_ty = type_of(cx.fcx.lcx.ccx, elt_ty);
2772 2773
        }

2774
        auto bcx = cx;
2775

2776
        auto len = bcx.build.Load(lenptr);
2777
        if (trailing_null) {
2778 2779
            auto unit_sz = size_of(bcx, elt_ty);
            bcx = unit_sz.bcx;
2780
            len = bcx.build.Sub(len, unit_sz.val);
2781 2782
        }

2783 2784
        auto p1 = vi2p(bcx, bcx.build.Add(vp2i(bcx, p0), len),
                       T_ptr(llunit_ty));
2785

2786
        ret iter_sequence_inner(bcx, p0, p1, elt_ty, f);
2787 2788
    }

2789
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
2790 2791
        case (ty.ty_vec(?elt)) {
            ret iter_sequence_body(cx, v, elt.ty, f, false);
2792
        }
2793
        case (ty.ty_str) {
2794
            auto et = ty.mk_mach(cx.fcx.lcx.ccx.tcx, common.ty_u8);
2795
            ret iter_sequence_body(cx, v, et, f, true);
2796
        }
2797
        case (_) { fail; }
2798
    }
2799
    cx.fcx.lcx.ccx.sess.bug("bad type in trans.iter_sequence");
2800 2801 2802
    fail;
}

2803 2804 2805 2806 2807 2808 2809 2810 2811
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);
2812

2813 2814 2815 2816 2817
    cx.build.FastCall(llfn, vec(C_null(T_ptr(T_nil())),
                                cx.fcx.lltaskptr,
                                C_null(T_ptr(T_nil())),
                                lltydescs,
                                llrawptr));
2818 2819
}

2820
fn call_tydesc_glue(@block_ctxt cx, ValueRef v,
2821 2822
                    ty.t t, bool escapes, int field) -> result {
    auto td = get_tydesc(cx, t, escapes);
2823 2824 2825
    call_tydesc_glue_full(td.bcx,
                          spill_if_immediate(td.bcx, v, t),
                          td.val, field);
2826
    ret res(td.bcx, C_nil());
2827 2828
}

2829 2830 2831 2832 2833
fn maybe_call_dtor(@block_ctxt cx, ValueRef v) -> @block_ctxt {
    auto vtbl = cx.build.GEP(v, vec(C_int(0), C_int(abi.obj_field_vtbl)));
    vtbl = cx.build.Load(vtbl);
    auto dtor_ptr = cx.build.GEP(vtbl, vec(C_int(0), C_int(0)));
    dtor_ptr = cx.build.Load(dtor_ptr);
M
Marijn Haverbeke 已提交
2834
    auto self_t = llvm.LLVMGetElementType(val_ty(v));
2835
    dtor_ptr = cx.build.BitCast(dtor_ptr,
M
Marijn Haverbeke 已提交
2836
                                T_ptr(T_dtor(cx.fcx.lcx.ccx, self_t)));
2837 2838 2839 2840 2841 2842 2843
    
    auto dtor_cx = new_sub_block_ctxt(cx, "dtor");
    auto after_cx = new_sub_block_ctxt(cx, "after_dtor");
    auto test = cx.build.ICmp(lib.llvm.LLVMIntNE, dtor_ptr,
                              C_null(val_ty(dtor_ptr)));
    cx.build.CondBr(test, dtor_cx.llbb, after_cx.llbb);

M
Marijn Haverbeke 已提交
2844
    auto me = dtor_cx.build.Load(v);
2845
    dtor_cx.build.FastCall(dtor_ptr, vec(C_null(T_ptr(T_nil())),
M
Marijn Haverbeke 已提交
2846
                                         cx.fcx.lltaskptr, me));
2847 2848 2849 2850
    dtor_cx.build.Br(after_cx.llbb);
    ret after_cx;
}

2851 2852 2853 2854
fn call_cmp_glue(@block_ctxt cx,
                 ValueRef lhs,
                 ValueRef rhs,
                 ty.t t,
2855 2856 2857 2858 2859 2860 2861 2862 2863 2864
                 ValueRef llop) -> result {
    // We can't use call_tydesc_glue_full() and friends here because compare
    // glue has a special signature.

    auto lllhs = spill_if_immediate(cx, lhs, t);
    auto llrhs = spill_if_immediate(cx, rhs, t);

    auto llrawlhsptr = cx.build.BitCast(lllhs, T_ptr(T_i8()));
    auto llrawrhsptr = cx.build.BitCast(llrhs, T_ptr(T_i8()));

2865
    auto r = get_tydesc(cx, t, false);
2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889
    auto lltydescs =
        r.bcx.build.GEP(r.val, vec(C_int(0),
                                   C_int(abi.tydesc_field_first_param)));
    lltydescs = r.bcx.build.Load(lltydescs);
    auto llfnptr =
        r.bcx.build.GEP(r.val, vec(C_int(0),
                                   C_int(abi.tydesc_field_cmp_glue)));
    auto llfn = r.bcx.build.Load(llfnptr);

    auto llcmpresultptr = r.bcx.build.Alloca(T_i1());

    let vec[ValueRef] llargs = vec(llcmpresultptr,
                                   r.bcx.fcx.lltaskptr,
                                   C_null(T_ptr(T_nil())),
                                   lltydescs,
                                   llrawlhsptr,
                                   llrawrhsptr,
                                   llop);

    r.bcx.build.FastCall(llfn, llargs);

    ret res(r.bcx, r.bcx.build.Load(llcmpresultptr));
}

2890
fn take_ty(@block_ctxt cx, ValueRef v, ty.t t) -> result {
2891
    if (!ty.type_is_scalar(cx.fcx.lcx.ccx.tcx, t)) {
2892
        ret call_tydesc_glue(cx, v, t, false, abi.tydesc_field_take_glue);
2893
    }
2894
    ret res(cx, C_nil());
2895 2896
}

2897 2898
fn drop_slot(@block_ctxt cx,
             ValueRef slot,
2899
             ty.t t) -> result {
2900
    auto llptr = load_if_immediate(cx, slot, t);
2901 2902 2903 2904 2905 2906
    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;
2907 2908
}

2909 2910
fn drop_ty(@block_ctxt cx,
           ValueRef v,
2911
           ty.t t) -> result {
2912

2913
    if (!ty.type_is_scalar(cx.fcx.lcx.ccx.tcx, t)) {
2914
        ret call_tydesc_glue(cx, v, t, false, abi.tydesc_field_drop_glue);
2915
    }
2916
    ret res(cx, C_nil());
2917 2918
}

2919 2920 2921
fn call_memcpy(@block_ctxt cx,
               ValueRef dst,
               ValueRef src,
2922 2923 2924 2925 2926 2927
               ValueRef n_bytes,
               ValueRef align_bytes) -> result {
    // FIXME: switch to the 64-bit variant when on such a platform.
    auto i = cx.fcx.lcx.ccx.intrinsics;
    assert (i.contains_key("llvm.memcpy.p0i8.p0i8.i32"));
    auto memcpy = i.get("llvm.memcpy.p0i8.p0i8.i32");
2928 2929
    auto src_ptr = cx.build.PointerCast(src, T_ptr(T_i8()));
    auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940
    auto size = cx.build.IntCast(n_bytes, T_i32());
    auto align =
        if (lib.llvm.llvm.LLVMIsConstant(align_bytes) == True)
            { cx.build.IntCast(align_bytes, T_i32()) }
        else
            { cx.build.IntCast(C_int(0), T_i32()) };

    auto volatile = C_bool(false);
    ret res(cx, cx.build.Call(memcpy,
                              vec(dst_ptr, src_ptr,
                                  size, align, volatile)));
2941 2942
}

2943 2944
fn call_bzero(@block_ctxt cx,
              ValueRef dst,
2945 2946 2947 2948 2949 2950 2951
              ValueRef n_bytes,
              ValueRef align_bytes) -> result {

    // FIXME: switch to the 64-bit variant when on such a platform.
    auto i = cx.fcx.lcx.ccx.intrinsics;
    assert (i.contains_key("llvm.memset.p0i8.i32"));
    auto memset = i.get("llvm.memset.p0i8.i32");
2952
    auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963
    auto size = cx.build.IntCast(n_bytes, T_i32());
    auto align =
        if (lib.llvm.llvm.LLVMIsConstant(align_bytes) == True)
            { cx.build.IntCast(align_bytes, T_i32()) }
        else
            { cx.build.IntCast(C_int(0), T_i32()) };

    auto volatile = C_bool(false);
    ret res(cx, cx.build.Call(memset,
                              vec(dst_ptr, C_u8(0u),
                                  size, align, volatile)));
2964 2965
}

2966 2967 2968
fn memcpy_ty(@block_ctxt cx,
             ValueRef dst,
             ValueRef src,
2969
             ty.t t) -> result {
2970
    if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
2971 2972 2973
        auto llsz = size_of(cx, t);
        auto llalign = align_of(llsz.bcx, t);
        ret call_memcpy(llalign.bcx, dst, src, llsz.val, llalign.val);
2974 2975 2976 2977 2978 2979

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

2980 2981 2982 2983 2984
tag copy_action {
    INIT;
    DROP_EXISTING;
}

2985
fn copy_ty(@block_ctxt cx,
2986
           copy_action action,
2987 2988
           ValueRef dst,
           ValueRef src,
2989
           ty.t t) -> result {
2990 2991
    if (ty.type_is_scalar(cx.fcx.lcx.ccx.tcx, t) ||
            ty.type_is_native(cx.fcx.lcx.ccx.tcx, t)) {
2992 2993
        ret res(cx, cx.build.Store(src, dst));

2994
    } else if (ty.type_is_nil(cx.fcx.lcx.ccx.tcx, t)) {
2995 2996
        ret res(cx, C_nil());

2997
    } else if (ty.type_is_boxed(cx.fcx.lcx.ccx.tcx, t)) {
2998
        auto r = take_ty(cx, src, t);
2999
        if (action == DROP_EXISTING) {
3000
            r = drop_ty(r.bcx, r.bcx.build.Load(dst), t);
3001 3002 3003
        }
        ret res(r.bcx, r.bcx.build.Store(src, dst));

3004 3005
    } else if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, t) ||
               ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
3006
        auto r = take_ty(cx, src, t);
3007
        if (action == DROP_EXISTING) {
3008 3009
            r = drop_ty(r.bcx, dst, t);
        }
3010
        ret memcpy_ty(r.bcx, dst, src, t);
3011 3012
    }

3013
    cx.fcx.lcx.ccx.sess.bug("unexpected type in trans.copy_ty: " +
3014
                        ty.ty_to_str(cx.fcx.lcx.ccx.tcx, t));
3015 3016 3017
    fail;
}

3018
fn trans_lit(@crate_ctxt cx, &ast.lit lit, &ast.ann ann) -> ValueRef {
3019
    alt (lit.node) {
3020
        case (ast.lit_int(?i)) {
3021
            ret C_int(i);
3022 3023
        }
        case (ast.lit_uint(?u)) {
3024
            ret C_int(u as int);
3025
        }
3026 3027 3028 3029 3030
        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();
3031
            auto s = True;
3032
            alt (tm) {
3033 3034 3035 3036
                case (common.ty_u8) { t = T_i8(); s = False; }
                case (common.ty_u16) { t = T_i16(); s = False; }
                case (common.ty_u32) { t = T_i32(); s = False; }
                case (common.ty_u64) { t = T_i64(); s = False; }
G
Graydon Hoare 已提交
3037 3038 3039 3040 3041

                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(); }
3042
            }
3043
            ret C_integral(t, i as uint, s);
3044
        }
3045 3046 3047
        case(ast.lit_float(?fs)) {
            ret C_float(fs);
        }
3048 3049 3050 3051 3052 3053 3054 3055
        case(ast.lit_mach_float(?tm, ?s)) {
            auto t = T_float();
            alt(tm) {
                case(common.ty_f32) { t = T_f32(); }
                case(common.ty_f64) { t = T_f64(); }
            }
            ret C_floating(s, t);
        }
3056
        case (ast.lit_char(?c)) {
3057
            ret C_integral(T_char(), c as uint, False);
3058 3059
        }
        case (ast.lit_bool(?b)) {
3060
            ret C_bool(b);
3061 3062
        }
        case (ast.lit_nil) {
3063
            ret C_nil();
3064 3065
        }
        case (ast.lit_str(?s)) {
3066
            ret C_str(cx, s);
3067 3068 3069 3070
        }
    }
}

3071
fn target_type(@crate_ctxt cx, ty.t t) -> ty.t {
3072
    alt (ty.struct(cx.tcx, t)) {
3073
        case (ty.ty_int) {
3074
            auto struct_ty = ty.mk_mach(cx.tcx,
3075
                                        cx.sess.get_targ_cfg().int_type);
3076
            ret ty.copy_cname(cx.tcx, struct_ty, t);
3077
        }
3078
        case (ty.ty_uint) {
3079
            auto struct_ty = ty.mk_mach(cx.tcx,
3080
                                        cx.sess.get_targ_cfg().uint_type);
3081
            ret ty.copy_cname(cx.tcx, struct_ty, t);
3082
        }
3083
        case (_) { /* fall through */ }
3084 3085 3086 3087
    }
    ret t;
}

3088 3089

// Converts an annotation to a type
3090
fn node_ann_type(@crate_ctxt cx, &ast.ann a) -> ty.t {
3091
    ret target_type(cx, ty.ann_to_monotype(cx.tcx, a));
3092 3093
}

3094
fn node_ann_ty_params(&ast.ann a) -> vec[ty.t] {
3095 3096
    alt (a) {
        case (ast.ann_none) {
3097
            log_err "missing type annotation";
3098 3099
            fail;
        }
3100
        case (ast.ann_type(_, ?tps_opt, _)) {
3101
            alt (tps_opt) {
3102
                case (none[vec[ty.t]]) {
3103
                    log_err "type annotation has no ty params";
3104 3105
                    fail;
                }
3106
                case (some[vec[ty.t]](?tps)) { ret tps; }
3107 3108 3109 3110 3111
            }
        }
    }
}

3112 3113 3114 3115
fn node_type(@crate_ctxt cx, &ast.ann a) -> TypeRef {
    ret type_of(cx, node_ann_type(cx, a));
}

3116 3117
fn trans_unary(@block_ctxt cx, ast.unop op,
               @ast.expr e, &ast.ann a) -> result {
3118 3119

    auto sub = trans_expr(cx, e);
3120
    auto e_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, e);
3121

3122 3123
    alt (op) {
        case (ast.bitnot) {
3124
            sub = autoderef(sub.bcx, sub.val,
3125
                            ty.expr_ty(cx.fcx.lcx.ccx.tcx, e));
3126
            ret res(sub.bcx, sub.bcx.build.Not(sub.val));
3127 3128
        }
        case (ast.not) {
3129
            sub = autoderef(sub.bcx, sub.val,
3130
                            ty.expr_ty(cx.fcx.lcx.ccx.tcx, e));
3131
            ret res(sub.bcx, sub.bcx.build.Not(sub.val));
3132 3133
        }
        case (ast.neg) {
3134
            sub = autoderef(sub.bcx, sub.val,
3135 3136
                            ty.expr_ty(cx.fcx.lcx.ccx.tcx, e));
            if(ty.struct(cx.fcx.lcx.ccx.tcx, e_ty) == ty.ty_float) {
3137 3138 3139 3140 3141
                ret res(sub.bcx, sub.bcx.build.FNeg(sub.val));
            }
            else {
                ret res(sub.bcx, sub.bcx.build.Neg(sub.val));
            }
3142
        }
3143
        case (ast.box(_)) {
3144
            auto e_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, e);
3145
            auto e_val = sub.val;
3146
            auto box_ty = node_ann_type(sub.bcx.fcx.lcx.ccx, a);
3147 3148
            sub = trans_malloc_boxed(sub.bcx, e_ty);
            find_scope_cx(cx).cleanups +=
3149
                vec(clean(bind drop_ty(_, sub.val, box_ty)));
3150

3151 3152
            auto box = sub.val;
            auto rc = sub.bcx.build.GEP(box,
3153 3154
                                        vec(C_int(0),
                                            C_int(abi.box_rc_field_refcnt)));
3155 3156 3157 3158
            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);
3159 3160 3161 3162

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

3168
            sub = copy_ty(sub.bcx, INIT, body, e_val, e_ty);
3169
            ret res(sub.bcx, box);
3170
        }
3171
        case (ast.deref) {
3172
            log_err "deref expressions should have been translated using " +
3173 3174
                "trans_lval(), not trans_unary()";
            fail;
3175
        }
3176 3177 3178 3179
    }
    fail;
}

3180
fn trans_compare(@block_ctxt cx0, ast.binop op, ty.t t0,
3181
                 ValueRef lhs0, ValueRef rhs0) -> result {
3182
    // Autoderef both sides.
3183 3184 3185 3186 3187 3188 3189 3190 3191 3192
    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;

3193
    auto t = autoderefed_ty(cx.fcx.lcx.ccx, t0);
3194

3195 3196 3197
    // Determine the operation we need.
    // FIXME: Use or-patterns when we have them.
    auto llop;
3198
    alt (op) {
3199 3200 3201 3202 3203 3204
        case (ast.eq) { llop = C_u8(abi.cmp_glue_op_eq); }
        case (ast.lt) { llop = C_u8(abi.cmp_glue_op_lt); }
        case (ast.le) { llop = C_u8(abi.cmp_glue_op_le); }
        case (ast.ne) { llop = C_u8(abi.cmp_glue_op_eq); }
        case (ast.ge) { llop = C_u8(abi.cmp_glue_op_lt); }
        case (ast.gt) { llop = C_u8(abi.cmp_glue_op_le); }
3205 3206
    }

3207
    auto rslt = call_cmp_glue(cx, lhs, rhs, t, llop);
3208

3209 3210
    // Invert the result if necessary.
    // FIXME: Use or-patterns when we have them.
3211
    alt (op) {
3212 3213 3214 3215 3216 3217
        case (ast.eq) { ret res(rslt.bcx, rslt.val);                     }
        case (ast.lt) { ret res(rslt.bcx, rslt.val);                     }
        case (ast.le) { ret res(rslt.bcx, rslt.val);                     }
        case (ast.ne) { ret res(rslt.bcx, rslt.bcx.build.Not(rslt.val)); }
        case (ast.ge) { ret res(rslt.bcx, rslt.bcx.build.Not(rslt.val)); }
        case (ast.gt) { ret res(rslt.bcx, rslt.bcx.build.Not(rslt.val)); }
3218 3219 3220
    }
}

3221
fn trans_vec_append(@block_ctxt cx, ty.t t,
3222 3223
                    ValueRef lhs, ValueRef rhs) -> result {

3224
    auto elt_ty = ty.sequence_element_type(cx.fcx.lcx.ccx.tcx, t);
3225 3226

    auto skip_null = C_bool(false);
3227
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
3228 3229 3230 3231 3232 3233
        case (ty.ty_str) { skip_null = C_bool(true); }
        case (_) { }
    }

    auto bcx = cx;

3234
    auto llvec_tydesc = get_tydesc(bcx, t, false);
3235 3236
    bcx = llvec_tydesc.bcx;

3237
    auto llelt_tydesc = get_tydesc(bcx, elt_ty, false);
3238 3239
    bcx = llelt_tydesc.bcx;

3240 3241 3242
    auto dst = bcx.build.PointerCast(lhs, T_ptr(T_opaque_vec_ptr()));
    auto src = bcx.build.PointerCast(rhs, T_opaque_vec_ptr());

3243
    ret res(bcx, bcx.build.FastCall(cx.fcx.lcx.ccx.glues.vec_append_glue,
3244 3245 3246 3247
                                    vec(cx.fcx.lltaskptr,
                                        llvec_tydesc.val,
                                        llelt_tydesc.val,
                                        dst, src, skip_null)));
3248 3249
}

3250
fn trans_vec_add(@block_ctxt cx, ty.t t,
3251
                 ValueRef lhs, ValueRef rhs) -> result {
3252
    auto r = alloc_ty(cx, t);
3253 3254
    auto tmp = r.val;
    r = copy_ty(r.bcx, INIT, tmp, lhs, t);
3255
    auto bcx = trans_vec_append(r.bcx, t, tmp, rhs).bcx;
3256
    tmp = load_if_immediate(bcx, tmp, t);
3257 3258
    find_scope_cx(cx).cleanups +=
        vec(clean(bind drop_ty(_, tmp, t)));
3259
    ret res(bcx, tmp);
3260 3261 3262
}


3263
fn trans_eager_binop(@block_ctxt cx, ast.binop op, ty.t intype,
3264
                     ValueRef lhs, ValueRef rhs) -> result {
3265

3266
    auto is_float = false;
3267
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, intype)) {
3268 3269 3270 3271 3272 3273 3274
        case (ty.ty_float) {
            is_float = true;
        }
        case (_) {
            is_float = false;
        }
    }
3275

3276
    alt (op) {
3277
        case (ast.add) {
3278
            if (ty.type_is_sequence(cx.fcx.lcx.ccx.tcx, intype)) {
3279
                ret trans_vec_add(cx, intype, lhs, rhs);
3280
            }
3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296
            if (is_float) {
                ret res(cx, cx.build.FAdd(lhs, rhs));
            }
            else {
                ret res(cx, cx.build.Add(lhs, rhs));
            }
        }
        case (ast.sub) {
            if (is_float) {
                ret res(cx, cx.build.FSub(lhs, rhs));
            }
            else {
                ret res(cx, cx.build.Sub(lhs, rhs));
            }
        }

3297
        case (ast.mul) {
3298 3299 3300 3301 3302 3303
            if (is_float) {
                ret res(cx, cx.build.FMul(lhs, rhs));
            }
            else {
                ret res(cx, cx.build.Mul(lhs, rhs));
            }
3304
        }
3305

3306
        case (ast.div) {
3307 3308 3309
            if (is_float) {
                ret res(cx, cx.build.FDiv(lhs, rhs));
            }
3310
            if (ty.type_is_signed(cx.fcx.lcx.ccx.tcx, intype)) {
3311
                ret res(cx, cx.build.SDiv(lhs, rhs));
3312
            } else {
3313
                ret res(cx, cx.build.UDiv(lhs, rhs));
3314 3315 3316
            }
        }
        case (ast.rem) {
3317 3318 3319
            if (is_float) {
                ret res(cx, cx.build.FRem(lhs, rhs));
            }
3320
            if (ty.type_is_signed(cx.fcx.lcx.ccx.tcx, intype)) {
3321
                ret res(cx, cx.build.SRem(lhs, rhs));
3322
            } else {
3323
                ret res(cx, cx.build.URem(lhs, rhs));
3324 3325
            }
        }
3326

3327 3328 3329 3330 3331 3332
        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)); }
3333
        case (_) {
3334
            ret trans_compare(cx, op, intype, lhs, rhs);
3335 3336 3337 3338 3339
        }
    }
    fail;
}

3340
fn autoderef(@block_ctxt cx, ValueRef v, ty.t t) -> result {
3341
    let ValueRef v1 = v;
3342
    let ty.t t1 = t;
3343 3344

    while (true) {
3345
        alt (ty.struct(cx.fcx.lcx.ccx.tcx, t1)) {
3346
            case (ty.ty_box(?mt)) {
3347 3348 3349
                auto body = cx.build.GEP(v1,
                                         vec(C_int(0),
                                             C_int(abi.box_rc_field_body)));
3350
                t1 = mt.ty;
3351 3352 3353 3354 3355

                // Since we're changing levels of box indirection, we may have
                // to cast this pointer, since statically-sized tag types have
                // different types depending on whether they're behind a box
                // or not.
3356
                if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, mt.ty)) {
3357
                    auto llty = type_of(cx.fcx.lcx.ccx, mt.ty);
3358 3359 3360 3361 3362
                    v1 = cx.build.PointerCast(body, T_ptr(llty));
                } else {
                    v1 = body;
                }

3363
                v1 = load_if_immediate(cx, v1, t1);
3364 3365 3366 3367 3368 3369 3370 3371
            }
            case (_) {
                ret res(cx, v1);
            }
        }
    }
}

3372
fn autoderefed_ty(@crate_ctxt ccx, ty.t t) -> ty.t {
3373
    let ty.t t1 = t;
3374 3375

    while (true) {
3376
        alt (ty.struct(ccx.tcx, t1)) {
3377 3378
            case (ty.ty_box(?mt)) {
                t1 = mt.ty;
3379 3380 3381 3382 3383 3384 3385 3386
            }
            case (_) {
                ret t1;
            }
        }
    }
}

3387 3388
fn trans_binary(@block_ctxt cx, ast.binop op,
                @ast.expr a, @ast.expr b) -> result {
3389

3390 3391 3392 3393 3394 3395
    // First couple cases are lazy:

    alt (op) {
        case (ast.and) {
            // Lazy-eval and
            auto lhs_res = trans_expr(cx, a);
3396
            lhs_res = autoderef(lhs_res.bcx, lhs_res.val,
3397
                                ty.expr_ty(cx.fcx.lcx.ccx.tcx, a));
3398

3399
            auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
3400
            auto rhs_res = trans_expr(rhs_cx, b);
3401
            rhs_res = autoderef(rhs_res.bcx, rhs_res.val,
3402
                                ty.expr_ty(cx.fcx.lcx.ccx.tcx, b));
3403

3404
            auto lhs_false_cx = new_scope_block_ctxt(cx, "lhs false");
3405
            auto lhs_false_res = res(lhs_false_cx, C_bool(false));
3406 3407 3408

            lhs_res.bcx.build.CondBr(lhs_res.val,
                                     rhs_cx.llbb,
3409 3410 3411 3412
                                     lhs_false_cx.llbb);

            ret join_results(cx, T_bool(),
                             vec(lhs_false_res, rhs_res));
3413 3414 3415 3416 3417
        }

        case (ast.or) {
            // Lazy-eval or
            auto lhs_res = trans_expr(cx, a);
3418
            lhs_res = autoderef(lhs_res.bcx, lhs_res.val,
3419
                                ty.expr_ty(cx.fcx.lcx.ccx.tcx, a));
3420

3421
            auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
3422
            auto rhs_res = trans_expr(rhs_cx, b);
3423
            rhs_res = autoderef(rhs_res.bcx, rhs_res.val,
3424
                                ty.expr_ty(cx.fcx.lcx.ccx.tcx, b));
3425

3426
            auto lhs_true_cx = new_scope_block_ctxt(cx, "lhs true");
3427
            auto lhs_true_res = res(lhs_true_cx, C_bool(true));
3428 3429

            lhs_res.bcx.build.CondBr(lhs_res.val,
3430
                                     lhs_true_cx.llbb,
3431
                                     rhs_cx.llbb);
3432 3433 3434

            ret join_results(cx, T_bool(),
                             vec(lhs_true_res, rhs_res));
3435
        }
3436 3437

        case (_) {
3438 3439
            // Remaining cases are eager:
            auto lhs = trans_expr(cx, a);
3440
            auto lhty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, a);
3441
            lhs = autoderef(lhs.bcx, lhs.val, lhty);
3442
            auto rhs = trans_expr(lhs.bcx, b);
3443
            auto rhty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, b);
3444
            rhs = autoderef(rhs.bcx, rhs.val, rhty);
3445
            ret trans_eager_binop(rhs.bcx, op,
3446
                autoderefed_ty(cx.fcx.lcx.ccx, lhty), lhs.val, rhs.val);
3447
        }
3448 3449 3450 3451
    }
    fail;
}

3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462
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)) {
3463 3464 3465
            live += vec(r);
            vals += vec(r.val);
            bbs += vec(r.bcx.llbb);
3466 3467 3468
        }
    }

3469
    alt (Vec.len[result](live)) {
3470 3471 3472 3473
        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.
3474
            assert (Vec.len[result](ins) >= 1u);
3475 3476 3477
            ret ins.(0);
        }

3478
        case (_) { /* fall through */ }
3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489
    }

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

3490
fn trans_if(@block_ctxt cx, @ast.expr cond,
3491
            &ast.block thn, &Option.t[@ast.expr] els) -> result {
3492 3493 3494

    auto cond_res = trans_expr(cx, cond);

3495
    auto then_cx = new_scope_block_ctxt(cx, "then");
3496 3497
    auto then_res = trans_block(then_cx, thn);

3498
    auto else_cx = new_scope_block_ctxt(cx, "else");
3499

3500 3501
    auto else_res;
    auto expr_llty;
3502
    alt (els) {
3503
        case (some[@ast.expr](?elexpr)) {
3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515
            alt (elexpr.node) {
                case (ast.expr_if(_, _, _, _)) {
                    else_res = trans_expr(else_cx, elexpr);
                }
                case (ast.expr_block(?blk, _)) {
                    // Calling trans_block directly instead of trans_expr
                    // because trans_expr will create another scope block
                    // context for the block, but we've already got the
                    // 'else' context
                    else_res = trans_block(else_cx, blk);
                }
            }
3516 3517 3518

            // If we have an else expression, then the entire
            // if expression can have a non-nil type.
3519
            // FIXME: This isn't quite right, particularly re: dynamic types
3520 3521
            auto expr_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, elexpr);
            if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, expr_ty)) {
3522
                expr_llty = T_typaram_ptr(cx.fcx.lcx.ccx.tn);
3523
            } else {
3524
                expr_llty = type_of(else_res.bcx.fcx.lcx.ccx, expr_ty);
3525
                if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, expr_ty)) {
3526 3527
                    expr_llty = T_ptr(expr_llty);
                }
3528
            }
3529 3530 3531 3532
        }
        case (_) {
            else_res = res(else_cx, C_nil());
            expr_llty = T_nil();
3533 3534 3535
        }
    }

3536
    cond_res.bcx.build.CondBr(cond_res.val,
3537 3538
                              then_cx.llbb,
                              else_cx.llbb);
3539

3540
    ret join_results(cx, expr_llty,
3541
                     vec(then_res, else_res));
3542 3543
}

G
Graydon Hoare 已提交
3544 3545 3546 3547 3548 3549
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,
3550
             ty.t t, ast.block body,
3551
             @block_ctxt outer_next_cx) -> result {
G
Graydon Hoare 已提交
3552 3553

        auto next_cx = new_sub_block_ctxt(cx, "next");
3554
        auto scope_cx =
3555
            new_loop_scope_block_ctxt(cx, Option.some[@block_ctxt](next_cx),
3556
                                      outer_next_cx, "for loop scope");
G
Graydon Hoare 已提交
3557 3558 3559

        cx.build.Br(scope_cx.llbb);
        auto local_res = alloc_local(scope_cx, local);
3560
        auto bcx = copy_ty(local_res.bcx, INIT, local_res.val, curr, t).bcx;
3561 3562
        scope_cx.cleanups +=
            vec(clean(bind drop_slot(_, local_res.val, t)));
3563
        bcx = trans_block(bcx, body).bcx;
G
Graydon Hoare 已提交
3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575
        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;
        }
    }

3576
    auto next_cx = new_sub_block_ctxt(cx, "next");
3577
    auto seq_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, seq);
G
Graydon Hoare 已提交
3578
    auto seq_res = trans_expr(cx, seq);
3579 3580 3581 3582
    auto it = iter_sequence(seq_res.bcx, seq_res.val, seq_ty,
                            bind inner(_, local, _, _, body, next_cx));
    it.bcx.build.Br(next_cx.llbb);
    ret res(next_cx, it.val);
G
Graydon Hoare 已提交
3583 3584
}

3585 3586 3587 3588 3589 3590

// 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)
3591
        -> vec[ast.def_id] {
3592
    type env = @rec(
3593 3594 3595
        mutable vec[ast.def_id] refs,
        hashmap[ast.def_id,()] decls
    );
3596

3597
    fn walk_expr(env e, &@ast.expr expr) {
M
Marijn Haverbeke 已提交
3598 3599
        alt (expr.node) {
            case (ast.expr_path(?path, ?d, _)) {
3600
                alt (Option.get[ast.def](d)) {
M
Marijn Haverbeke 已提交
3601
                    case (ast.def_arg(?did)) {
3602
                        Vec.push[ast.def_id](e.refs, did);
M
Marijn Haverbeke 已提交
3603 3604
                    }
                    case (ast.def_local(?did)) {
3605
                        Vec.push[ast.def_id](e.refs, did);
M
Marijn Haverbeke 已提交
3606 3607
                    }
                    case (ast.def_upvar(?did)) {
3608
                        Vec.push[ast.def_id](e.refs, did);
M
Marijn Haverbeke 已提交
3609 3610 3611 3612 3613
                    }
                    case (_) {}
                }
            }
            case (_) {}
3614 3615 3616
        }
    }

3617
    fn walk_decl(env e, &@ast.decl decl) {
M
Marijn Haverbeke 已提交
3618 3619 3620 3621 3622 3623
        alt (decl.node) {
            case (ast.decl_local(?local)) {
                e.decls.insert(local.id, ());
            }
            case (_) {}
        }
3624 3625 3626 3627 3628 3629 3630
    }

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

M
Marijn Haverbeke 已提交
3631 3632 3633 3634
    auto visitor = @rec(visit_decl_pre = bind walk_decl(e, _),
                        visit_expr_pre = bind walk_expr(e, _)
                        with walk.default_visitor());
    walk.walk_block(*visitor, bloc);
3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646

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

3647 3648 3649 3650
fn trans_for_each(@block_ctxt cx,
                  @ast.decl decl,
                  @ast.expr seq,
                  &ast.block body) -> result {
3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676
    /*
     * 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.

3677
    auto lcx = cx.fcx.lcx;
3678
    // FIXME: possibly support alias-mode here?
3679
    auto decl_ty = ty.mk_nil(lcx.ccx.tcx);
3680
    auto decl_id;
3681 3682
    alt (decl.node) {
        case (ast.decl_local(?local)) {
3683
            decl_ty = node_ann_type(lcx.ccx, local.ann);
3684
            decl_id = local.id;
3685 3686 3687
        }
    }

3688
    auto upvars = collect_upvars(cx, body, decl_id);
3689
    auto upvar_count = Vec.len[ast.def_id](upvars);
3690 3691 3692 3693 3694 3695 3696 3697 3698 3699

    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]) {
3700 3701 3702 3703 3704 3705
                    alt (cx.fcx.llupvars.find(did)) {
                        case (none[ValueRef]) {
                            llbinding = cx.fcx.llargs.get(did);
                        }
                        case (some[ValueRef](?llval)) { llbinding = llval; }
                    }
3706 3707 3708 3709 3710 3711 3712 3713
                }
                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.
3714
        llbindingsptr = alloca(cx, T_struct(llbindingtys));
3715 3716 3717 3718 3719 3720 3721 3722 3723 3724
        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()));
3725 3726
    }

3727
    // Create an environment and populate it with the bindings.
3728
    auto tydesc_count = Vec.len[ValueRef](cx.fcx.lltydescs);
3729
    auto llenvptrty = T_closure_ptr(lcx.ccx.tn, T_ptr(T_nil()),
3730
                                    val_ty(llbindingsptr), tydesc_count);
3731
    auto llenvptr = alloca(cx, llvm.LLVMGetElementType(llenvptrty));
3732 3733 3734 3735 3736 3737

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

3739 3740 3741 3742 3743
    // Copy in our type descriptors, in case the iterator body needs to refer
    // to them.
    auto lltydescsptr = cx.build.GEP(llenvptr,
                                     vec(C_int(0),
                                         C_int(abi.box_rc_field_body),
3744
                                         C_int(abi.closure_elt_ty_params)));
3745 3746 3747 3748 3749 3750 3751 3752
    auto i = 0u;
    while (i < tydesc_count) {
        auto lltydescptr = cx.build.GEP(lltydescsptr,
                                        vec(C_int(0), C_int(i as int)));
        cx.build.Store(cx.fcx.lltydescs.(i), lltydescptr);
        i += 1u;
    }

3753 3754
    // Step 2: Declare foreach body function.

3755
    let str s = mangle_name_by_seq(lcx.ccx, lcx.path, "foreach");
3756 3757 3758 3759 3760 3761 3762

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

3763 3764 3765
    auto iter_body_llty =
        type_of_fn_full(lcx.ccx, ast.proto_fn,
                        none[TypeRef],
3766
                        vec(rec(mode=ty.mo_alias, ty=decl_ty)),
3767
                        ty.mk_nil(lcx.ccx.tcx), 0u);
3768

3769
    let ValueRef lliterbody = decl_internal_fastcall_fn(lcx.ccx.llmod,
3770
                                                       s, iter_body_llty);
3771

3772
    auto fcx = new_fn_ctxt(lcx, lliterbody);
3773
    auto bcx = new_top_block_ctxt(fcx);
3774
    auto lltop = bcx.llbb;
3775

3776 3777
    // Populate the upvars from the environment.
    auto llremoteenvptr = bcx.build.PointerCast(fcx.llenv, llenvptrty);
3778 3779 3780 3781
    auto llremotebindingsptrptr =
        bcx.build.GEP(llremoteenvptr, vec(C_int(0),
                                          C_int(abi.box_rc_field_body),
                                          C_int(abi.closure_elt_bindings)));
3782 3783
    auto llremotebindingsptr = bcx.build.Load(llremotebindingsptrptr);

3784
    i = 0u;
3785 3786 3787 3788 3789 3790 3791 3792 3793 3794
    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;
    }

3795
    // Populate the type parameters from the environment.
3796 3797 3798 3799 3800
    auto llremotetydescsptr =
        bcx.build.GEP(llremoteenvptr,
                      vec(C_int(0),
                          C_int(abi.box_rc_field_body),
                          C_int(abi.closure_elt_ty_params)));
3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811

    i = 0u;
    while (i < tydesc_count) {
        auto llremotetydescptr = bcx.build.GEP(llremotetydescsptr,
                                               vec(C_int(0),
                                                   C_int(i as int)));
        auto llremotetydesc = bcx.build.Load(llremotetydescptr);
        fcx.lltydescs += vec(llremotetydesc);
        i += 1u;
    }

3812 3813
    // Add an upvar for the loop variable alias.
    fcx.llupvars.insert(decl_id, llvm.LLVMGetParam(fcx.llfn, 3u));
3814

3815
    auto r = trans_block(bcx, body);
3816 3817 3818 3819

    // Tie up the llallocas -> lltop edge.
    new_builder(fcx.llallocas).Br(lltop);

3820
    r.bcx.build.RetVoid();
3821 3822


3823
    // Step 3: Call iter passing [lliterbody, llenv], plus other args.
3824 3825

    alt (seq.node) {
3826

3827
        case (ast.expr_call(?f, ?args, ?ann)) {
3828

3829
            auto pair = alloca(cx, T_fn_pair(lcx.ccx.tn,
3830
                                             iter_body_llty));
3831 3832 3833 3834 3835
            auto code_cell = cx.build.GEP(pair,
                                          vec(C_int(0),
                                              C_int(abi.fn_field_code)));
            cx.build.Store(lliterbody, code_cell);

3836 3837 3838
            auto env_cell = cx.build.GEP(pair, vec(C_int(0),
                                                   C_int(abi.fn_field_box)));
            auto llenvblobptr = cx.build.PointerCast(llenvptr,
3839
                T_opaque_closure_ptr(lcx.ccx.tn));
3840 3841
            cx.build.Store(llenvblobptr, env_cell);

3842
            // log "lliterbody: " + val_str(lcx.ccx.tn, lliterbody);
3843
            r = trans_call(cx, f,
3844
                           some[ValueRef](cx.build.Load(pair)),
3845 3846
                           args,
                           ann);
3847
            ret res(r.bcx, C_nil());
3848 3849
        }
    }
3850 3851 3852 3853
    fail;
}


3854 3855
fn trans_while(@block_ctxt cx, @ast.expr cond,
               &ast.block body) -> result {
3856

3857
    auto cond_cx = new_scope_block_ctxt(cx, "while cond");
3858
    auto next_cx = new_sub_block_ctxt(cx, "next");
3859
    auto body_cx = new_loop_scope_block_ctxt(cx, Option.none[@block_ctxt],
3860
                                             next_cx, "while loop body");
3861 3862

    auto body_res = trans_block(body_cx, body);
3863 3864 3865
    auto cond_res = trans_expr(cond_cx, cond);

    body_res.bcx.build.Br(cond_cx.llbb);
3866 3867 3868

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

    cx.build.Br(cond_cx.llbb);
3871 3872 3873
    ret res(next_cx, C_nil());
}

3874 3875
fn trans_do_while(@block_ctxt cx, &ast.block body,
                  @ast.expr cond) -> result {
3876

3877
    auto next_cx = new_sub_block_ctxt(cx, "next");
3878
    auto body_cx = new_loop_scope_block_ctxt(cx, Option.none[@block_ctxt],
3879
                                             next_cx, "do-while loop body");
3880 3881

    auto body_res = trans_block(body_cx, body);
3882 3883 3884 3885 3886 3887
    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);
3888 3889 3890
    ret res(next_cx, body_res.val);
}

P
Patrick Walton 已提交
3891 3892
// Pattern matching translation

3893 3894
fn trans_pat_match(@block_ctxt cx, @ast.pat pat, ValueRef llval,
                   @block_ctxt next_cx) -> result {
P
Patrick Walton 已提交
3895 3896 3897
    alt (pat.node) {
        case (ast.pat_wild(_)) { ret res(cx, llval); }
        case (ast.pat_bind(_, _, _)) { ret res(cx, llval); }
3898 3899

        case (ast.pat_lit(?lt, ?ann)) {
3900
            auto lllit = trans_lit(cx.fcx.lcx.ccx, *lt, ann);
3901 3902
            auto lltype = ty.ann_to_type(ann);
            auto lleq = trans_compare(cx, ast.eq, lltype, llval, lllit);
3903

3904 3905
            auto matched_cx = new_sub_block_ctxt(lleq.bcx, "matched_cx");
            lleq.bcx.build.CondBr(lleq.val, matched_cx.llbb, next_cx.llbb);
3906 3907 3908
            ret res(matched_cx, llval);
        }

P
Patrick Walton 已提交
3909
        case (ast.pat_tag(?id, ?subpats, ?vdef_opt, ?ann)) {
3910
            auto lltagptr = cx.build.PointerCast(llval,
3911
                T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn));
3912 3913 3914

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

3917
            auto vdef = Option.get[ast.variant_def](vdef_opt);
P
Patrick Walton 已提交
3918 3919
            auto variant_id = vdef._1;
            auto variant_tag = 0;
3920

3921
            auto variants = tag_variants(cx.fcx.lcx.ccx, vdef._0);
P
Patrick Walton 已提交
3922
            auto i = 0;
3923 3924
            for (variant_info v in variants) {
                auto this_variant_id = v.id;
P
Patrick Walton 已提交
3925
                if (variant_id._0 == this_variant_id._0 &&
G
Graydon Hoare 已提交
3926
                    variant_id._1 == this_variant_id._1) {
P
Patrick Walton 已提交
3927 3928 3929 3930 3931 3932 3933
                    variant_tag = i;
                }
                i += 1;
            }

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

3934
            auto lleq = cx.build.ICmp(lib.llvm.LLVMIntEQ, lldiscrim,
P
Patrick Walton 已提交
3935 3936 3937
                                      C_int(variant_tag));
            cx.build.CondBr(lleq, matched_cx.llbb, next_cx.llbb);

3938 3939
            auto ty_params = node_ann_ty_params(ann);

3940
            if (Vec.len[@ast.pat](subpats) > 0u) {
3941
                auto llblobptr = matched_cx.build.GEP(lltagptr,
3942
                    vec(C_int(0), C_int(1)));
P
Patrick Walton 已提交
3943 3944
                auto i = 0;
                for (@ast.pat subpat in subpats) {
3945 3946
                    auto rslt = GEP_tag(matched_cx, llblobptr, vdef._0,
                                        vdef._1, ty_params, i);
3947 3948 3949
                    auto llsubvalptr = rslt.val;
                    matched_cx = rslt.bcx;

3950
                    auto llsubval = load_if_immediate(matched_cx,
3951
                        llsubvalptr, pat_ty(cx.fcx.lcx.ccx.tcx, subpat));
P
Patrick Walton 已提交
3952 3953 3954
                    auto subpat_res = trans_pat_match(matched_cx, subpat,
                                                      llsubval, next_cx);
                    matched_cx = subpat_res.bcx;
3955 3956

                    i += 1;
P
Patrick Walton 已提交
3957 3958 3959 3960 3961 3962 3963 3964 3965 3966
                }
            }

            ret res(matched_cx, llval);
        }
    }

    fail;
}

3967 3968
fn trans_pat_binding(@block_ctxt cx, @ast.pat pat,
                     ValueRef llval, bool bind_alias)
3969
    -> result {
P
Patrick Walton 已提交
3970 3971
    alt (pat.node) {
        case (ast.pat_wild(_)) { ret res(cx, llval); }
3972
        case (ast.pat_lit(_, _)) { ret res(cx, llval); }
P
Patrick Walton 已提交
3973
        case (ast.pat_bind(?id, ?def_id, ?ann)) {
3974 3975 3976 3977 3978 3979 3980 3981
            if (bind_alias) {
                cx.fcx.lllocals.insert(def_id, llval);
                ret res(cx, llval);
            } else {
                auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
                auto rslt = alloc_ty(cx, t);
                auto dst = rslt.val;
                auto bcx = rslt.bcx;
3982
                llvm.LLVMSetValueName(dst, Str.buf(id));
3983 3984 3985 3986 3987
                bcx.fcx.lllocals.insert(def_id, dst);
                bcx.cleanups +=
                    vec(clean(bind drop_slot(_, dst, t)));
                ret copy_ty(bcx, INIT, dst, llval, t);
            }
P
Patrick Walton 已提交
3988
        }
3989
        case (ast.pat_tag(_, ?subpats, ?vdef_opt, ?ann)) {
3990
            if (Vec.len[@ast.pat](subpats) == 0u) { ret res(cx, llval); }
P
Patrick Walton 已提交
3991

3992
            // Get the appropriate variant for this tag.
3993
            auto vdef = Option.get[ast.variant_def](vdef_opt);
3994 3995

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

3999 4000
            auto ty_param_substs = node_ann_ty_params(ann);

P
Patrick Walton 已提交
4001 4002 4003
            auto this_cx = cx;
            auto i = 0;
            for (@ast.pat subpat in subpats) {
4004 4005
                auto rslt = GEP_tag(this_cx, llblobptr, vdef._0, vdef._1,
                                    ty_param_substs, i);
4006
                this_cx = rslt.bcx;
P
Patrick Walton 已提交
4007
                auto subpat_res = trans_pat_binding(this_cx, subpat,
4008
                                                    rslt.val, true);
P
Patrick Walton 已提交
4009
                this_cx = subpat_res.bcx;
4010
                i += 1;
P
Patrick Walton 已提交
4011 4012 4013 4014 4015 4016 4017
            }

            ret res(this_cx, llval);
        }
    }
}

4018 4019
fn trans_alt(@block_ctxt cx, @ast.expr expr,
             vec[ast.arm] arms, ast.ann ann) -> result {
P
Patrick Walton 已提交
4020 4021 4022
    auto expr_res = trans_expr(cx, expr);

    auto this_cx = expr_res.bcx;
4023
    let vec[result] arm_results = vec();
P
Patrick Walton 已提交
4024 4025 4026 4027 4028 4029 4030 4031 4032
    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,
4033
                                             expr_res.val, false);
P
Patrick Walton 已提交
4034 4035

        auto block_res = trans_block(binding_res.bcx, arm.block);
4036
        arm_results += vec(block_res);
P
Patrick Walton 已提交
4037 4038 4039 4040

        this_cx = next_cx;
    }

4041
    auto default_cx = this_cx;
4042
    auto default_res = trans_fail(default_cx, some[common.span](expr.span),
4043
                                  "non-exhaustive match failure");
P
Patrick Walton 已提交
4044

4045
    // FIXME: This isn't quite right, particularly re: dynamic types
4046 4047
    auto expr_ty = ty.ann_to_type(ann);
    auto expr_llty;
4048
    if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, expr_ty)) {
4049
        expr_llty = T_typaram_ptr(cx.fcx.lcx.ccx.tn);
4050
    } else {
4051
        expr_llty = type_of(cx.fcx.lcx.ccx, expr_ty);
4052
        if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, expr_ty)) {
4053 4054 4055 4056 4057
            expr_llty = T_ptr(expr_llty);
        }
    }

    ret join_results(cx, expr_llty, arm_results);
P
Patrick Walton 已提交
4058 4059
}

4060
type generic_info = rec(ty.t item_type,
4061 4062
                        vec[ValueRef] tydescs);

4063 4064
type lval_result = rec(result res,
                       bool is_mem,
4065 4066 4067
                       Option.t[generic_info] generic,
                       Option.t[ValueRef] llobj,
                       Option.t[ty.t] method_ty);
4068 4069 4070 4071

fn lval_mem(@block_ctxt cx, ValueRef val) -> lval_result {
    ret rec(res=res(cx, val),
            is_mem=true,
4072
            generic=none[generic_info],
4073
            llobj=none[ValueRef],
4074
            method_ty=none[ty.t]);
4075 4076 4077 4078 4079
}

fn lval_val(@block_ctxt cx, ValueRef val) -> lval_result {
    ret rec(res=res(cx, val),
            is_mem=false,
4080
            generic=none[generic_info],
4081
            llobj=none[ValueRef],
4082
            method_ty=none[ty.t]);
4083
}
4084

4085
fn trans_external_path(@block_ctxt cx, ast.def_id did,
4086
                       ty.ty_param_count_and_ty tpt) -> lval_result {
4087 4088 4089 4090
    auto lcx = cx.fcx.lcx;
    auto name = creader.get_symbol(lcx.ccx.sess, did);
    auto v = get_extern_const(lcx.ccx.externs, lcx.ccx.llmod,
                              name, type_of_ty_param_count_and_ty(lcx, tpt));
4091 4092 4093
    ret lval_val(cx, v);
}

4094
fn lval_generic_fn(@block_ctxt cx,
4095
                   ty.ty_param_count_and_ty tpt,
4096 4097
                   ast.def_id fn_id,
                   &ast.ann ann)
4098
        -> lval_result {
4099
    auto lv;
4100
    if (cx.fcx.lcx.ccx.sess.get_targ_crate_num() == fn_id._0) {
4101
        // Internal reference.
4102
        assert (cx.fcx.lcx.ccx.fn_pairs.contains_key(fn_id));
4103
        lv = lval_val(cx, cx.fcx.lcx.ccx.fn_pairs.get(fn_id));
4104 4105
    } else {
        // External reference.
4106
        lv = trans_external_path(cx, fn_id, tpt);
4107
    }
4108 4109

    auto monoty;
4110
    let vec[ty.t] tys;
4111 4112
    alt (ann) {
        case (ast.ann_none) {
4113
            cx.fcx.lcx.ccx.sess.bug("no type annotation for path!");
4114 4115
            fail;
        }
4116
        case (ast.ann_type(?monoty_, ?tps, _)) {
4117
            monoty = monoty_;
4118
            tys = Option.get[vec[ty.t]](tps);
4119 4120
        }
    }
4121

4122
    if (Vec.len[ty.t](tys) != 0u) {
4123
        auto bcx = lv.res.bcx;
4124
        let vec[ValueRef] tydescs = vec();
4125
        for (ty.t t in tys) {
4126 4127
            // TODO: Doesn't always escape.
            auto td = get_tydesc(bcx, t, true);
4128
            bcx = td.bcx;
4129
            Vec.push[ValueRef](tydescs, td.val);
4130 4131 4132 4133 4134 4135 4136 4137 4138 4139
        }
        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;
}

4140
fn lookup_discriminant(@local_ctxt lcx, ast.def_id tid, ast.def_id vid)
4141
        -> ValueRef {
4142
    alt (lcx.ccx.discrims.find(vid)) {
4143 4144
        case (none[ValueRef]) {
            // It's an external discriminant that we haven't seen yet.
4145
            assert (lcx.ccx.sess.get_targ_crate_num() != vid._0);
4146 4147
            auto sym = creader.get_symbol(lcx.ccx.sess, vid);
            auto gvar = llvm.LLVMAddGlobal(lcx.ccx.llmod, T_int(),
4148
                                           Str.buf(sym));
4149 4150 4151
            llvm.LLVMSetLinkage(gvar,
                                lib.llvm.LLVMExternalLinkage as llvm.Linkage);
            llvm.LLVMSetGlobalConstant(gvar, True);
4152
            lcx.ccx.discrims.insert(vid, gvar);
4153 4154 4155 4156 4157 4158
            ret gvar;
        }
        case (some[ValueRef](?llval)) { ret llval; }
    }
}

4159
fn trans_path(@block_ctxt cx, &ast.path p, &Option.t[ast.def] dopt,
G
Graydon Hoare 已提交
4160
              &ast.ann ann) -> lval_result {
4161 4162 4163 4164
    alt (dopt) {
        case (some[ast.def](?def)) {
            alt (def) {
                case (ast.def_arg(?did)) {
4165 4166
                    alt (cx.fcx.llargs.find(did)) {
                        case (none[ValueRef]) {
4167
                            assert (cx.fcx.llupvars.contains_key(did));
4168 4169 4170 4171 4172 4173
                            ret lval_mem(cx, cx.fcx.llupvars.get(did));
                        }
                        case (some[ValueRef](?llval)) {
                            ret lval_mem(cx, llval);
                        }
                    }
4174 4175
                }
                case (ast.def_local(?did)) {
4176 4177
                    alt (cx.fcx.lllocals.find(did)) {
                        case (none[ValueRef]) {
4178
                            assert (cx.fcx.llupvars.contains_key(did));
4179 4180 4181 4182 4183 4184
                            ret lval_mem(cx, cx.fcx.llupvars.get(did));
                        }
                        case (some[ValueRef](?llval)) {
                            ret lval_mem(cx, llval);
                        }
                    }
G
Graydon Hoare 已提交
4185
                }
P
Patrick Walton 已提交
4186
                case (ast.def_binding(?did)) {
4187
                    assert (cx.fcx.lllocals.contains_key(did));
4188
                    ret lval_mem(cx, cx.fcx.lllocals.get(did));
P
Patrick Walton 已提交
4189
                }
4190
                case (ast.def_obj_field(?did)) {
4191
                    assert (cx.fcx.llobjfields.contains_key(did));
4192 4193
                    ret lval_mem(cx, cx.fcx.llobjfields.get(did));
                }
4194
                case (ast.def_fn(?did)) {
4195
                    auto tyt = ty.lookup_item_type(cx.fcx.lcx.ccx.sess,
4196
                        cx.fcx.lcx.ccx.tcx, cx.fcx.lcx.ccx.type_cache, did);
4197
                    ret lval_generic_fn(cx, tyt, did, ann);
4198
                }
4199
                case (ast.def_obj(?did)) {
4200
                    auto tyt = ty.lookup_item_type(cx.fcx.lcx.ccx.sess,
4201
                        cx.fcx.lcx.ccx.tcx, cx.fcx.lcx.ccx.type_cache, did);
4202
                    ret lval_generic_fn(cx, tyt, did, ann);
4203
                }
4204
                case (ast.def_variant(?tid, ?vid)) {
4205
                    auto v_tyt = ty.lookup_item_type(cx.fcx.lcx.ccx.sess,
4206 4207
                        cx.fcx.lcx.ccx.tcx, cx.fcx.lcx.ccx.type_cache, vid);
                    alt (ty.struct(cx.fcx.lcx.ccx.tcx, v_tyt._1)) {
4208 4209 4210
                        case (ty.ty_fn(_, _, _)) {
                            // N-ary variant.
                            ret lval_generic_fn(cx, v_tyt, vid, ann);
4211
                        }
4212 4213
                        case (_) {
                            // Nullary variant.
4214
                            auto tag_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
4215
                            auto lldiscrim_gv =
4216
                                lookup_discriminant(cx.fcx.lcx, tid, vid);
4217 4218 4219 4220 4221 4222
                            auto lldiscrim = cx.build.Load(lldiscrim_gv);

                            auto alloc_result = alloc_ty(cx, tag_ty);
                            auto lltagblob = alloc_result.val;

                            auto lltagty;
4223 4224
                            if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx,
                                                         tag_ty)) {
4225
                                lltagty = T_opaque_tag(cx.fcx.lcx.ccx.tn);
4226
                            } else {
4227
                                lltagty = type_of(cx.fcx.lcx.ccx, tag_ty);
4228
                            }
4229 4230
                            auto lltagptr = alloc_result.bcx.build.
                                PointerCast(lltagblob, T_ptr(lltagty));
4231

4232 4233 4234 4235
                            auto lldiscrimptr = alloc_result.bcx.build.GEP(
                                lltagptr, vec(C_int(0), C_int(0)));
                            alloc_result.bcx.build.Store(lldiscrim,
                                                         lldiscrimptr);
4236

4237 4238
                            ret lval_val(alloc_result.bcx, lltagptr);
                        }
4239
                    }
4240
                }
4241
                case (ast.def_const(?did)) {
4242
                    // TODO: externals
4243
                    assert (cx.fcx.lcx.ccx.consts.contains_key(did));
4244
                    ret lval_mem(cx, cx.fcx.lcx.ccx.consts.get(did));
4245
                }
4246
                case (ast.def_native_fn(?did)) {
4247
                    auto tyt = ty.lookup_item_type(cx.fcx.lcx.ccx.sess,
4248
                        cx.fcx.lcx.ccx.tcx,
4249
                        cx.fcx.lcx.ccx.type_cache, did);
4250
                    ret lval_generic_fn(cx, tyt, did, ann);
4251
                }
4252
                case (_) {
4253
                    cx.fcx.lcx.ccx.sess.unimpl("def variant in trans");
G
Graydon Hoare 已提交
4254 4255 4256
                }
            }
        }
4257
        case (none[ast.def]) {
4258
            cx.fcx.lcx.ccx.sess.err("unresolved expr_path in trans");
4259 4260 4261 4262 4263
        }
    }
    fail;
}

4264
fn trans_field(@block_ctxt cx, &ast.span sp, ValueRef v, ty.t t0,
4265
               &ast.ident field, &ast.ann ann) -> lval_result {
4266 4267

    auto r = autoderef(cx, v, t0);
4268
    auto t = autoderefed_ty(cx.fcx.lcx.ccx, t0);
4269

4270
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
4271
        case (ty.ty_tup(_)) {
4272
            let uint ix = ty.field_num(cx.fcx.lcx.ccx.sess, sp, field);
4273
            auto v = GEP_tup_like(r.bcx, t, r.val, vec(0, ix as int));
4274
            ret lval_mem(v.bcx, v.val);
4275
        }
4276
        case (ty.ty_rec(?fields)) {
4277 4278
            let uint ix = ty.field_idx(cx.fcx.lcx.ccx.sess, sp, field,
                                       fields);
4279
            auto v = GEP_tup_like(r.bcx, t, r.val, vec(0, ix as int));
4280
            ret lval_mem(v.bcx, v.val);
4281
        }
4282
        case (ty.ty_obj(?methods)) {
4283 4284
            let uint ix = ty.method_idx(cx.fcx.lcx.ccx.sess, sp, field,
                                        methods);
4285 4286 4287 4288
            auto vtbl = r.bcx.build.GEP(r.val,
                                        vec(C_int(0),
                                            C_int(abi.obj_field_vtbl)));
            vtbl = r.bcx.build.Load(vtbl);
4289
            // +1 because slot #0 contains the destructor
4290
            auto v =  r.bcx.build.GEP(vtbl, vec(C_int(0),
4291
                                                C_int((ix + 1u) as int)));
4292 4293

            auto lvo = lval_mem(r.bcx, v);
4294
            let ty.t fn_ty = ty.method_ty_to_fn_ty(cx.fcx.lcx.ccx.tcx,
4295
                                                   methods.(ix));
4296
            ret rec(llobj = some[ValueRef](r.val),
4297
                    method_ty = some[ty.t](fn_ty)
4298
                    with lvo);
4299
        }
4300
        case (_) {cx.fcx.lcx.ccx.sess.unimpl("field variant in trans_field");}
4301 4302 4303 4304
    }
    fail;
}

4305 4306
fn trans_index(@block_ctxt cx, &ast.span sp, @ast.expr base,
               @ast.expr idx, &ast.ann ann) -> lval_result {
4307

G
Graydon Hoare 已提交
4308
    auto lv = trans_expr(cx, base);
4309
    lv = autoderef(lv.bcx, lv.val, ty.expr_ty(cx.fcx.lcx.ccx.tcx, base));
G
Graydon Hoare 已提交
4310 4311
    auto ix = trans_expr(lv.bcx, idx);
    auto v = lv.val;
4312
    auto bcx = ix.bcx;
4313

4314 4315
    // Cast to an LLVM integer. Rust is less strict than LLVM in this regard.
    auto ix_val;
4316 4317
    auto ix_size = llsize_of_real(cx.fcx.lcx.ccx, val_ty(ix.val));
    auto int_size = llsize_of_real(cx.fcx.lcx.ccx, T_int());
4318 4319 4320 4321 4322 4323 4324 4325
    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;
    }

4326
    auto unit_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
4327
    auto unit_sz = size_of(bcx, unit_ty);
4328
    bcx = unit_sz.bcx;
4329
    llvm.LLVMSetValueName(unit_sz.val, Str.buf("unit_sz"));
4330 4331

    auto scaled_ix = bcx.build.Mul(ix_val, unit_sz.val);
4332
    llvm.LLVMSetValueName(scaled_ix, Str.buf("scaled_ix"));
4333

4334 4335
    auto lim = bcx.build.GEP(v, vec(C_int(0), C_int(abi.vec_elt_fill)));
    lim = bcx.build.Load(lim);
4336

4337 4338
    auto bounds_check = bcx.build.ICmp(lib.llvm.LLVMIntULT,
                                       scaled_ix, lim);
4339

4340 4341 4342
    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);
4343 4344

    // fail: bad bounds check.
4345 4346
    auto fail_res = trans_fail(fail_cx, some[common.span](sp),
                               "bounds check");
4347 4348

    auto body = next_cx.build.GEP(v, vec(C_int(0), C_int(abi.vec_elt_data)));
4349
    auto elt;
4350
    if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, unit_ty)) {
4351
        body = next_cx.build.PointerCast(body, T_ptr(T_array(T_i8(), 1u)));
4352 4353 4354
        elt = next_cx.build.GEP(body, vec(C_int(0), scaled_ix));
    } else {
        elt = next_cx.build.GEP(body, vec(C_int(0), ix_val));
4355 4356

        // We're crossing a box boundary here, so we may need to pointer cast.
4357
        auto llunitty = type_of(next_cx.fcx.lcx.ccx, unit_ty);
4358
        elt = next_cx.build.PointerCast(elt, T_ptr(llunitty));
4359 4360
    }

4361
    ret lval_mem(next_cx, elt);
4362 4363
}

4364 4365 4366 4367
// 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).

4368
fn trans_lval(@block_ctxt cx, @ast.expr e) -> lval_result {
4369
    alt (e.node) {
4370 4371
        case (ast.expr_path(?p, ?dopt, ?ann)) {
            ret trans_path(cx, p, dopt, ann);
4372 4373
        }
        case (ast.expr_field(?base, ?ident, ?ann)) {
4374
            auto r = trans_expr(cx, base);
4375
            auto t = ty.expr_ty(cx.fcx.lcx.ccx.tcx, base);
4376
            ret trans_field(r.bcx, e.span, r.val, t, ident, ann);
4377
        }
4378 4379 4380
        case (ast.expr_index(?base, ?idx, ?ann)) {
            ret trans_index(cx, e.span, base, idx, ann);
        }
4381
        case (ast.expr_unary(?unop, ?base, ?ann)) {
4382
            assert (unop == ast.deref);
4383 4384 4385 4386 4387 4388 4389

            auto sub = trans_expr(cx, base);
            auto val = sub.bcx.build.GEP(sub.val,
                                         vec(C_int(0),
                                             C_int(abi.box_rc_field_body)));
            ret lval_mem(sub.bcx, val);
        }
4390
        case (ast.expr_self_method(?ident, ?ann)) {
4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403
            alt (cx.fcx.llself) {
                case (some[self_vt](?s_vt)) {
                    auto r =  s_vt.v;
                    auto t =  s_vt.t;
                    ret trans_field(cx, e.span, r, t, ident, ann);
                }
                case (_) {
                    // Shouldn't happen.
                    fail;
                }

            }
        }
4404
        case (_) {
4405 4406
            cx.fcx.lcx.ccx.sess.span_unimpl(e.span,
                                            "expr variant in trans_lval");
4407
        }
G
Graydon Hoare 已提交
4408 4409 4410 4411
    }
    fail;
}

4412
fn trans_cast(@block_ctxt cx, @ast.expr e, &ast.ann ann) -> result {
4413 4414
    auto e_res = trans_expr(cx, e);
    auto llsrctype = val_ty(e_res.val);
4415 4416
    auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
    auto lldsttype = type_of(cx.fcx.lcx.ccx, t);
4417
    if (!ty.type_is_fp(cx.fcx.lcx.ccx.tcx, t)) {
4418
        // TODO: native-to-native casts
4419 4420
        if (ty.type_is_native(cx.fcx.lcx.ccx.tcx,
                              ty.expr_ty(cx.fcx.lcx.ccx.tcx, e))) {
4421
            e_res.val = e_res.bcx.build.PtrToInt(e_res.val, lldsttype);
4422
        } else if (ty.type_is_native(cx.fcx.lcx.ccx.tcx, t)) {
4423
            e_res.val = e_res.bcx.build.IntToPtr(e_res.val, lldsttype);
4424
        } else if (llvm.LLVMGetIntTypeWidth(lldsttype) >
4425
            llvm.LLVMGetIntTypeWidth(llsrctype)) {
4426
            if (ty.type_is_signed(cx.fcx.lcx.ccx.tcx, t)) {
4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443
                // 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 {
4444
        cx.fcx.lcx.ccx.sess.unimpl("fp cast");
4445 4446 4447 4448
    }
    ret e_res;
}

4449
fn trans_bind_thunk(@local_ctxt cx,
4450 4451
                    ty.t incoming_fty,
                    ty.t outgoing_fty,
4452
                    vec[Option.t[@ast.expr]] args,
4453 4454
                    ty.t closure_ty,
                    vec[ty.t] bound_tys,
4455
                    uint ty_param_count) -> ValueRef {
4456 4457 4458
    // Construct a thunk-call with signature incoming_fty, and that copies
    // args forward into a call to outgoing_fty.

4459
    let str s = mangle_name_by_seq(cx.ccx, cx.path, "thunk");
4460 4461 4462
    let TypeRef llthunk_ty = get_pair_fn_ty(type_of(cx.ccx, incoming_fty));
    let ValueRef llthunk = decl_internal_fastcall_fn(cx.ccx.llmod,
                                                     s, llthunk_ty);
4463

4464
    auto fcx = new_fn_ctxt(cx, llthunk);
4465
    auto bcx = new_top_block_ctxt(fcx);
4466
    auto lltop = bcx.llbb;
4467

4468
    auto llclosure_ptr_ty =
4469
        type_of(cx.ccx, ty.mk_imm_box(cx.ccx.tcx, closure_ty));
4470
    auto llclosure = bcx.build.PointerCast(fcx.llenv, llclosure_ptr_ty);
4471

4472 4473 4474 4475 4476 4477
    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,
4478 4479 4480
                                         vec(C_int(0),
                                             C_int(abi.fn_field_box)));
    lltargetclosure = bcx.build.Load(lltargetclosure);
4481

4482 4483
    auto outgoing_ret_ty = ty.ty_fn_ret(cx.ccx.tcx, outgoing_fty);
    auto outgoing_args = ty.ty_fn_args(cx.ccx.tcx, outgoing_fty);
4484 4485

    auto llretptr = fcx.llretptr;
4486
    if (ty.type_has_dynamic_size(cx.ccx.tcx, outgoing_ret_ty)) {
4487
        llretptr = bcx.build.PointerCast(llretptr, T_typaram_ptr(cx.ccx.tn));
4488 4489 4490
    }

    let vec[ValueRef] llargs = vec(llretptr,
4491
                                   fcx.lltaskptr,
4492
                                   lltargetclosure);
4493 4494 4495 4496 4497

    // Copy in the type parameters.
    let uint i = 0u;
    while (i < ty_param_count) {
        auto lltyparam_ptr =
4498 4499 4500 4501 4502 4503
            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;
4504 4505 4506
        auto td = bcx.build.Load(lltyparam_ptr.val);
        llargs += vec(td);
        fcx.lltydescs += vec(td);
4507 4508 4509
        i += 1u;
    }

4510
    let uint a = 3u;    // retptr, task ptr, env come first
4511
    let int b = 0;
4512
    let uint outgoing_arg_index = 0u;
4513
    let vec[TypeRef] llout_arg_tys =
4514
        type_of_explicit_args(cx.ccx, outgoing_args);
4515

4516
    for (Option.t[@ast.expr] arg in args) {
4517 4518 4519 4520

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

4521 4522 4523
        alt (arg) {

            // Arg provided at binding time; thunk copies it from closure.
4524 4525
            case (some[@ast.expr](?e)) {
                auto e_ty = ty.expr_ty(cx.ccx.tcx, e);
4526 4527 4528 4529 4530 4531
                auto bound_arg =
                    GEP_tup_like(bcx, closure_ty, llclosure,
                                 vec(0,
                                     abi.box_rc_field_body,
                                     abi.closure_elt_bindings,
                                     b));
4532

4533
                bcx = bound_arg.bcx;
4534 4535
                auto val = bound_arg.val;

4536
                if (out_arg.mode == ty.mo_val) {
4537 4538 4539 4540 4541 4542 4543
                    if (type_is_immediate(cx.ccx, e_ty)) {
                        val = bcx.build.Load(val);
                        bcx = take_ty(bcx, val, e_ty).bcx;
                    } else {
                        bcx = take_ty(bcx, val, e_ty).bcx;
                        val = bcx.build.Load(val);
                    }
4544 4545
                } else if (ty.type_contains_params(cx.ccx.tcx,
                                                   out_arg.ty)) {
4546
                    assert (out_arg.mode == ty.mo_alias);
4547 4548 4549
                    val = bcx.build.PointerCast(val, llout_arg_ty);
                }

4550
                llargs += vec(val);
4551 4552 4553 4554 4555 4556
                b += 1;
            }

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

4558
                if (ty.type_contains_params(cx.ccx.tcx, out_arg.ty)) {
4559
                    assert (out_arg.mode == ty.mo_alias);
4560
                    passed_arg = bcx.build.PointerCast(passed_arg,
4561
                                                       llout_arg_ty);
4562
                }
4563

4564
                llargs += vec(passed_arg);
4565 4566 4567
                a += 1u;
            }
        }
4568

4569
        outgoing_arg_index += 1u;
4570 4571 4572
    }

    // FIXME: turn this call + ret into a tail call.
4573
    auto lltargetfn = bcx.build.GEP(lltarget.val,
4574 4575
                                    vec(C_int(0),
                                        C_int(abi.fn_field_code)));
4576 4577 4578

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

4587
    lltargetfn = bcx.build.Load(lltargetfn);
4588

4589
    auto r = bcx.build.FastCall(lltargetfn, llargs);
4590
    bcx.build.RetVoid();
4591

4592 4593 4594
    // Tie up the llallocas -> lltop edge.
    new_builder(fcx.llallocas).Br(lltop);

4595 4596 4597
    ret llthunk;
}

4598
fn trans_bind(@block_ctxt cx, @ast.expr f,
4599
              vec[Option.t[@ast.expr]] args,
4600
              &ast.ann ann) -> result {
4601 4602
    auto f_res = trans_lval(cx, f);
    if (f_res.is_mem) {
4603
        cx.fcx.lcx.ccx.sess.unimpl("re-binding existing function");
4604
    } else {
4605 4606
        let vec[@ast.expr] bound = vec();

4607
        for (Option.t[@ast.expr] argopt in args) {
4608 4609 4610 4611
            alt (argopt) {
                case (none[@ast.expr]) {
                }
                case (some[@ast.expr](?e)) {
4612
                    Vec.push[@ast.expr](bound, e);
4613 4614 4615
                }
            }
        }
4616 4617

        // Figure out which tydescs we need to pass, if any.
4618
        let ty.t outgoing_fty;
B
Brian Anderson 已提交
4619
        let vec[ValueRef] lltydescs;
4620 4621
        alt (f_res.generic) {
            case (none[generic_info]) {
4622
                outgoing_fty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, f);
B
Brian Anderson 已提交
4623
                lltydescs = vec();
4624 4625 4626 4627 4628 4629
            }
            case (some[generic_info](?ginfo)) {
                outgoing_fty = ginfo.item_type;
                lltydescs = ginfo.tydescs;
            }
        }
4630
        auto ty_param_count = Vec.len[ValueRef](lltydescs);
4631

4632
        if (Vec.len[@ast.expr](bound) == 0u && ty_param_count == 0u) {
4633 4634 4635 4636
            // Trivial 'binding': just return the static pair-ptr.
            ret f_res.res;
        } else {
            auto bcx = f_res.res.bcx;
4637
            auto pair_t = node_type(cx.fcx.lcx.ccx, ann);
4638
            auto pair_v = alloca(bcx, pair_t);
4639 4640

            // Translate the bound expressions.
4641
            let vec[ty.t] bound_tys = vec();
4642
            let vec[ValueRef] bound_vals = vec();
4643
            auto i = 0u;
4644 4645 4646
            for (@ast.expr e in bound) {
                auto arg = trans_expr(bcx, e);
                bcx = arg.bcx;
4647

4648 4649
                Vec.push[ValueRef](bound_vals, arg.val);
                Vec.push[ty.t](bound_tys,
4650
                                 ty.expr_ty(cx.fcx.lcx.ccx.tcx, e));
4651 4652

                i += 1u;
4653 4654 4655
            }

            // Synthesize a closure type.
4656
            let ty.t bindings_ty = ty.mk_imm_tup(cx.fcx.lcx.ccx.tcx,
4657
                                                  bound_tys);
4658 4659 4660 4661

            // 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.
4662
            let ty.t tydesc_ty = ty.mk_type(cx.fcx.lcx.ccx.tcx);
4663

4664
            let vec[ty.t] captured_tys =
4665
                Vec.init_elt[ty.t](tydesc_ty, ty_param_count);
4666

4667
            let vec[ty.t] closure_tys =
4668 4669 4670
                vec(tydesc_ty,
                    outgoing_fty,
                    bindings_ty,
4671
                    ty.mk_imm_tup(cx.fcx.lcx.ccx.tcx, captured_tys));
4672

4673
            let ty.t closure_ty = ty.mk_imm_tup(cx.fcx.lcx.ccx.tcx,
4674
                                                 closure_tys);
4675 4676

            auto r = trans_malloc_boxed(bcx, closure_ty);
4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692
            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)));
4693
            auto bindings_tydesc = get_tydesc(bcx, bindings_ty, true);
4694 4695
            bcx = bindings_tydesc.bcx;
            bcx.build.Store(bindings_tydesc.val, bound_tydesc);
4696

4697 4698 4699 4700 4701 4702
            // 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.
4703
            auto llfnty = type_of_fn(bcx.fcx.lcx.ccx,
4704 4705 4706
                ty.ty_fn_proto(bcx.fcx.lcx.ccx.tcx, outgoing_fty),
                ty.ty_fn_args(bcx.fcx.lcx.ccx.tcx, outgoing_fty),
                ty.ty_fn_ret(bcx.fcx.lcx.ccx.tcx, outgoing_fty),
4707
                ty_param_count);
4708
            auto llclosurety = T_ptr(T_fn_pair(bcx.fcx.lcx.ccx.tn, llfnty));
4709

4710 4711
            // Store thunk-target.
            auto bound_target =
4712 4713
                bcx.build.GEP(closure,
                              vec(C_int(0),
4714
                                  C_int(abi.closure_elt_target)));
4715
            auto src = bcx.build.Load(f_res.res.val);
4716
            bound_target = bcx.build.PointerCast(bound_target, llclosurety);
4717
            bcx.build.Store(src, bound_target);
4718

4719
            // Copy expr values into boxed bindings.
4720
            i = 0u;
4721 4722 4723 4724
            auto bindings =
                bcx.build.GEP(closure,
                              vec(C_int(0),
                                  C_int(abi.closure_elt_bindings)));
4725 4726
            for (ValueRef v in bound_vals) {
                auto bound = bcx.build.GEP(bindings,
4727
                                           vec(C_int(0), C_int(i as int)));
4728
                bcx = copy_ty(bcx, INIT, bound, v, bound_tys.(i)).bcx;
4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748
                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;
                    }
4749 4750

                    outgoing_fty = ginfo.item_type;
4751
                }
4752 4753
            }

4754 4755 4756 4757
            // 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)));
4758

4759
            let ty.t pair_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
4760

4761
            let ValueRef llthunk =
4762
                trans_bind_thunk(cx.fcx.lcx, pair_ty, outgoing_fty,
4763
                                 args, closure_ty, bound_tys,
4764
                                 ty_param_count);
4765 4766 4767 4768 4769 4770 4771

            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)));
4772 4773 4774
            bcx.build.Store
                (bcx.build.PointerCast
                 (box,
4775
                  T_opaque_closure_ptr(bcx.fcx.lcx.ccx.tn)),
4776
                 pair_box);
4777

4778
            find_scope_cx(cx).cleanups +=
4779
                vec(clean(bind drop_slot(_, pair_v, pair_ty)));
4780

4781 4782
            ret res(bcx, pair_v);
        }
4783 4784 4785
    }
}

4786 4787 4788 4789 4790 4791 4792
fn trans_arg_expr(@block_ctxt cx,
                  ty.arg arg,
                  TypeRef lldestty0,
                  @ast.expr e) -> result {

    auto val;
    auto bcx = cx;
4793
    auto e_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, e);
4794

4795
    if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, e_ty)) {
4796 4797 4798
        auto re = trans_expr(bcx, e);
        val = re.val;
        bcx = re.bcx;
4799
    } else if (arg.mode == ty.mo_alias) {
4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825
        let lval_result lv;
        if (ty.is_lval(e)) {
            lv = trans_lval(bcx, e);
        } else {
            auto r = trans_expr(bcx, e);
            if (type_is_immediate(cx.fcx.lcx.ccx, e_ty)) {
                lv = lval_val(r.bcx, r.val);
            } else {
                lv = lval_mem(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.
            val = do_spill(lv.res.bcx, lv.res.val);
        }
    } else {
        auto re = trans_expr(bcx, e);
        val = re.val;
        bcx = re.bcx;
    }

4826
    if (arg.mode != ty.mo_alias) {
4827 4828 4829
        bcx = take_ty(bcx, val, e_ty).bcx;
    }

4830
    if (ty.type_contains_params(cx.fcx.lcx.ccx.tcx, arg.ty)) {
4831
        auto lldestty = lldestty0;
4832
        if (arg.mode == ty.mo_val) {
4833
            // FIXME: we'd prefer to use &&, but rustboot doesn't like it
4834
            if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, e_ty)) {
4835 4836 4837 4838 4839 4840
                lldestty = T_ptr(lldestty);
            }
        }
        val = bcx.build.PointerCast(val, lldestty);
    }

4841
    if (arg.mode == ty.mo_val) {
4842
        // FIXME: we'd prefer to use &&, but rustboot doesn't like it
4843
        if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, e_ty)) {
4844 4845 4846 4847 4848 4849 4850 4851
            // 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);
        }
    }
    ret res(bcx, val);
}

4852 4853 4854 4855 4856 4857 4858 4859 4860
// 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,
4861 4862 4863
              Option.t[ValueRef] llobj,
              Option.t[generic_info] gen,
              Option.t[ValueRef] lliterbody,
4864
              &vec[@ast.expr] es,
4865
              ty.t fn_ty)
4866 4867
    -> tup(@block_ctxt, vec[ValueRef], ValueRef) {

4868
    let vec[ty.arg] args = ty.ty_fn_args(cx.fcx.lcx.ccx.tcx, fn_ty);
4869 4870 4871 4872 4873 4874
    let vec[ValueRef] llargs = vec();
    let vec[ValueRef] lltydescs = vec();
    let @block_ctxt bcx = cx;


    // Arg 0: Output pointer.
4875
    auto retty = ty.ty_fn_ret(cx.fcx.lcx.ccx.tcx, fn_ty);
4876 4877 4878 4879
    auto llretslot_res = alloc_ty(bcx, retty);
    bcx = llretslot_res.bcx;
    auto llretslot = llretslot_res.val;

4880 4881 4882
    alt (gen) {
        case (some[generic_info](?g)) {
            lltydescs = g.tydescs;
4883 4884
            args = ty.ty_fn_args(cx.fcx.lcx.ccx.tcx, g.item_type);
            retty = ty.ty_fn_ret(cx.fcx.lcx.ccx.tcx, g.item_type);
4885 4886 4887 4888
        }
        case (_) {
        }
    }
4889
    if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, retty)) {
4890 4891
        llargs += vec(bcx.build.PointerCast
                      (llretslot, T_typaram_ptr(cx.fcx.lcx.ccx.tn)));
4892
    } else if (ty.type_contains_params(cx.fcx.lcx.ccx.tcx, retty)) {
4893 4894 4895 4896 4897
        // 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.
4898 4899
        llargs +=
            vec(cx.build.PointerCast(llretslot,
4900
                                     T_ptr(type_of(bcx.fcx.lcx.ccx, retty))));
4901
    } else {
4902
        llargs += vec(llretslot);
4903 4904 4905 4906
    }


    // Arg 1: Task pointer.
4907
    llargs += vec(bcx.fcx.lltaskptr);
4908 4909 4910 4911 4912 4913 4914

    // 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).
4915
            llargs += vec(bcx.build.Load(ob));
4916 4917
        }
        case (_) {
4918
            llargs += vec(llenv);
4919 4920 4921 4922 4923 4924
        }
    }

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

4925 4926 4927 4928
    // ... then possibly an lliterbody argument.
    alt (lliterbody) {
        case (none[ValueRef]) {}
        case (some[ValueRef](?lli)) {
4929
            llargs += vec(lli);
4930 4931 4932
        }
    }

4933
    // ... then explicit args.
4934 4935 4936 4937

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

4940 4941
    auto i = 0u;
    for (@ast.expr e in es) {
4942 4943 4944
        auto r = trans_arg_expr(bcx, args.(i), arg_tys.(i), e);
        bcx = r.bcx;
        llargs += vec(r.val);
4945 4946 4947 4948 4949 4950
        i += 1u;
    }

    ret tup(bcx, llargs, llretslot);
}

4951
fn trans_call(@block_ctxt cx, @ast.expr f,
4952
              Option.t[ValueRef] lliterbody,
4953 4954
              vec[@ast.expr] args,
              &ast.ann ann) -> result {
4955 4956 4957 4958 4959

    // NB: 'f' isn't necessarily a function; it might be an entire self-call
    // expression because of the hack that allows us to process self-calls
    // with trans_call.

4960
    auto f_res = trans_lval(cx, f);
4961
    auto faddr = f_res.res.val;
4962
    auto llenv = C_null(T_opaque_closure_ptr(cx.fcx.lcx.ccx.tn));
4963 4964 4965 4966 4967 4968 4969 4970 4971

    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;
4972 4973
            auto pair = faddr;
            faddr = bcx.build.GEP(pair, vec(C_int(0),
G
Graydon Hoare 已提交
4974
                                            C_int(abi.fn_field_code)));
4975
            faddr = bcx.build.Load(faddr);
4976

4977 4978 4979 4980
            auto llclosure = bcx.build.GEP(pair,
                                           vec(C_int(0),
                                               C_int(abi.fn_field_box)));
            llenv = bcx.build.Load(llclosure);
4981
        }
4982
    }
4983

4984
    let ty.t fn_ty;
4985
    alt (f_res.method_ty) {
4986
        case (some[ty.t](?meth)) {
4987 4988
            // self-call
            fn_ty = meth;
4989
        }
4990

4991
        case (_) {
4992
            fn_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, f);
4993 4994

        }
4995

4996
    }
4997

4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009
    auto ret_ty = ty.ann_to_type(ann);
    auto args_res = trans_args(f_res.res.bcx,
                               llenv, f_res.llobj,
                               f_res.generic,
                               lliterbody,
                               args, fn_ty);

    auto bcx = args_res._0;
    auto llargs = args_res._1;
    auto llretslot = args_res._2;

    /*
5010
    log "calling: " + val_str(cx.fcx.lcx.ccx.tn, faddr);
5011

5012
    for (ValueRef arg in llargs) {
5013
        log "arg: " + val_str(cx.fcx.lcx.ccx.tn, arg);
5014
    }
5015 5016 5017 5018 5019
    */

    bcx.build.FastCall(faddr, llargs);
    auto retval = C_nil();

5020 5021
    alt (lliterbody) {
        case (none[ValueRef]) {
5022
            if (!ty.type_is_nil(cx.fcx.lcx.ccx.tcx, ret_ty)) {
5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035
                retval = load_if_immediate(bcx, llretslot, ret_ty);
                // Retval doesn't correspond to anything really tangible in
                // the frame, but it's a ref all the same, so we put a note
                // here to drop it when we're done in this scope.
                find_scope_cx(cx).cleanups +=
                    vec(clean(bind drop_ty(_, retval, ret_ty)));
            }
        }
        case (some[ValueRef](_)) {
            // If there was an lliterbody, it means we were calling an
            // iter, and we are *not* the party using its 'output' value,
            // we should ignore llretslot.
        }
5036 5037 5038 5039
    }
    ret res(bcx, retval);
}

5040 5041
fn trans_tup(@block_ctxt cx, vec[ast.elt] elts,
             &ast.ann ann) -> result {
5042
    auto bcx = cx;
5043
    auto t = node_ann_type(bcx.fcx.lcx.ccx, ann);
5044 5045 5046 5047
    auto tup_res = alloc_ty(bcx, t);
    auto tup_val = tup_res.val;
    bcx = tup_res.bcx;

5048 5049
    find_scope_cx(cx).cleanups +=
        vec(clean(bind drop_ty(_, tup_val, t)));
G
Graydon Hoare 已提交
5050
    let int i = 0;
5051

5052
    for (ast.elt e in elts) {
5053
        auto e_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, e.expr);
5054 5055 5056 5057 5058
        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 已提交
5059 5060
        i += 1;
    }
5061
    ret res(bcx, tup_val);
G
Graydon Hoare 已提交
5062 5063
}

5064 5065
fn trans_vec(@block_ctxt cx, vec[@ast.expr] args,
             &ast.ann ann) -> result {
5066
    auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
5067
    auto unit_ty = t;
5068
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
5069 5070
        case (ty.ty_vec(?mt)) {
            unit_ty = mt.ty;
G
Graydon Hoare 已提交
5071 5072
        }
        case (_) {
5073
            cx.fcx.lcx.ccx.sess.bug("non-vec type in trans_vec");
G
Graydon Hoare 已提交
5074 5075 5076
        }
    }

5077 5078 5079
    auto bcx = cx;
    auto unit_sz = size_of(bcx, unit_ty);
    bcx = unit_sz.bcx;
5080
    auto data_sz = bcx.build.Mul(C_int(Vec.len[@ast.expr](args) as int),
5081
                                 unit_sz.val);
G
Graydon Hoare 已提交
5082 5083

    // FIXME: pass tydesc properly.
5084 5085
    auto sub = trans_upcall(bcx, "upcall_new_vec", vec(data_sz, C_int(0)),
                            false);
5086
    bcx = sub.bcx;
G
Graydon Hoare 已提交
5087

5088
    auto llty = type_of(bcx.fcx.lcx.ccx, t);
5089
    auto vec_val = vi2p(bcx, sub.val, llty);
5090 5091
    find_scope_cx(bcx).cleanups +=
        vec(clean(bind drop_ty(_, vec_val, t)));
G
Graydon Hoare 已提交
5092

5093 5094 5095 5096
    auto body = bcx.build.GEP(vec_val, vec(C_int(0),
                                           C_int(abi.vec_elt_data)));

    auto pseudo_tup_ty =
5097
        ty.mk_imm_tup(cx.fcx.lcx.ccx.tcx,
5098 5099
                      Vec.init_elt[ty.t](unit_ty,
                                           Vec.len[@ast.expr](args)));
G
Graydon Hoare 已提交
5100
    let int i = 0;
5101

G
Graydon Hoare 已提交
5102
    for (@ast.expr e in args) {
5103 5104 5105 5106
        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;
5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120

        // 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;
5121
        if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, unit_ty)) {
5122
            auto llunit_ty = type_of(cx.fcx.lcx.ccx, unit_ty);
5123 5124 5125 5126 5127 5128
            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 已提交
5129 5130
        i += 1;
    }
5131 5132 5133
    auto fill = bcx.build.GEP(vec_val,
                              vec(C_int(0), C_int(abi.vec_elt_fill)));
    bcx.build.Store(data_sz, fill);
5134

5135
    ret res(bcx, vec_val);
G
Graydon Hoare 已提交
5136 5137
}

5138
fn trans_rec(@block_ctxt cx, vec[ast.field] fields,
5139
             Option.t[@ast.expr] base, &ast.ann ann) -> result {
5140

5141
    auto bcx = cx;
5142
    auto t = node_ann_type(bcx.fcx.lcx.ccx, ann);
5143 5144 5145 5146
    auto rec_res = alloc_ty(bcx, t);
    auto rec_val = rec_res.val;
    bcx = rec_res.bcx;

5147 5148
    find_scope_cx(cx).cleanups +=
        vec(clean(bind drop_ty(_, rec_val, t)));
5149
    let int i = 0;
5150

G
Graydon Hoare 已提交
5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162
    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();
5163
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
G
Graydon Hoare 已提交
5164 5165 5166 5167
        case (ty.ty_rec(?flds)) { ty_fields = flds; }
    }

    for (ty.field tf in ty_fields) {
5168
        auto e_ty = tf.mt.ty;
5169 5170
        auto dst_res = GEP_tup_like(bcx, t, rec_val, vec(0, i));
        bcx = dst_res.bcx;
G
Graydon Hoare 已提交
5171 5172 5173 5174 5175

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

        for (ast.field f in fields) {
5176
            if (Str.eq(f.ident, tf.ident)) {
G
Graydon Hoare 已提交
5177 5178 5179 5180 5181 5182 5183
                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,
5184
                          load_if_immediate(bcx, src_res.val, e_ty));
G
Graydon Hoare 已提交
5185 5186 5187 5188
        }

        bcx = src_res.bcx;
        bcx = copy_ty(bcx, INIT, dst_res.val, src_res.val, e_ty).bcx;
5189 5190
        i += 1;
    }
5191
    ret res(bcx, rec_val);
5192 5193
}

G
Graydon Hoare 已提交
5194

G
Graydon Hoare 已提交
5195

5196
fn trans_expr(@block_ctxt cx, @ast.expr e) -> result {
5197
    alt (e.node) {
5198
        case (ast.expr_lit(?lit, ?ann)) {
5199
            ret res(cx, trans_lit(cx.fcx.lcx.ccx, *lit, ann));
5200 5201
        }

5202
        case (ast.expr_unary(?op, ?x, ?ann)) {
5203 5204 5205
            if (op != ast.deref) {
                ret trans_unary(cx, op, x, ann);
            }
5206 5207
        }

P
Patrick Walton 已提交
5208
        case (ast.expr_binary(?op, ?x, ?y, _)) {
5209
            ret trans_binary(cx, op, x, y);
5210
        }
5211

P
Patrick Walton 已提交
5212
        case (ast.expr_if(?cond, ?thn, ?els, _)) {
5213
            ret trans_if(cx, cond, thn, els);
5214 5215
        }

G
Graydon Hoare 已提交
5216 5217 5218 5219
        case (ast.expr_for(?decl, ?seq, ?body, _)) {
            ret trans_for(cx, decl, seq, body);
        }

5220 5221 5222 5223
        case (ast.expr_for_each(?decl, ?seq, ?body, _)) {
            ret trans_for_each(cx, decl, seq, body);
        }

5224
        case (ast.expr_while(?cond, ?body, _)) {
5225
            ret trans_while(cx, cond, body);
5226 5227
        }

5228
        case (ast.expr_do_while(?body, ?cond, _)) {
5229
            ret trans_do_while(cx, body, cond);
5230 5231
        }

5232 5233
        case (ast.expr_alt(?expr, ?arms, ?ann)) {
            ret trans_alt(cx, expr, arms, ann);
P
Patrick Walton 已提交
5234 5235
        }

P
Patrick Walton 已提交
5236
        case (ast.expr_block(?blk, _)) {
5237 5238 5239 5240 5241 5242 5243 5244
            auto sub_cx = new_scope_block_ctxt(cx, "block-expr body");
            auto next_cx = new_sub_block_ctxt(cx, "next");
            auto sub = trans_block(sub_cx, blk);

            cx.build.Br(sub_cx.llbb);
            sub.bcx.build.Br(next_cx.llbb);

            ret res(next_cx, sub.val);
5245
        }
5246

5247
        case (ast.expr_assign(?dst, ?src, ?ann)) {
5248
            auto lhs_res = trans_lval(cx, dst);
5249
            assert (lhs_res.is_mem);
5250
            auto rhs_res = trans_expr(lhs_res.res.bcx, src);
5251
            auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
G
Graydon Hoare 已提交
5252
            // FIXME: calculate copy init-ness in typestate.
5253 5254
            ret copy_ty(rhs_res.bcx, DROP_EXISTING,
                        lhs_res.res.val, rhs_res.val, t);
5255
        }
G
Graydon Hoare 已提交
5256

5257
        case (ast.expr_assign_op(?op, ?dst, ?src, ?ann)) {
5258
            auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
5259
            auto lhs_res = trans_lval(cx, dst);
5260
            assert (lhs_res.is_mem);
5261
            auto rhs_res = trans_expr(lhs_res.res.bcx, src);
5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273
            if (ty.type_is_sequence(cx.fcx.lcx.ccx.tcx, t)) {
                alt (op) {
                    case (ast.add) {
                        ret trans_vec_append(rhs_res.bcx, t,
                                             lhs_res.res.val,
                                             rhs_res.val);
                    }
                    case (_) { }
                }
            }
            auto lhs_val = load_if_immediate(rhs_res.bcx,
                                             lhs_res.res.val, t);
5274 5275
            auto v = trans_eager_binop(rhs_res.bcx, op, t,
                                       lhs_val, rhs_res.val);
5276
            // FIXME: calculate copy init-ness in typestate.
5277 5278
            ret copy_ty(v.bcx, DROP_EXISTING,
                        lhs_res.res.val, v.val, t);
5279 5280
        }

5281 5282 5283 5284
        case (ast.expr_bind(?f, ?args, ?ann)) {
            ret trans_bind(cx, f, args, ann);
        }

G
Graydon Hoare 已提交
5285
        case (ast.expr_call(?f, ?args, ?ann)) {
5286
            ret trans_call(cx, f, none[ValueRef], args, ann);
5287 5288
        }

5289
        case (ast.expr_cast(?e, _, ?ann)) {
5290
            ret trans_cast(cx, e, ann);
5291
        }
G
Graydon Hoare 已提交
5292

5293
        case (ast.expr_vec(?args, _, ?ann)) {
G
Graydon Hoare 已提交
5294 5295 5296
            ret trans_vec(cx, args, ann);
        }

G
Graydon Hoare 已提交
5297 5298 5299
        case (ast.expr_tup(?args, ?ann)) {
            ret trans_tup(cx, args, ann);
        }
G
Graydon Hoare 已提交
5300

5301 5302
        case (ast.expr_rec(?args, ?base, ?ann)) {
            ret trans_rec(cx, args, base, ann);
5303 5304
        }

5305
        case (ast.expr_ext(_, _, _, ?expanded, _)) {
5306
            ret trans_expr(cx, expanded);
5307 5308
        }

5309
        case (ast.expr_fail(_)) {
5310
            ret trans_fail(cx, some[common.span](e.span), "explicit failure");
5311 5312
        }

M
Marijn Haverbeke 已提交
5313 5314
        case (ast.expr_log(?lvl, ?a, _)) {
            ret trans_log(lvl, cx, a);
5315 5316
        }

5317 5318 5319 5320 5321
        case (ast.expr_assert(?a, _)) {
            ret trans_check_expr(cx, a);
        }

        case (ast.expr_check(?a, _)) {
5322 5323 5324
            ret trans_check_expr(cx, a);
        }

5325
        case (ast.expr_break(?a)) {
5326 5327 5328
            ret trans_break(cx);
        }

5329
        case (ast.expr_cont(?a)) {
5330 5331 5332
            ret trans_cont(cx);
        }

5333
        case (ast.expr_ret(?e, _)) {
5334 5335 5336
            ret trans_ret(cx, e);
        }

5337
        case (ast.expr_put(?e, _)) {
5338 5339 5340
            ret trans_put(cx, e);
        }

5341
        case (ast.expr_be(?e, _)) {
5342 5343 5344
            ret trans_be(cx, e);
        }

B
Brian Anderson 已提交
5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360
        case (ast.expr_port(?ann)) {
            ret trans_port(cx, ann);
        }

        case (ast.expr_chan(?e, ?ann)) {
            ret trans_chan(cx, e, ann);
        }

        case (ast.expr_send(?lhs, ?rhs, ?ann)) {
            ret trans_send(cx, lhs, rhs, ann);
        }

        case (ast.expr_recv(?lhs, ?rhs, ?ann)) {
            ret trans_recv(cx, lhs, rhs, ann);
        }

5361
        case (_) {
5362
            // The expression is an lvalue. Fall through.
5363
        }
5364
    }
5365 5366 5367 5368

    // lval cases fall through to trans_lval and then
    // possibly load the result (if it's non-structural).

5369
    auto t = ty.expr_ty(cx.fcx.lcx.ccx.tcx, e);
5370
    auto sub = trans_lval(cx, e);
5371
    ret res(sub.res.bcx, load_if_immediate(sub.res.bcx, sub.res.val, t));
5372 5373
}

5374
// We pass structural values around the compiler "by pointer" and
5375 5376 5377 5378 5379
// non-structural values (scalars, boxes, pointers) "by value". We call the
// latter group "immediates" and, in some circumstances when we know we have a
// pointer (or need one), perform load/store operations based on the
// immediate-ness of the type.

5380
fn type_is_immediate(@crate_ctxt ccx, ty.t t) -> bool {
5381 5382 5383
    ret ty.type_is_scalar(ccx.tcx, t) ||
        ty.type_is_boxed(ccx.tcx, t) ||
        ty.type_is_native(ccx.tcx, t);
5384 5385 5386 5387 5388 5389 5390 5391
}

fn do_spill(@block_ctxt cx, ValueRef v) -> ValueRef {
    // We have a value but we have to spill it to pass by alias.
    auto llptr = alloca(cx, val_ty(v));
    cx.build.Store(v, llptr);
    ret llptr;
}
5392

5393
fn spill_if_immediate(@block_ctxt cx, ValueRef v, ty.t t) -> ValueRef {
5394
    if (type_is_immediate(cx.fcx.lcx.ccx, t)) {
5395 5396 5397 5398 5399
        ret do_spill(cx, v);
    }
    ret v;
}

5400
fn load_if_immediate(@block_ctxt cx, ValueRef v, ty.t t) -> ValueRef {
5401
    if (type_is_immediate(cx.fcx.lcx.ccx, t)) {
5402 5403
        ret cx.build.Load(v);
    }
5404
    ret v;
5405 5406
}

M
Marijn Haverbeke 已提交
5407
fn trans_log(int lvl, @block_ctxt cx, @ast.expr e) -> result {
5408
    auto lcx = cx.fcx.lcx;
5409
    auto modname = Str.connect(lcx.module_path, ".");
5410 5411 5412 5413 5414
    auto global;
    if (lcx.ccx.module_data.contains_key(modname)) {
        global = lcx.ccx.module_data.get(modname);
    } else {
        global = llvm.LLVMAddGlobal(lcx.ccx.llmod, T_int(),
5415
                                    Str.buf("_rust_mod_log_" + modname));
5416 5417 5418 5419 5420 5421 5422
        llvm.LLVMSetGlobalConstant(global, False);
        llvm.LLVMSetInitializer(global, C_null(T_int()));
        llvm.LLVMSetLinkage(global, lib.llvm.LLVMInternalLinkage
                            as llvm.Linkage);
        lcx.ccx.module_data.insert(modname, global);
    }

5423
    auto log_cx = new_scope_block_ctxt(cx, "log");
5424 5425
    auto after_cx = new_sub_block_ctxt(cx, "after");
    auto load = cx.build.Load(global);
M
Marijn Haverbeke 已提交
5426
    auto test = cx.build.ICmp(lib.llvm.LLVMIntSGE, load, C_int(lvl));
5427 5428 5429
    cx.build.CondBr(test, log_cx.llbb, after_cx.llbb);

    auto sub = trans_expr(log_cx, e);
5430
    auto e_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, e);
5431

5432
    auto log_bcx = sub.bcx;
5433
    if (ty.type_is_fp(cx.fcx.lcx.ccx.tcx, e_ty)) {
5434 5435
        let TypeRef tr;
        let bool is32bit = false;
5436
        alt (ty.struct(cx.fcx.lcx.ccx.tcx, e_ty)) {
5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448
            case (ty.ty_machine(util.common.ty_f32)) {
                tr = T_f32();
                is32bit = true;
            }
            case (ty.ty_machine(util.common.ty_f64)) {
                tr = T_f64();
            }
            case (_) {
                tr = T_float();
            }
        }
        if (is32bit) {
5449
            auto uval = trans_upcall(log_bcx,
5450
                                     "upcall_log_float",
5451 5452
                                     vec(C_int(lvl), sub.val),
                                     false);
5453
            log_bcx = uval.bcx;
5454
        } else {
5455
            auto tmp = alloca(log_bcx, tr);
5456
            sub.bcx.build.Store(sub.val, tmp);
5457
            auto uval = trans_upcall(log_bcx,
5458
                                     "upcall_log_double",
5459
                                     vec(C_int(lvl), vp2i(log_bcx, tmp)),
5460
                                     false);
5461
            log_bcx = uval.bcx;
5462
        }
5463
    } else {
5464
        alt (ty.struct(cx.fcx.lcx.ccx.tcx, e_ty)) {
5465
            case (ty.ty_str) {
5466 5467 5468 5469 5470
                auto v = vp2i(log_bcx, sub.val);
                log_bcx = trans_upcall(log_bcx,
                                       "upcall_log_str",
                                       vec(C_int(lvl), v),
                                       false).bcx;
5471 5472
            }
            case (_) {
M
Marijn Haverbeke 已提交
5473
                auto v = vec(C_int(lvl), sub.val);
5474 5475 5476
                log_bcx = trans_upcall(log_bcx,
                                       "upcall_log_int",
                                       v, false).bcx;
5477
            }
5478 5479
        }
    }
5480

5481 5482 5483
    log_bcx = trans_block_cleanups(log_bcx, log_cx);
    log_bcx.build.Br(after_cx.llbb);

5484
    ret res(after_cx, C_nil());
5485 5486
}

5487
fn trans_check_expr(@block_ctxt cx, @ast.expr e) -> result {
5488 5489
    auto cond_res = trans_expr(cx, e);

5490
    auto expr_str = util.common.expr_to_str(e);
5491
    auto fail_cx = new_sub_block_ctxt(cx, "fail");
5492
    auto fail_res = trans_fail(fail_cx, some[common.span](e.span), expr_str);
5493

5494
    auto next_cx = new_sub_block_ctxt(cx, "next");
5495 5496 5497 5498 5499 5500
    cond_res.bcx.build.CondBr(cond_res.val,
                              next_cx.llbb,
                              fail_cx.llbb);
    ret res(next_cx, C_nil());
}

5501
fn trans_fail(@block_ctxt cx, Option.t[common.span] sp_opt, str fail_str)
5502
        -> result {
5503
    auto V_fail_str = p2i(C_cstr(cx.fcx.lcx.ccx, fail_str));
5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517

    auto V_filename; auto V_line;
    alt (sp_opt) {
        case (some[common.span](?sp)) {
            auto loc = cx.fcx.lcx.ccx.sess.lookup_pos(sp.lo);
            V_filename = p2i(C_cstr(cx.fcx.lcx.ccx, loc.filename));
            V_line = loc.line as int;
        }
        case (none[common.span]) {
            V_filename = p2i(C_str(cx.fcx.lcx.ccx, "<runtime>"));
            V_line = 0;
        }
    }

B
Brian Anderson 已提交
5518 5519
    auto args = vec(V_fail_str, V_filename, C_int(V_line));

5520
    auto sub = trans_upcall(cx, "upcall_fail", args, false);
5521 5522
    sub.bcx.build.Unreachable();
    ret res(sub.bcx, C_nil());
B
Brian Anderson 已提交
5523 5524
}

5525
fn trans_put(@block_ctxt cx, &Option.t[@ast.expr] e) -> result {
5526 5527 5528 5529 5530
    auto llcallee = C_nil();
    auto llenv = C_nil();

    alt (cx.fcx.lliterbody) {
        case (some[ValueRef](?lli)) {
5531
            auto slot = alloca(cx, val_ty(lli));
5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543
            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;
5544
    auto dummy_retslot = alloca(bcx, T_nil());
5545 5546 5547 5548
    let vec[ValueRef] llargs = vec(dummy_retslot, cx.fcx.lltaskptr, llenv);
    alt (e) {
        case (none[@ast.expr]) { }
        case (some[@ast.expr](?x)) {
5549
            auto e_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, x);
5550
            auto arg = rec(mode=ty.mo_alias, ty=e_ty);
5551 5552
            auto arg_tys = type_of_explicit_args(cx.fcx.lcx.ccx, vec(arg));
            auto r = trans_arg_expr(bcx, arg, arg_tys.(0), x);
5553
            bcx = r.bcx;
5554
            llargs += vec(r.val);
5555 5556
        }
    }
5557

5558
    ret res(bcx, bcx.build.FastCall(llcallee, llargs));
5559 5560
}

5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572
fn trans_break_cont(@block_ctxt cx, bool to_end) -> result {
    auto bcx = cx;
    // Locate closest loop block, outputting cleanup as we go.
    auto cleanup_cx = cx;
    while (true) {
        bcx = trans_block_cleanups(bcx, cleanup_cx);
        alt (cleanup_cx.kind) {
            case (LOOP_SCOPE_BLOCK(?_cont, ?_break)) {
                if (to_end) {
                    bcx.build.Br(_break.llbb);
                } else {
                    alt (_cont) {
5573
                        case (Option.some[@block_ctxt](?_cont)) {
5574 5575 5576 5577 5578 5579 5580
                            bcx.build.Br(_cont.llbb);
                        }
                        case (_) {
                            bcx.build.Br(cleanup_cx.llbb);
                        }
                    }
                }
5581 5582
                ret res(new_sub_block_ctxt(bcx, "break_cont.unreachable"),
                        C_nil());
5583 5584 5585 5586 5587 5588 5589 5590
            }
            case (_) {
                alt (cleanup_cx.parent) {
                    case (parent_some(?cx)) { cleanup_cx = cx; }
                }
            }
        }
    }
5591
    fail;
5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602
}

fn trans_break(@block_ctxt cx) -> result {
    ret trans_break_cont(cx, true);
}

fn trans_cont(@block_ctxt cx) -> result {
    ret trans_break_cont(cx, false);
}


5603
fn trans_ret(@block_ctxt cx, &Option.t[@ast.expr] e) -> result {
5604 5605 5606
    auto bcx = cx;
    auto val = C_nil();

5607 5608
    alt (e) {
        case (some[@ast.expr](?x)) {
5609
            auto t = ty.expr_ty(cx.fcx.lcx.ccx.tcx, x);
5610 5611 5612
            auto r = trans_expr(cx, x);
            bcx = r.bcx;
            val = r.val;
5613
            bcx = copy_ty(bcx, INIT, cx.fcx.llretptr, val, t).bcx;
5614
        }
5615 5616 5617 5618 5619
        case (_) {
            auto t = llvm.LLVMGetElementType(val_ty(cx.fcx.llretptr));
            auto null = lib.llvm.llvm.LLVMConstNull(t);
            bcx.build.Store(null, cx.fcx.llretptr);
        }
5620 5621
    }

5622 5623
    // Run all cleanups and back out.
    let bool more_cleanups = true;
5624
    auto cleanup_cx = cx;
5625
    while (more_cleanups) {
5626
        bcx = trans_block_cleanups(bcx, cleanup_cx);
5627
        alt (cleanup_cx.parent) {
5628
            case (parent_some(?b)) {
5629
                cleanup_cx = b;
5630 5631 5632 5633 5634 5635 5636
            }
            case (parent_none) {
                more_cleanups = false;
            }
        }
    }

5637
    bcx.build.RetVoid();
5638
    ret res(new_sub_block_ctxt(bcx, "ret.unreachable"), C_nil());
5639 5640
}

5641
fn trans_be(@block_ctxt cx, @ast.expr e) -> result {
5642
    // FIXME: This should be a typestate precondition
5643
    assert (ast.is_call_expr(e));
5644 5645
    // FIXME: Turn this into a real tail call once
    // calling convention issues are settled
5646 5647 5648
    ret trans_ret(cx, some(e));
}

B
Brian Anderson 已提交
5649 5650
fn trans_port(@block_ctxt cx, ast.ann ann) -> result {

5651
    auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
B
Brian Anderson 已提交
5652
    auto unit_ty;
5653
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
B
Brian Anderson 已提交
5654 5655 5656 5657
        case (ty.ty_port(?t)) {
            unit_ty = t;
        }
        case (_) {
5658
            cx.fcx.lcx.ccx.sess.bug("non-port type in trans_port");
B
Brian Anderson 已提交
5659 5660 5661 5662
            fail;
        }
    }

5663
    auto llunit_ty = type_of(cx.fcx.lcx.ccx, unit_ty);
B
Brian Anderson 已提交
5664 5665 5666 5667

    auto bcx = cx;
    auto unit_sz = size_of(bcx, unit_ty);
    bcx = unit_sz.bcx;
5668
    auto sub = trans_upcall(bcx, "upcall_new_port", vec(unit_sz.val), false);
B
Brian Anderson 已提交
5669
    bcx = sub.bcx;
5670
    auto llty = type_of(cx.fcx.lcx.ccx, t);
B
Brian Anderson 已提交
5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684
    auto port_val = vi2p(bcx, sub.val, llty);
    auto dropref = clean(bind drop_ty(_, port_val, t));
    find_scope_cx(bcx).cleanups += vec(dropref);

    ret res(bcx, port_val);
}

fn trans_chan(@block_ctxt cx, @ast.expr e, ast.ann ann) -> result {

    auto bcx = cx;
    auto prt = trans_expr(bcx, e);
    bcx = prt.bcx;

    auto prt_val = vp2i(bcx, prt.val);
5685
    auto sub = trans_upcall(bcx, "upcall_new_chan", vec(prt_val), false);
B
Brian Anderson 已提交
5686 5687
    bcx = sub.bcx;

5688 5689
    auto chan_ty = node_ann_type(bcx.fcx.lcx.ccx, ann);
    auto chan_llty = type_of(bcx.fcx.lcx.ccx, chan_ty);
B
Brian Anderson 已提交
5690 5691 5692 5693 5694 5695 5696 5697 5698
    auto chan_val = vi2p(bcx, sub.val, chan_llty);
    auto dropref = clean(bind drop_ty(_, chan_val, chan_ty));
    find_scope_cx(bcx).cleanups += vec(dropref);

    ret res(bcx, chan_val);
}

fn trans_send(@block_ctxt cx, @ast.expr lhs, @ast.expr rhs,
              ast.ann ann) -> result {
5699 5700 5701 5702 5703 5704 5705

    auto bcx = cx;
    auto chn = trans_expr(bcx, lhs);
    bcx = chn.bcx;
    auto data = trans_expr(bcx, rhs);
    bcx = data.bcx;

5706
    auto chan_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
5707
    auto unit_ty;
5708
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, chan_ty)) {
5709 5710 5711 5712
        case (ty.ty_chan(?t)) {
            unit_ty = t;
        }
        case (_) {
5713
            bcx.fcx.lcx.ccx.sess.bug("non-chan type in trans_send");
5714 5715 5716 5717
            fail;
        }
    }

5718 5719 5720 5721
    auto data_alloc = alloc_ty(bcx, unit_ty);
    bcx = data_alloc.bcx;
    auto data_tmp = copy_ty(bcx, INIT, data_alloc.val, data.val, unit_ty);
    bcx = data_tmp.bcx;
5722

5723 5724
    find_scope_cx(bcx).cleanups +=
        vec(clean(bind drop_ty(_, data_alloc.val, unit_ty)));
5725

5726 5727
    auto sub = trans_upcall(bcx, "upcall_send",
                            vec(vp2i(bcx, chn.val),
5728
                                vp2i(bcx, data_alloc.val)), false);
5729 5730
    bcx = sub.bcx;

5731
    ret res(bcx, chn.val);
B
Brian Anderson 已提交
5732 5733 5734 5735
}

fn trans_recv(@block_ctxt cx, @ast.expr lhs, @ast.expr rhs,
              ast.ann ann) -> result {
5736 5737

    auto bcx = cx;
B
Brian Anderson 已提交
5738
    auto data = trans_lval(bcx, lhs);
5739
    assert (data.is_mem);
B
Brian Anderson 已提交
5740
    bcx = data.res.bcx;
5741
    auto unit_ty = node_ann_type(bcx.fcx.lcx.ccx, ann);
5742 5743 5744

    // FIXME: calculate copy init-ness in typestate.
    ret recv_val(bcx, data.res.val, rhs, unit_ty, DROP_EXISTING);
5745
 }
5746 5747

fn recv_val(@block_ctxt cx, ValueRef lhs, @ast.expr rhs,
5748
            ty.t unit_ty, copy_action action) -> result {
5749 5750

    auto bcx = cx;
5751 5752
    auto prt = trans_expr(bcx, rhs);
    bcx = prt.bcx;
B
Brian Anderson 已提交
5753

5754
    auto sub = trans_upcall(bcx, "upcall_recv",
5755
                            vec(vp2i(bcx, lhs),
5756
                                vp2i(bcx, prt.val)), false);
5757 5758
    bcx = sub.bcx;

5759
    auto data_load = load_if_immediate(bcx, lhs, unit_ty);
5760
    auto cp = copy_ty(bcx, action, lhs, data_load, unit_ty);
5761
    bcx = cp.bcx;
B
Brian Anderson 已提交
5762

5763
    // TODO: Any cleanup need to be done here?
5764

5765
    ret res(bcx, lhs);
B
Brian Anderson 已提交
5766 5767
}

5768 5769 5770
fn init_local(@block_ctxt cx, @ast.local local) -> result {

    // Make a note to drop this slot on the way out.
5771
    assert (cx.fcx.lllocals.contains_key(local.id));
5772
    auto llptr = cx.fcx.lllocals.get(local.id);
5773
    auto ty = node_ann_type(cx.fcx.lcx.ccx, local.ann);
5774 5775 5776
    auto bcx = cx;

    find_scope_cx(cx).cleanups +=
5777
        vec(clean(bind drop_slot(_, llptr, ty)));
5778 5779

    alt (local.init) {
5780
        case (some[ast.initializer](?init)) {
5781 5782 5783 5784 5785 5786 5787 5788 5789
            alt (init.op) {
                case (ast.init_assign) {
                    auto sub = trans_expr(bcx, init.expr);
                    bcx = copy_ty(sub.bcx, INIT, llptr, sub.val, ty).bcx;
                }
                case (ast.init_recv) {
                    bcx = recv_val(bcx, llptr, init.expr, ty, INIT).bcx;
                }
            }
5790 5791
        }
        case (_) {
5792
            bcx = zero_alloca(bcx, llptr, ty).bcx;
5793 5794 5795 5796 5797
        }
    }
    ret res(bcx, llptr);
}

5798
fn zero_alloca(@block_ctxt cx, ValueRef llptr, ty.t t) -> result {
5799
    auto bcx = cx;
5800
    if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
5801
        auto llsz = size_of(bcx, t);
5802 5803 5804
        auto llalign = align_of(llsz.bcx, t);
        bcx = call_bzero(llalign.bcx, llptr,
                         llsz.val, llalign.val).bcx;
5805
    } else {
5806
        auto llty = type_of(bcx.fcx.lcx.ccx, t);
5807 5808 5809 5810 5811 5812
        auto null = lib.llvm.llvm.LLVMConstNull(llty);
        bcx.build.Store(null, llptr);
    }
    ret res(bcx, llptr);
 }

5813 5814
fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
    auto bcx = cx;
5815
    alt (s.node) {
5816
        case (ast.stmt_expr(?e,_)) {
5817
            bcx = trans_expr(cx, e).bcx;
5818
        }
5819

5820
        case (ast.stmt_decl(?d,_)) {
5821 5822
            alt (d.node) {
                case (ast.decl_local(?local)) {
5823
                    bcx = init_local(bcx, local).bcx;
5824
                }
G
Graydon Hoare 已提交
5825
                case (ast.decl_item(?i)) {
5826
                    trans_item(cx.fcx.lcx, *i);
G
Graydon Hoare 已提交
5827
                }
5828 5829
            }
        }
5830
        case (_) {
5831
            cx.fcx.lcx.ccx.sess.unimpl("stmt variant");
5832 5833
        }
    }
5834
    ret res(bcx, C_nil());
5835 5836
}

5837
fn new_builder(BasicBlockRef llbb) -> builder {
5838 5839
    let BuilderRef llbuild = llvm.LLVMCreateBuilder();
    llvm.LLVMPositionBuilderAtEnd(llbuild, llbb);
5840
    ret builder(llbuild, @mutable false);
5841 5842
}

5843 5844
// You probably don't want to use this one. See the
// next three functions instead.
5845
fn new_block_ctxt(@fn_ctxt cx, block_parent parent,
5846
                  block_kind kind,
5847
                  str name) -> @block_ctxt {
5848
    let vec[cleanup] cleanups = vec();
5849
    let BasicBlockRef llbb =
5850
        llvm.LLVMAppendBasicBlock(cx.llfn,
5851
                                  Str.buf(cx.lcx.ccx.names.next(name)));
5852

5853
    ret @rec(llbb=llbb,
5854
             build=new_builder(llbb),
5855
             parent=parent,
5856
             kind=kind,
5857
             mutable cleanups=cleanups,
5858 5859 5860
             fcx=cx);
}

5861 5862
// 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 {
5863 5864
    ret new_block_ctxt(fcx, parent_none, SCOPE_BLOCK,
                       "function top level");
5865
}
5866

5867 5868
// 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 {
5869
    ret new_block_ctxt(bcx.fcx, parent_some(bcx), SCOPE_BLOCK, n);
5870 5871
}

5872
fn new_loop_scope_block_ctxt(@block_ctxt bcx, Option.t[@block_ctxt] _cont,
5873 5874 5875 5876 5877
                             @block_ctxt _break, str n) -> @block_ctxt {
    ret new_block_ctxt(bcx.fcx, parent_some(bcx),
                       LOOP_SCOPE_BLOCK(_cont, _break), n);
}

5878
// Use this when you're making a general CFG BB within a scope.
5879
fn new_sub_block_ctxt(@block_ctxt bcx, str n) -> @block_ctxt {
5880
    ret new_block_ctxt(bcx.fcx, parent_some(bcx), NON_SCOPE_BLOCK, n);
5881
}
5882

5883

5884 5885
fn trans_block_cleanups(@block_ctxt cx,
                        @block_ctxt cleanup_cx) -> @block_ctxt {
5886
    auto bcx = cx;
5887

5888
    if (cleanup_cx.kind == NON_SCOPE_BLOCK) {
5889
        assert (Vec.len[cleanup](cleanup_cx.cleanups) == 0u);
5890 5891
    }

5892
    auto i = Vec.len[cleanup](cleanup_cx.cleanups);
5893 5894 5895
    while (i > 0u) {
        i -= 1u;
        auto c = cleanup_cx.cleanups.(i);
5896
        alt (c) {
5897
            case (clean(?cfn)) {
5898
                bcx = cfn(bcx).bcx;
5899 5900 5901
            }
        }
    }
5902 5903 5904
    ret bcx;
}

5905 5906 5907 5908 5909
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) {
5910
            case (ast.stmt_decl(?d,_)) {
5911 5912 5913 5914
                alt (d.node) {
                    case (ast.decl_local(?local)) {
                        put local;
                    }
5915
                    case (_) { /* fall through */ }
5916 5917
                }
            }
5918
            case (_) { /* fall through */ }
5919 5920 5921 5922
        }
    }
}

5923 5924 5925 5926 5927 5928 5929 5930 5931 5932
fn llallocas_block_ctxt(@fn_ctxt fcx) -> @block_ctxt {
    let vec[cleanup] cleanups = vec();
    ret @rec(llbb=fcx.llallocas,
             build=new_builder(fcx.llallocas),
             parent=parent_none,
             kind=SCOPE_BLOCK,
             mutable cleanups=cleanups,
             fcx=fcx);
}

5933
fn alloc_ty(@block_ctxt cx, ty.t t) -> result {
5934
    auto val = C_int(0);
5935
    if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
5936 5937 5938 5939 5940 5941 5942 5943 5944

        // NB: we have to run this particular 'size_of' in a
        // block_ctxt built on the llallocas block for the fn,
        // so that the size dominates the array_alloca that
        // comes next.

        auto n = size_of(llallocas_block_ctxt(cx.fcx), t);
        cx.fcx.llallocas = n.bcx.llbb;
        val = array_alloca(cx, T_i8(), n.val);
5945
    } else {
5946
        val = alloca(cx, type_of(cx.fcx.lcx.ccx, t));
5947
    }
5948 5949 5950 5951 5952 5953 5954
    // NB: since we've pushed all size calculations in this
    // function up to the alloca block, we actually return the
    // block passed into us unmodified; it doesn't really
    // have to be passed-and-returned here, but it fits
    // past caller conventions and may well make sense again,
    // so we leave it as-is.
    ret res(cx, val);
5955 5956
}

5957
fn alloc_local(@block_ctxt cx, @ast.local local) -> result {
5958
    auto t = node_ann_type(cx.fcx.lcx.ccx, local.ann);
5959 5960 5961 5962 5963
    auto r = alloc_ty(cx, t);
    r.bcx.fcx.lllocals.insert(local.id, r.val);
    ret r;
}

5964
fn trans_block(@block_ctxt cx, &ast.block b) -> result {
5965 5966
    auto bcx = cx;

5967
    for each (@ast.local local in block_locals(b)) {
5968
        bcx = alloc_local(bcx, local).bcx;
5969
    }
5970
    auto r = res(bcx, C_nil());
5971

5972
    for (@ast.stmt s in b.node.stmts) {
5973 5974
        r = trans_stmt(bcx, *s);
        bcx = r.bcx;
5975 5976 5977 5978 5979
        // 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;
        }
5980
    }
5981

5982 5983 5984 5985
    alt (b.node.expr) {
        case (some[@ast.expr](?e)) {
            r = trans_expr(bcx, e);
            bcx = r.bcx;
5986

5987 5988
            if (is_terminated(bcx)) {
                ret r;
5989
            } else {
5990 5991
                auto r_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, e);
                if (!ty.type_is_nil(cx.fcx.lcx.ccx.tcx, r_ty)) {
5992
                    // The value resulting from the block gets copied into an
B
Brian Anderson 已提交
5993
                    // alloca created in an outer scope and its refcount
5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005
                    // bumped so that it can escape this block. This means
                    // that it will definitely live until the end of the
                    // enclosing scope, even if nobody uses it, which may be
                    // something of a surprise.

                    // It's possible we never hit this block, so the alloca
                    // must be initialized to null, then when the potential
                    // value finally goes out of scope the drop glue will see
                    // that it was never used and ignore it.

                    // NB: Here we're building and initalizing the alloca in
                    // the alloca context, not this block's context.
6006
                    auto res_alloca = alloc_ty(bcx, r_ty);
6007 6008
                    auto llbcx = llallocas_block_ctxt(bcx.fcx);
                    zero_alloca(llbcx, res_alloca.val, r_ty);
6009 6010

                    // Now we're working in our own block context again
6011 6012 6013 6014 6015 6016
                    auto res_copy = copy_ty(bcx, INIT,
                                            res_alloca.val, r.val, r_ty);
                    bcx = res_copy.bcx;

                    fn drop_hoisted_ty(@block_ctxt cx,
                                       ValueRef alloca_val,
6017
                                       ty.t t) -> result {
6018
                        auto reg_val = load_if_immediate(cx,
6019 6020 6021 6022 6023 6024 6025 6026
                                                            alloca_val, t);
                        ret drop_ty(cx, reg_val, t);
                    }

                    auto cleanup = bind drop_hoisted_ty(_, res_alloca.val,
                                                        r_ty);
                    find_outer_scope_cx(bcx).cleanups += vec(clean(cleanup));
                }
6027 6028 6029 6030 6031 6032 6033
            }
        }
        case (none[@ast.expr]) {
            r = res(bcx, C_nil());
        }
    }

6034
    bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
6035
    ret res(bcx, r.val);
6036 6037
}

6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048
fn new_local_ctxt(@crate_ctxt ccx) -> @local_ctxt {
    let vec[str] pth = vec();
    let vec[ast.ty_param] obj_typarams = vec();
    let vec[ast.obj_field] obj_fields = vec();
    ret @rec(path=pth,
             module_path=vec(crate_name(ccx, "main")),
             obj_typarams = obj_typarams,
             obj_fields = obj_fields,
             ccx = ccx);
}

6049 6050 6051 6052 6053 6054 6055
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args

6056
fn new_fn_ctxt(@local_ctxt cx,
6057
               ValueRef llfndecl) -> @fn_ctxt {
6058

6059 6060 6061
    let ValueRef llretptr = llvm.LLVMGetParam(llfndecl, 0u);
    let ValueRef lltaskptr = llvm.LLVMGetParam(llfndecl, 1u);
    let ValueRef llenv = llvm.LLVMGetParam(llfndecl, 2u);
6062 6063

    let hashmap[ast.def_id, ValueRef] llargs = new_def_hash[ValueRef]();
6064 6065
    let hashmap[ast.def_id, ValueRef] llobjfields = new_def_hash[ValueRef]();
    let hashmap[ast.def_id, ValueRef] lllocals = new_def_hash[ValueRef]();
6066
    let hashmap[ast.def_id, ValueRef] llupvars = new_def_hash[ValueRef]();
6067

6068
    let BasicBlockRef llallocas =
6069
        llvm.LLVMAppendBasicBlock(llfndecl, Str.buf("allocas"));
6070

6071
    ret @rec(llfn=llfndecl,
6072
             lltaskptr=lltaskptr,
6073 6074
             llenv=llenv,
             llretptr=llretptr,
6075
             mutable llallocas = llallocas,
6076
             mutable llself=none[self_vt],
6077
             mutable lliterbody=none[ValueRef],
6078
             llargs=llargs,
6079
             llobjfields=llobjfields,
6080
             lllocals=lllocals,
6081
             llupvars=llupvars,
6082
             mutable lltydescs=Vec.empty[ValueRef](),
6083
             lcx=cx);
6084 6085
}

6086 6087 6088 6089 6090 6091 6092
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args

6093
fn create_llargs_for_fn_args(&@fn_ctxt cx,
6094
                             ast.proto proto,
6095
                             Option.t[tup(TypeRef, ty.t)] ty_self,
6096
                             ty.t ret_ty,
6097
                             &vec[ast.arg] args,
6098
                             &vec[ast.ty_param] ty_params) {
6099 6100

    auto arg_n = 3u;
6101

6102
    alt (ty_self) {
6103
        case (some[tup(TypeRef, ty.t)](?tt)) {
6104 6105
            cx.llself = some[self_vt](rec(v = cx.llenv, t = tt._1));
        }
6106
        case (none[tup(TypeRef, ty.t)]) {
6107
            auto i = 0u;
6108 6109
            for (ast.ty_param tp in ty_params) {
                auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n);
6110
                assert (llarg as int != 0);
6111
                cx.lltydescs += vec(llarg);
6112
                arg_n += 1u;
6113
                i += 1u;
6114
            }
6115
        }
6116 6117
    }

6118
    if (proto == ast.proto_iter) {
6119
        auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n);
6120
        assert (llarg as int != 0);
6121 6122 6123
        cx.lliterbody = some[ValueRef](llarg);
        arg_n += 1u;
    }
6124

6125 6126
    for (ast.arg arg in args) {
        auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n);
6127
        assert (llarg as int != 0);
6128 6129 6130 6131 6132
        cx.llargs.insert(arg.id, llarg);
        arg_n += 1u;
    }
}

6133 6134 6135 6136
// 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.

6137
fn copy_any_self_to_alloca(@fn_ctxt fcx,
6138
                           Option.t[tup(TypeRef, ty.t)] ty_self) {
6139

6140
    auto bcx = llallocas_block_ctxt(fcx);
6141

6142
    alt (fcx.llself) {
6143
        case (some[self_vt](?s_vt)) {
6144
            alt (ty_self) {
6145
                case (some[tup(TypeRef, ty.t)](?tt)) {
6146 6147 6148
                    auto a = alloca(bcx, tt._0);
                    bcx.build.Store(s_vt.v, a);
                    fcx.llself = some[self_vt](rec(v = a, t = s_vt.t));
6149 6150 6151 6152 6153 6154
                }
            }
        }
        case (_) {
        }
    }
6155 6156 6157 6158 6159 6160 6161 6162 6163 6164
}


fn copy_args_to_allocas(@fn_ctxt fcx,
                        vec[ast.arg] args,
                        vec[ty.arg] arg_tys) {

    auto bcx = llallocas_block_ctxt(fcx);

    let uint arg_n = 0u;
6165

6166
    for (ast.arg aarg in args) {
6167
        if (aarg.mode != ast.alias) {
6168
            auto arg_t = type_of_arg(fcx.lcx, arg_tys.(arg_n));
6169 6170 6171
            auto a = alloca(bcx, arg_t);
            auto argval = fcx.llargs.get(aarg.id);
            bcx.build.Store(argval, a);
6172
            // Overwrite the llargs entry for this arg with its alloca.
6173
            fcx.llargs.insert(aarg.id, a);
6174 6175
        }

6176 6177
        arg_n += 1u;
    }
6178 6179

    fcx.llallocas = bcx.llbb;
6180 6181
}

6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196
fn add_cleanups_for_args(@block_ctxt bcx,
                         vec[ast.arg] args,
                         vec[ty.arg] arg_tys) {
    let uint arg_n = 0u;
    for (ast.arg aarg in args) {
        if (aarg.mode != ast.alias) {
            auto argval = bcx.fcx.llargs.get(aarg.id);
            find_scope_cx(bcx).cleanups +=
                vec(clean(bind drop_slot(_, argval, arg_tys.(arg_n).ty)));
        }
        arg_n += 1u;
    }
}


6197 6198 6199 6200 6201
fn is_terminated(@block_ctxt cx) -> bool {
    auto inst = llvm.LLVMGetLastInstruction(cx.llbb);
    ret llvm.LLVMIsATerminatorInst(inst) as int != 0;
}

6202
fn arg_tys_of_fn(@crate_ctxt ccx, ast.ann ann) -> vec[ty.arg] {
6203
    alt (ty.struct(ccx.tcx, ty.ann_to_type(ann))) {
6204
        case (ty.ty_fn(_, ?arg_tys, _)) {
6205 6206 6207 6208 6209 6210
            ret arg_tys;
        }
    }
    fail;
}

6211
fn ret_ty_of_fn_ty(@crate_ctxt ccx, ty.t t) -> ty.t {
6212
    alt (ty.struct(ccx.tcx, t)) {
6213
        case (ty.ty_fn(_, _, ?ret_ty)) {
6214 6215 6216 6217 6218 6219
            ret ret_ty;
        }
    }
    fail;
}

6220

6221 6222
fn ret_ty_of_fn(@crate_ctxt ccx, ast.ann ann) -> ty.t {
    ret ret_ty_of_fn_ty(ccx, ty.ann_to_type(ann));
6223 6224
}

6225
fn populate_fn_ctxt_from_llself(@fn_ctxt fcx, self_vt llself) {
6226
    auto bcx = llallocas_block_ctxt(fcx);
6227

6228
    let vec[ty.t] field_tys = vec();
6229

6230 6231
    for (ast.obj_field f in bcx.fcx.lcx.obj_fields) {
        field_tys += vec(node_ann_type(bcx.fcx.lcx.ccx, f.ann));
6232 6233
    }

6234 6235
    // Synthesize a tuple type for the fields so that GEP_tup_like() can work
    // its magic.
6236
    auto fields_tup_ty = ty.mk_imm_tup(fcx.lcx.ccx.tcx, field_tys);
6237

6238
    auto n_typarams = Vec.len[ast.ty_param](bcx.fcx.lcx.obj_typarams);
6239
    let TypeRef llobj_box_ty = T_obj_ptr(bcx.fcx.lcx.ccx.tn, n_typarams);
6240 6241

    auto box_cell =
6242
        bcx.build.GEP(llself.v,
6243 6244
                      vec(C_int(0),
                          C_int(abi.obj_field_box)));
6245

6246
    auto box_ptr = bcx.build.Load(box_cell);
6247

6248
    box_ptr = bcx.build.PointerCast(box_ptr, llobj_box_ty);
6249

6250
    auto obj_typarams = bcx.build.GEP(box_ptr,
6251 6252 6253
                                     vec(C_int(0),
                                         C_int(abi.box_rc_field_body),
                                         C_int(abi.obj_body_elt_typarams)));
6254

6255 6256 6257
    // 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),
6258
        llsize_of(llvm.LLVMGetElementType(val_ty(obj_typarams))));
6259 6260 6261 6262

    // 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 *.
6263
    if (!ty.type_has_dynamic_size(fcx.lcx.ccx.tcx, fields_tup_ty)) {
6264
        auto llfields_ty = type_of(fcx.lcx.ccx, fields_tup_ty);
6265 6266 6267 6268 6269
        obj_fields = vi2p(bcx, obj_fields, T_ptr(llfields_ty));
    } else {
        obj_fields = vi2p(bcx, obj_fields, T_ptr(T_i8()));
    }

6270 6271

    let int i = 0;
6272

6273
    for (ast.ty_param p in fcx.lcx.obj_typarams) {
6274 6275 6276 6277
        let ValueRef lltyparam = bcx.build.GEP(obj_typarams,
                                               vec(C_int(0),
                                                   C_int(i)));
        lltyparam = bcx.build.Load(lltyparam);
6278
        fcx.lltydescs += vec(lltyparam);
6279 6280 6281 6282
        i += 1;
    }

    i = 0;
6283
    for (ast.obj_field f in fcx.lcx.obj_fields) {
6284
        auto rslt = GEP_tup_like(bcx, fields_tup_ty, obj_fields, vec(0, i));
6285
        bcx = llallocas_block_ctxt(fcx);
6286
        auto llfield = rslt.val;
6287
        fcx.llobjfields.insert(f.id, llfield);
6288 6289
        i += 1;
    }
6290

6291
    fcx.llallocas = bcx.llbb;
6292 6293
}

6294
fn trans_fn(@local_ctxt cx, &ast._fn f, ast.def_id fid,
6295
            Option.t[tup(TypeRef, ty.t)] ty_self,
6296
            &vec[ast.ty_param] ty_params, &ast.ann ann) {
6297
    auto llfndecl = cx.ccx.item_ids.get(fid);
6298

6299
    auto fcx = new_fn_ctxt(cx, llfndecl);
6300
    create_llargs_for_fn_args(fcx, f.proto,
6301
                              ty_self, ret_ty_of_fn(cx.ccx, ann),
6302
                              f.decl.inputs, ty_params);
6303

6304
    copy_any_self_to_alloca(fcx, ty_self);
6305 6306

    alt (fcx.llself) {
6307
        case (some[self_vt](?llself)) {
6308
            populate_fn_ctxt_from_llself(fcx, llself);
6309 6310 6311 6312
        }
        case (_) {
        }
    }
6313

6314 6315
    auto arg_tys = arg_tys_of_fn(fcx.lcx.ccx, ann);
    copy_args_to_allocas(fcx, f.decl.inputs, arg_tys);
6316 6317

    auto bcx = new_top_block_ctxt(fcx);
6318 6319 6320

    add_cleanups_for_args(bcx, f.decl.inputs, arg_tys);

6321 6322
    auto lltop = bcx.llbb;

6323 6324
    auto res = trans_block(bcx, f.body);
    if (!is_terminated(res.bcx)) {
6325 6326
        // FIXME: until LLVM has a unit type, we are moving around
        // C_nil values rather than their void type.
6327
        res.bcx.build.RetVoid();
6328
    }
6329 6330 6331

    // Tie up the llallocas -> lltop edge.
    new_builder(fcx.llallocas).Br(lltop);
6332 6333
}

6334
fn trans_vtbl(@local_ctxt cx,
6335
              TypeRef llself_ty,
6336
              ty.t self_ty,
6337 6338
              &ast._obj ob,
              &vec[ast.ty_param] ty_params) -> ValueRef {
6339 6340 6341 6342 6343 6344 6345 6346 6347
    auto dtor = C_null(T_ptr(T_i8()));
    alt (ob.dtor) {
        case (some[@ast.method](?d)) {
            auto dtor_1 = trans_dtor(cx, llself_ty, self_ty, ty_params, d);
            dtor = llvm.LLVMConstBitCast(dtor_1, val_ty(dtor));
        }
        case (none[@ast.method]) {}
    }
    let vec[ValueRef] methods = vec(dtor);
6348 6349

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

6353
    auto meths = std.Sort.merge_sort[@ast.method](bind meth_lteq(_,_),
6354 6355 6356
                                                  ob.methods);

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

6358
        auto llfnty = T_nil();
6359
        alt (ty.struct(cx.ccx.tcx, node_ann_type(cx.ccx, m.node.ann))) {
6360
            case (ty.ty_fn(?proto, ?inputs, ?output)) {
6361
                llfnty = type_of_fn_full(cx.ccx, proto,
6362
                                         some[TypeRef](llself_ty),
6363
                                         inputs, output,
6364
                                         Vec.len[ast.ty_param](ty_params));
6365 6366 6367
            }
        }

6368
        let @local_ctxt mcx = extend_path(cx, m.node.ident);
6369
        let str s = mangle_name_by_seq(mcx.ccx, mcx.path, "method");
6370 6371 6372 6373
        let ValueRef llfn = decl_internal_fastcall_fn(cx.ccx.llmod, s,
                                                      llfnty);
        cx.ccx.item_ids.insert(m.node.id, llfn);
        cx.ccx.item_symbols.insert(m.node.id, s);
6374

6375
        trans_fn(mcx, m.node.meth, m.node.id,
6376
                 some[tup(TypeRef, ty.t)](tup(llself_ty, self_ty)),
6377
                 ty_params, m.node.ann);
6378
        methods += vec(llfn);
G
Graydon Hoare 已提交
6379
    }
6380
    auto vtbl = C_struct(methods);
6381
    auto vtbl_name = mangle_name_by_seq(cx.ccx, cx.path, "vtbl");
6382
    auto gvar = llvm.LLVMAddGlobal(cx.ccx.llmod, val_ty(vtbl),
6383
                                   Str.buf(vtbl_name));
6384 6385
    llvm.LLVMSetInitializer(gvar, vtbl);
    llvm.LLVMSetGlobalConstant(gvar, True);
6386
    llvm.LLVMSetLinkage(gvar, lib.llvm.LLVMInternalLinkage
6387
                        as llvm.Linkage);
6388
    ret gvar;
G
Graydon Hoare 已提交
6389 6390
}

6391
fn trans_dtor(@local_ctxt cx,
6392
              TypeRef llself_ty,
6393
              ty.t self_ty,
6394 6395 6396
              &vec[ast.ty_param] ty_params,
              &@ast.method dtor) -> ValueRef {

6397
    auto llfnty = T_dtor(cx.ccx, llself_ty);
6398
    let @local_ctxt dcx = extend_path(cx, "drop");
6399
    let str s = mangle_name_by_seq(dcx.ccx, dcx.path, "drop");
6400 6401 6402
    let ValueRef llfn = decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty);
    cx.ccx.item_ids.insert(dtor.node.id, llfn);
    cx.ccx.item_symbols.insert(dtor.node.id, s);
6403 6404

    trans_fn(dcx, dtor.node.meth, dtor.node.id,
6405
             some[tup(TypeRef, ty.t)](tup(llself_ty, self_ty)),
6406 6407 6408 6409 6410
             ty_params, dtor.node.ann);

    ret llfn;
}

6411
fn trans_obj(@local_ctxt cx, &ast._obj ob, ast.def_id oid,
6412
             &vec[ast.ty_param] ty_params, &ast.ann ann) {
6413 6414
    auto ccx = cx.ccx;
    auto llctor_decl = ccx.item_ids.get(oid);
6415

6416
    // Translate obj ctor args to function arguments.
6417 6418
    let vec[ast.arg] fn_args = vec();
    for (ast.obj_field f in ob.fields) {
6419
        fn_args += vec(rec(mode=ast.alias, ty=f.ty, ident=f.ident, id=f.id));
6420 6421
    }

6422
    auto fcx = new_fn_ctxt(cx, llctor_decl);
6423
    create_llargs_for_fn_args(fcx, ast.proto_fn,
6424
                              none[tup(TypeRef, ty.t)],
6425
                              ret_ty_of_fn(ccx, ann),
6426
                              fn_args, ty_params);
6427

6428
    let vec[ty.arg] arg_tys = arg_tys_of_fn(ccx, ann);
6429 6430 6431 6432
    copy_args_to_allocas(fcx, fn_args, arg_tys);

    auto bcx = new_top_block_ctxt(fcx);
    auto lltop = bcx.llbb;
6433

6434
    auto self_ty = ret_ty_of_fn(ccx, ann);
6435
    auto llself_ty = type_of(ccx, self_ty);
6436
    auto pair = bcx.fcx.llretptr;
6437

6438
    auto vtbl = trans_vtbl(cx, llself_ty, self_ty, ob, ty_params);
6439 6440 6441
    auto pair_vtbl = bcx.build.GEP(pair,
                                   vec(C_int(0),
                                       C_int(abi.obj_field_vtbl)));
6442 6443 6444
    auto pair_box = bcx.build.GEP(pair,
                                  vec(C_int(0),
                                      C_int(abi.obj_field_box)));
6445
    bcx.build.Store(vtbl, pair_vtbl);
6446

6447
    let TypeRef llbox_ty = T_opaque_obj_ptr(ccx.tn);
6448

M
Marijn Haverbeke 已提交
6449 6450
    // FIXME we should probably also allocate a box for empty objs that have a
    // dtor, since otherwise they are never dropped, and the dtor never runs
6451 6452
    if (Vec.len[ast.ty_param](ty_params) == 0u &&
        Vec.len[ty.arg](arg_tys) == 0u) {
6453
        // Store null into pair, if no args or typarams.
6454 6455 6456
        bcx.build.Store(C_null(llbox_ty), pair_box);
    } else {
        // Malloc a box for the body and copy args in.
6457
        let vec[ty.t] obj_fields = vec();
6458
        for (ty.arg a in arg_tys) {
6459
            Vec.push[ty.t](obj_fields, a.ty);
6460
        }
6461 6462

        // Synthesize an obj body type.
6463
        auto tydesc_ty = ty.mk_type(ccx.tcx);
6464
        let vec[ty.t] tps = vec();
6465
        for (ast.ty_param tp in ty_params) {
6466
            Vec.push[ty.t](tps, tydesc_ty);
6467 6468
        }

6469 6470 6471
        let ty.t typarams_ty = ty.mk_imm_tup(ccx.tcx, tps);
        let ty.t fields_ty = ty.mk_imm_tup(ccx.tcx, obj_fields);
        let ty.t body_ty = ty.mk_imm_tup(ccx.tcx,
6472
                                          vec(tydesc_ty,
6473 6474
                                              typarams_ty,
                                              fields_ty));
6475
        let ty.t boxed_body_ty = ty.mk_imm_box(ccx.tcx, body_ty);
6476

6477
        // Malloc a box for the body.
6478
        auto box = trans_malloc_boxed(bcx, body_ty);
6479 6480 6481 6482 6483 6484 6485 6486
        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);
6487

6488 6489
        // Store body tydesc.
        auto body_tydesc =
6490 6491 6492
            GEP_tup_like(bcx, body_ty, body.val,
                         vec(0, abi.obj_body_elt_tydesc));
        bcx = body_tydesc.bcx;
6493

6494 6495 6496 6497 6498 6499 6500 6501 6502
        auto body_td = get_tydesc(bcx, body_ty, true);
        auto dtor = C_null(T_ptr(T_glue_fn(ccx.tn)));
        alt (ob.dtor) {
            case (some[@ast.method](?d)) {
                dtor = trans_dtor(cx, llself_ty, self_ty, ty_params, d);
            }
            case (none[@ast.method]) {}
        }

6503 6504
        bcx = body_td.bcx;
        bcx.build.Store(body_td.val, body_tydesc.val);
6505

6506 6507 6508 6509 6510 6511 6512
        // 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) {
6513
            auto typaram = bcx.fcx.lltydescs.(i);
6514 6515 6516 6517 6518 6519 6520
            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;
        }

6521 6522
        // Copy args into body fields.
        auto body_fields =
6523 6524 6525
            GEP_tup_like(bcx, body_ty, body.val,
                         vec(0, abi.obj_body_elt_fields));
        bcx = body_fields.bcx;
6526

6527
        i = 0;
6528
        for (ast.obj_field f in ob.fields) {
6529
            auto arg = bcx.fcx.llargs.get(f.id);
6530
            arg = load_if_immediate(bcx, arg, arg_tys.(i).ty);
6531 6532 6533 6534
            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;
6535 6536 6537
            i += 1;
        }
        // Store box ptr in outer pair.
6538
        auto p = bcx.build.PointerCast(box.val, llbox_ty);
6539
        bcx.build.Store(p, pair_box);
6540
    }
6541
    bcx.build.RetVoid();
6542 6543 6544

    // Tie up the llallocas -> lltop edge.
    new_builder(fcx.llallocas).Br(lltop);
6545 6546
}

6547
fn trans_tag_variant(@local_ctxt cx, ast.def_id tag_id,
6548 6549
                     &ast.variant variant, int index,
                     &vec[ast.ty_param] ty_params) {
6550
    if (Vec.len[ast.variant_arg](variant.node.args) == 0u) {
6551 6552 6553
        ret;    // nullary constructors are just constants
    }

6554 6555 6556
    // Translate variant arguments to function arguments.
    let vec[ast.arg] fn_args = vec();
    auto i = 0u;
6557
    for (ast.variant_arg varg in variant.node.args) {
6558 6559
        fn_args += vec(rec(mode=ast.alias,
                           ty=varg.ty,
6560
                           ident="arg" + UInt.to_str(i, 10u),
6561 6562 6563
                           id=varg.id));
    }

6564
    assert (cx.ccx.item_ids.contains_key(variant.node.id));
6565
    let ValueRef llfndecl = cx.ccx.item_ids.get(variant.node.id);
6566

6567
    auto fcx = new_fn_ctxt(cx, llfndecl);
6568

6569
    create_llargs_for_fn_args(fcx, ast.proto_fn,
6570
                              none[tup(TypeRef, ty.t)],
6571
                              ret_ty_of_fn(cx.ccx, variant.node.ann),
6572
                              fn_args, ty_params);
6573

6574
    let vec[ty.t] ty_param_substs = vec();
6575
    i = 0u;
6576
    for (ast.ty_param tp in ty_params) {
6577
        ty_param_substs += vec(ty.mk_param(cx.ccx.tcx, i));
6578
        i += 1u;
6579 6580
    }

6581
    auto arg_tys = arg_tys_of_fn(cx.ccx, variant.node.ann);
6582 6583 6584 6585
    copy_args_to_allocas(fcx, fn_args, arg_tys);

    auto bcx = new_top_block_ctxt(fcx);
    auto lltop = bcx.llbb;
6586

6587 6588
    // Cast the tag to a type we can GEP into.
    auto lltagptr = bcx.build.PointerCast(fcx.llretptr,
6589
                                          T_opaque_tag_ptr(fcx.lcx.ccx.tn));
6590 6591

    auto lldiscrimptr = bcx.build.GEP(lltagptr,
6592
                                      vec(C_int(0), C_int(0)));
6593 6594
    bcx.build.Store(C_int(index), lldiscrimptr);

6595
    auto llblobptr = bcx.build.GEP(lltagptr,
6596
                                   vec(C_int(0), C_int(1)));
6597 6598

    i = 0u;
6599 6600
    for (ast.variant_arg va in variant.node.args) {
        auto rslt = GEP_tag(bcx, llblobptr, tag_id, variant.node.id,
6601
                            ty_param_substs, i as int);
6602 6603
        bcx = rslt.bcx;
        auto lldestptr = rslt.val;
6604

6605 6606 6607 6608
        // 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),
6609
            val_ty(lldestptr));
6610

6611 6612
        auto arg_ty = arg_tys.(i).ty;
        auto llargval;
6613 6614
        if (ty.type_is_structural(cx.ccx.tcx, arg_ty) ||
                ty.type_has_dynamic_size(cx.ccx.tcx, arg_ty)) {
6615 6616 6617 6618 6619 6620 6621 6622
            llargval = llargptr;
        } else {
            llargval = bcx.build.Load(llargptr);
        }

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

6623 6624 6625 6626
        i += 1u;
    }

    bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
6627
    bcx.build.RetVoid();
6628 6629 6630

    // Tie up the llallocas -> lltop edge.
    new_builder(fcx.llallocas).Br(lltop);
6631 6632
}

6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648
// 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);
6649 6650 6651 6652 6653 6654

    // 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);
6655 6656
}

6657
fn trans_item(@local_ctxt cx, &ast.item item) {
6658
    alt (item.node) {
6659
        case (ast.item_fn(?name, ?f, ?tps, ?fid, ?ann)) {
6660
            auto sub_cx = extend_path(cx, name);
6661
            trans_fn(sub_cx, f, fid, none[tup(TypeRef, ty.t)], tps, ann);
6662
        }
6663
        case (ast.item_obj(?name, ?ob, ?tps, ?oid, ?ann)) {
6664 6665 6666
            auto sub_cx = @rec(obj_typarams=tps,
                               obj_fields=ob.fields with
                               *extend_path(cx, name));
6667
            trans_obj(sub_cx, ob, oid.ctor, tps, ann);
6668
        }
6669
        case (ast.item_mod(?name, ?m, _)) {
6670 6671 6672
            auto sub_cx = @rec(path = cx.path + vec(name),
                               module_path = cx.module_path + vec(name)
                               with *cx);
6673
            trans_mod(sub_cx, m);
6674
        }
6675
        case (ast.item_tag(?name, ?variants, ?tps, ?tag_id, _)) {
6676
            auto sub_cx = extend_path(cx, name);
6677
            auto i = 0;
6678
            for (ast.variant variant in variants) {
6679
                trans_tag_variant(sub_cx, tag_id, variant, i, tps);
6680
                i += 1;
6681 6682
            }
        }
6683
        case (ast.item_const(?name, _, ?expr, ?cid, ?ann)) {
6684
            trans_const(cx.ccx, expr, cid, ann);
6685
        }
6686
        case (_) { /* fall through */ }
6687 6688 6689
    }
}

6690
fn trans_mod(@local_ctxt cx, &ast._mod m) {
6691 6692
    for (@ast.item item in m.items) {
        trans_item(cx, *item);
6693 6694 6695
    }
}

6696 6697 6698 6699
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,
6700
                                   Vec.buf[TypeRef](pair_tys));
6701 6702 6703
    ret llvm.LLVMGetElementType(pair_tys.(0));
}

6704 6705
fn decl_fn_and_pair(@crate_ctxt ccx,
                    vec[str] path,
6706
                    str flav,
6707
                    vec[ast.ty_param] ty_params,
6708 6709 6710
                    &ast.ann ann,
                    ast.def_id id) {

6711 6712
    auto llfty;
    auto llpairty;
6713
    alt (ty.struct(ccx.tcx, node_ann_type(ccx, ann))) {
6714
        case (ty.ty_fn(?proto, ?inputs, ?output)) {
6715
            llfty = type_of_fn(ccx, proto, inputs, output,
6716
                               Vec.len[ast.ty_param](ty_params));
6717
            llpairty = T_fn_pair(ccx.tn, llfty);
6718 6719
        }
        case (_) {
6720
            ccx.sess.bug("decl_fn_and_pair(): fn item doesn't have fn type!");
6721 6722 6723
            fail;
        }
    }
6724 6725

    // Declare the function itself.
6726
    let str s = mangle_name_by_seq(ccx, path, flav);
6727
    let ValueRef llfn = decl_internal_fastcall_fn(ccx.llmod, s, llfty);
6728 6729

    // Declare the global constant pair that points to it.
6730
    let str ps = mangle_name_by_type(ccx, path, node_ann_type(ccx, ann));
6731

6732
    register_fn_pair(ccx, ps, llpairty, llfn, id);
6733 6734 6735 6736
}

fn register_fn_pair(@crate_ctxt cx, str ps, TypeRef llpairty, ValueRef llfn,
                    ast.def_id id) {
6737
    let ValueRef gvar = llvm.LLVMAddGlobal(cx.llmod, llpairty,
6738
                                           Str.buf(ps));
6739
    auto pair = C_struct(vec(llfn,
6740
                             C_null(T_opaque_closure_ptr(cx.tn))));
6741 6742 6743

    llvm.LLVMSetInitializer(gvar, pair);
    llvm.LLVMSetGlobalConstant(gvar, True);
6744 6745 6746
    llvm.LLVMSetVisibility(gvar,
                           lib.llvm.LLVMProtectedVisibility
                           as llvm.Visibility);
6747 6748

    cx.item_ids.insert(id, llfn);
P
Patrick Walton 已提交
6749
    cx.item_symbols.insert(id, ps);
6750 6751 6752
    cx.fn_pairs.insert(id, gvar);
}

6753 6754 6755 6756 6757 6758 6759 6760 6761 6762
// 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;
        }
6763
        case (ast.native_item_fn(_, _, _, ?tps, _, _)) {
6764
            count = Vec.len[ast.ty_param](tps);
6765 6766 6767 6768 6769
        }
    }
    ret count;
}

6770
fn native_fn_wrapper_type(@crate_ctxt cx, uint ty_param_count, ty.t x)
6771
        -> TypeRef {
6772
    alt (ty.struct(cx.tcx, x)) {
6773
        case (ty.ty_native_fn(?abi, ?args, ?out)) {
6774
            ret type_of_fn(cx, ast.proto_fn, args, out, ty_param_count);
6775 6776 6777 6778 6779
        }
    }
    fail;
}

6780 6781
fn decl_native_fn_and_pair(@crate_ctxt ccx,
                           vec[str] path,
6782 6783 6784
                           str name,
                           &ast.ann ann,
                           ast.def_id id) {
6785
    auto num_ty_param = native_fn_ty_param_count(ccx, id);
6786

6787
    // Declare the wrapper.
6788 6789
    auto t = node_ann_type(ccx, ann);
    auto wrapper_type = native_fn_wrapper_type(ccx, num_ty_param, t);
6790
    let str s = mangle_name_by_seq(ccx, path, "wrapper");
6791 6792
    let ValueRef wrapper_fn = decl_internal_fastcall_fn(ccx.llmod, s,
                                                        wrapper_type);
6793

6794
    // Declare the global constant pair that points to it.
6795
    auto wrapper_pair_type = T_fn_pair(ccx.tn, wrapper_type);
6796
    let str ps = mangle_name_by_type(ccx, path, node_ann_type(ccx, ann));
6797

6798
    register_fn_pair(ccx, ps, wrapper_pair_type, wrapper_fn, id);
6799

6800
    // Build the wrapper.
6801
    auto fcx = new_fn_ctxt(new_local_ctxt(ccx), wrapper_fn);
6802
    auto bcx = new_top_block_ctxt(fcx);
6803
    auto lltop = bcx.llbb;
6804

6805
    // Declare the function itself.
6806 6807
    auto item = ccx.native_items.get(id);
    auto fn_type = node_ann_type(ccx, ann);  // NB: has no type params
6808

6809
    auto abi = ty.ty_fn_abi(ccx.tcx, fn_type);
6810
    auto llfnty = type_of_native_fn(ccx, abi,
6811 6812
        ty.ty_fn_args(ccx.tcx, fn_type),
        ty.ty_fn_ret(ccx.tcx, fn_type), num_ty_param);
6813

6814 6815 6816 6817 6818
    // FIXME: If the returned type is not nil, then we assume it's 32 bits
    // wide. This is obviously wildly unsafe. We should have a better FFI
    // that allows types of different sizes to be returned.
    auto rty_is_nil = ty.type_is_nil(ccx.tcx, ty.ty_fn_ret(ccx.tcx, fn_type));

6819
    auto pass_task;
6820
    auto cast_to_i32;
6821 6822
    alt (abi) {
        case (ast.native_abi_rust) {
6823
            pass_task = true;
6824
            cast_to_i32 = true;
6825
        }
6826 6827
        case (ast.native_abi_rust_intrinsic) {
            pass_task = true;
6828
            cast_to_i32 = false;
6829
        }
6830
        case (ast.native_abi_cdecl) {
6831
            pass_task = false;
6832
            cast_to_i32 = true;
6833
        }
6834 6835
        case (ast.native_abi_llvm) {
            pass_task = false;
6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850
            cast_to_i32 = false;
        }
    }

    auto lltaskptr;
    if (cast_to_i32) {
        lltaskptr = vp2i(bcx, fcx.lltaskptr);
    } else {
        lltaskptr = fcx.lltaskptr;
    }

    let vec[ValueRef] call_args = vec();
    if (pass_task) { call_args += vec(lltaskptr); }

    auto arg_n = 3u;
6851
    for each (uint i in UInt.range(0u, num_ty_param)) {
6852 6853 6854 6855 6856 6857 6858 6859
        auto llarg = llvm.LLVMGetParam(fcx.llfn, arg_n);
        fcx.lltydescs += vec(llarg);
        assert (llarg as int != 0);

        if (cast_to_i32) {
            call_args += vec(vp2i(bcx, llarg));
        } else {
            call_args += vec(llarg);
6860
        }
6861 6862

        arg_n += 1u;
6863
    }
6864

6865 6866 6867
    fn convert_arg_to_i32(@block_ctxt cx,
                          ValueRef v,
                          ty.t t,
6868 6869
                          ty.mode mode) -> ValueRef {
        if (mode == ty.mo_val) {
6870 6871 6872 6873 6874
            if (ty.type_is_integral(cx.fcx.lcx.ccx.tcx, t)) {
                auto lldsttype = T_int();
                auto llsrctype = type_of(cx.fcx.lcx.ccx, t);
                if (llvm.LLVMGetIntTypeWidth(lldsttype) >
                    llvm.LLVMGetIntTypeWidth(llsrctype)) {
6875
                    ret cx.build.ZExtOrBitCast(v, T_int());
6876
                }
6877
                ret cx.build.TruncOrBitCast(v, T_int());
6878 6879
            }
            if (ty.type_is_fp(cx.fcx.lcx.ccx.tcx, t)) {
6880
                ret cx.build.FPToSI(v, T_int());
6881 6882
            }
        }
6883

6884
        ret vp2i(cx, v);
6885 6886
    }

6887 6888 6889
    fn trans_simple_native_abi(@block_ctxt bcx,
                               str name,
                               &mutable vec[ValueRef] call_args,
6890 6891
                               ty.t fn_type,
                               uint first_arg_n) -> tup(ValueRef, ValueRef) {
6892
        let vec[TypeRef] call_arg_tys = vec();
6893 6894
        for (ValueRef arg in call_args) {
            call_arg_tys += vec(val_ty(arg));
6895
        }
6896

6897 6898 6899 6900
        auto llnativefnty =
            T_fn(call_arg_tys,
                 type_of(bcx.fcx.lcx.ccx,
                         ty.ty_fn_ret(bcx.fcx.lcx.ccx.tcx, fn_type)));
6901

6902 6903 6904 6905 6906
        auto llnativefn = get_extern_fn(bcx.fcx.lcx.ccx.externs,
                                        bcx.fcx.lcx.ccx.llmod,
                                        name,
                                        lib.llvm.LLVMCCallConv,
                                        llnativefnty);
G
Graydon Hoare 已提交
6907

6908 6909 6910 6911
        auto r = bcx.build.Call(llnativefn, call_args);
        auto rptr = bcx.fcx.llretptr;
        ret tup(r, rptr);
    }
G
Graydon Hoare 已提交
6912

6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928
    auto args = ty.ty_fn_args(ccx.tcx, fn_type);

    // Build up the list of arguments.
    let vec[tup(ValueRef, ty.t)] drop_args = vec();
    auto i = arg_n;
    for (ty.arg arg in args) {
        auto llarg = llvm.LLVMGetParam(fcx.llfn, i);
        assert (llarg as int != 0);

        if (cast_to_i32) {
            auto llarg_i32 = convert_arg_to_i32(bcx, llarg, arg.ty, arg.mode);
            call_args += vec(llarg_i32);
        } else {
            call_args += vec(llarg);
        }

6929
        if (arg.mode == ty.mo_val) {
6930 6931 6932 6933 6934 6935
            drop_args += vec(tup(llarg, arg.ty));
        }

        i += 1u;
    }

6936 6937 6938 6939
    auto r;
    auto rptr;
    alt (abi) {
        case (ast.native_abi_llvm) {
6940 6941
            auto result = trans_simple_native_abi(bcx, name, call_args,
                                                  fn_type, arg_n);
6942 6943 6944
            r = result._0; rptr = result._1;
        }
        case (ast.native_abi_rust_intrinsic) {
6945 6946 6947
            auto external_name = "rust_intrinsic_" + name;
            auto result = trans_simple_native_abi(bcx, external_name,
                                                  call_args, fn_type, arg_n);
6948
            r = result._0; rptr = result._1;
6949
        }
6950 6951 6952 6953 6954 6955
        case (_) {
            r = trans_native_call(bcx.build, ccx.glues, lltaskptr,
                                  ccx.externs, ccx.tn, ccx.llmod, name,
                                  pass_task, call_args);
            rptr = bcx.build.BitCast(fcx.llretptr, T_ptr(T_i32()));

G
Graydon Hoare 已提交
6956
        }
6957
    }
6958

6959 6960 6961 6962 6963
    // We don't store the return value if it's nil, to avoid stomping on a nil
    // pointer. This is the only concession made to non-i32 return values. See
    // the FIXME above.
    if (!rty_is_nil) { bcx.build.Store(r, rptr); }

6964 6965 6966 6967
    for (tup(ValueRef, ty.t) d in drop_args) {
        bcx = drop_ty(bcx, d._0, d._1).bcx;
    }

6968
    bcx.build.RetVoid();
6969 6970 6971

    // Tie up the llallocas -> lltop edge.
    new_builder(fcx.llallocas).Br(lltop);
6972 6973
}

6974
type walk_ctxt = rec(mutable vec[str] path);
6975 6976 6977 6978
fn new_walk_ctxt() -> @walk_ctxt {
    let vec[str] path = vec();
    ret @rec(mutable path=path);
}
6979

6980
fn enter_item(@walk_ctxt cx, &@ast.item item) {
6981 6982
    alt (item.node) {
        case (ast.item_fn(?name, _, _, _, _)) {
6983
            Vec.push[str](cx.path, name);
6984
        }
6985
        case (ast.item_obj(?name, _, _, _, _)) {
6986
            Vec.push[str](cx.path, name);
6987 6988
        }
        case (ast.item_mod(?name, _, _)) {
6989
            Vec.push[str](cx.path, name);
6990
        }
6991
        case (_) { }
6992 6993
    }
}
6994

6995
fn leave_item(@walk_ctxt cx, &@ast.item item) {
6996 6997
    alt (item.node) {
        case (ast.item_fn(_, _, _, _, _)) {
6998
            Vec.pop[str](cx.path);
6999
        }
7000
        case (ast.item_obj(_, _, _, _, _)) {
7001
            Vec.pop[str](cx.path);
7002
        }
7003
        case (ast.item_mod(_, _, _)) {
7004
            Vec.pop[str](cx.path);
7005
        }
7006 7007 7008 7009
        case (_) { }
    }
}

7010
fn collect_native_item(@crate_ctxt ccx, @walk_ctxt wcx, &@ast.native_item i) {
7011 7012 7013 7014 7015 7016
    alt (i.node) {
        case (ast.native_item_fn(?name, _, _, _, ?fid, ?ann)) {
            ccx.native_items.insert(fid, i);
            if (!ccx.obj_methods.contains_key(fid)) {
                decl_native_fn_and_pair(ccx, wcx.path, name, ann, fid);
            }
7017
        }
7018 7019
        case (ast.native_item_ty(_, ?tid)) {
            ccx.native_items.insert(tid, i);
7020 7021 7022
        }
    }
}
7023

7024
fn collect_item_1(@crate_ctxt ccx, @walk_ctxt wcx, &@ast.item i) {
7025 7026
    enter_item(wcx, i);

7027
    alt (i.node) {
7028
        case (ast.item_const(?name, _, _, ?cid, ?ann)) {
7029 7030
            auto typ = node_ann_type(ccx, ann);
            auto g = llvm.LLVMAddGlobal(ccx.llmod, type_of(ccx, typ),
7031
                                        Str.buf(ccx.names.next(name)));
7032
            llvm.LLVMSetLinkage(g, lib.llvm.LLVMInternalLinkage
7033
                                as llvm.Linkage);
7034 7035
            ccx.items.insert(cid, i);
            ccx.consts.insert(cid, g);
7036 7037
        }
        case (ast.item_mod(?name, ?m, ?mid)) {
7038
            ccx.items.insert(mid, i);
7039
        }
7040
        case (ast.item_ty(_, _, _, ?did, _)) {
7041
            ccx.items.insert(did, i);
7042
        }
7043
        case (ast.item_tag(?name, ?variants, ?tps, ?tag_id, _)) {
7044
            ccx.items.insert(tag_id, i);
7045
        }
7046
        case (_) {}
7047 7048 7049
    }
}

7050
fn collect_item_2(@crate_ctxt ccx, @walk_ctxt wcx, &@ast.item i) {
7051 7052
    enter_item(wcx, i);

7053
    alt (i.node) {
7054
        case (ast.item_fn(?name, ?f, ?tps, ?fid, ?ann)) {
7055 7056 7057
            ccx.items.insert(fid, i);
            if (!ccx.obj_methods.contains_key(fid)) {
                decl_fn_and_pair(ccx, wcx.path, "fn", tps, ann, fid);
7058
            }
7059
        }
7060
        case (ast.item_obj(?name, ?ob, ?tps, ?oid, ?ann)) {
7061 7062
            ccx.items.insert(oid.ctor, i);
            decl_fn_and_pair(ccx, wcx.path, "obj_ctor", tps, ann, oid.ctor);
7063
            for (@ast.method m in ob.methods) {
7064
                ccx.obj_methods.insert(m.node.id, ());
7065
            }
7066
        }
7067
        case (_) {}
7068 7069 7070
    }
}

7071
fn collect_items(@crate_ctxt ccx, @ast.crate crate) {
7072
    auto wcx = new_walk_ctxt();
7073
    auto visitor0 = walk.default_visitor();
7074
    auto visitor1 = rec(visit_native_item_pre =
7075 7076 7077 7078 7079 7080 7081 7082 7083
                          bind collect_native_item(ccx, wcx, _),
                        visit_item_pre = bind collect_item_1(ccx, wcx, _),
                        visit_item_post = bind leave_item(wcx, _)
                        with visitor0);
    auto visitor2 = rec(visit_item_pre = bind collect_item_2(ccx, wcx, _),
                        visit_item_post = bind leave_item(wcx, _)
                        with visitor0);
    walk.walk_crate(visitor1, *crate);
    walk.walk_crate(visitor2, *crate);
7084 7085
}

7086
fn collect_tag_ctor(@crate_ctxt ccx, @walk_ctxt wcx, &@ast.item i) {
7087
    enter_item(wcx, i);
7088 7089

    alt (i.node) {
7090
        case (ast.item_tag(_, ?variants, ?tps, _, _)) {
7091
            for (ast.variant variant in variants) {
7092
                if (Vec.len[ast.variant_arg](variant.node.args) != 0u) {
7093
                    decl_fn_and_pair(ccx, wcx.path + vec(variant.node.name),
7094 7095
                                     "tag", tps, variant.node.ann,
                                     variant.node.id);
7096 7097 7098 7099 7100 7101 7102 7103
                }
            }
        }

        case (_) { /* fall through */ }
    }
}

7104 7105 7106 7107 7108 7109
fn collect_tag_ctors(@crate_ctxt ccx, @ast.crate crate) {
    auto wcx = new_walk_ctxt();
    auto visitor = rec(visit_item_pre = bind collect_tag_ctor(ccx, wcx, _),
                       visit_item_post = bind leave_item(wcx, _)
                       with walk.default_visitor());
    walk.walk_crate(visitor, *crate);
7110 7111
}

7112 7113
// The constant translation pass.

7114
fn trans_constant(@crate_ctxt ccx, @walk_ctxt wcx, &@ast.item it) {
7115
    enter_item(wcx, it);
7116

7117
    alt (it.node) {
7118
        case (ast.item_tag(?ident, ?variants, _, ?tag_id, _)) {
7119
            auto i = 0u;
7120
            auto n_variants = Vec.len[ast.variant](variants);
7121 7122
            while (i < n_variants) {
                auto variant = variants.(i);
7123 7124 7125

                auto discrim_val = C_int(i as int);

7126
                auto s = mangle_name_by_seq(ccx, wcx.path,
7127 7128
                                            #fmt("_rust_tag_discrim_%s_%u",
                                                 ident, i));
7129
                auto discrim_gvar = llvm.LLVMAddGlobal(ccx.llmod, T_int(),
7130
                                                       Str.buf(s));
7131 7132 7133 7134

                llvm.LLVMSetInitializer(discrim_gvar, discrim_val);
                llvm.LLVMSetGlobalConstant(discrim_gvar, True);

7135 7136
                ccx.discrims.insert(variant.node.id, discrim_gvar);
                ccx.discrim_symbols.insert(variant.node.id, s);
7137 7138 7139 7140

                i += 1u;
            }
        }
7141 7142 7143 7144 7145

        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);
7146 7147 7148 7149
            ccx.item_ids.insert(cid, v);
            auto s = mangle_name_by_type(ccx, wcx.path + vec(name),
                                         node_ann_type(ccx, ann));
            ccx.item_symbols.insert(cid, s);
7150 7151
        }

7152
        case (_) {}
7153 7154 7155
    }
}

7156 7157 7158 7159 7160 7161
fn trans_constants(@crate_ctxt ccx, @ast.crate crate) {
    auto wcx = new_walk_ctxt();
    auto visitor = rec(visit_item_pre = bind trans_constant(ccx, wcx, _),
                       visit_item_post = bind leave_item(wcx, _)
                       with walk.default_visitor());
    walk.walk_crate(visitor, *crate);
7162 7163
}

7164 7165 7166 7167 7168 7169 7170 7171 7172 7173

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

7174 7175 7176 7177
fn p2i(ValueRef v) -> ValueRef {
    ret llvm.LLVMConstPtrToInt(v, T_int());
}

7178 7179 7180 7181
fn i2p(ValueRef v, TypeRef t) -> ValueRef {
    ret llvm.LLVMConstIntToPtr(v, t);
}

7182
fn trans_exit_task_glue(@glue_fns glues,
7183
                        &hashmap[str, ValueRef] externs,
7184
                        type_names tn, ModuleRef llmod) {
7185 7186 7187
    let vec[TypeRef] T_args = vec();
    let vec[ValueRef] V_args = vec();

7188
    auto llfn = glues.exit_task_glue;
7189

7190
    auto entrybb = llvm.LLVMAppendBasicBlock(llfn, Str.buf("entry"));
7191
    auto build = new_builder(entrybb);
7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207

    let ValueRef arg1 = llvm.LLVMGetParam(llfn, 0u);
    let ValueRef arg2 = llvm.LLVMGetParam(llfn, 1u);
    let ValueRef arg3 = llvm.LLVMGetParam(llfn, 2u);
    let ValueRef arg4 = llvm.LLVMGetParam(llfn, 3u);
    let ValueRef arg5 = llvm.LLVMGetParam(llfn, 4u);

    auto main_type = T_fn(vec(T_int(), T_int(), T_int(), T_int()), T_void());

    auto fun = build.IntToPtr(arg1, T_ptr(main_type));
    auto call_args = vec(arg2, arg3, arg4, arg5);
    build.FastCall(fun, call_args);

    trans_native_call(build, glues, arg3,
                      externs, tn, llmod, "upcall_exit", true, vec(arg3));

7208
    build.RetVoid();
7209 7210
}

7211
fn create_typedefs(@crate_ctxt cx) {
7212 7213 7214
    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));
7215 7216
}

7217
fn create_crate_constant(ValueRef crate_ptr, @glue_fns glues) {
7218

7219
    let ValueRef crate_addr = p2i(crate_ptr);
7220 7221

    let ValueRef activate_glue_off =
7222
        llvm.LLVMConstSub(p2i(glues.activate_glue), crate_addr);
7223 7224

    let ValueRef yield_glue_off =
7225
        llvm.LLVMConstSub(p2i(glues.yield_glue), crate_addr);
7226

7227
    let ValueRef exit_task_glue_off =
7228
        llvm.LLVMConstSub(p2i(glues.exit_task_glue), crate_addr);
7229 7230 7231

    let ValueRef crate_val =
        C_struct(vec(C_null(T_int()),     // ptrdiff_t image_base_off
7232
                     p2i(crate_ptr),      // uintptr_t self_addr
7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243
                     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
7244
                     C_null(T_int()),     // int n_libs
7245
                     C_int(abi.abi_x86_rustc_fastcall) // uintptr_t abi_tag
7246 7247
                     ));

7248
    llvm.LLVMSetInitializer(crate_ptr, crate_val);
7249 7250
}

7251 7252 7253 7254
fn find_main_fn(@crate_ctxt cx) -> ValueRef {
    auto e = sep() + "main";
    let ValueRef v = C_nil();
    let uint n = 0u;
7255
    for each (@tup(ast.def_id, str) i in cx.item_symbols.items()) {
7256
        if (Str.ends_with(i._1, e)) {
7257
            n += 1u;
7258
            v = cx.item_ids.get(i._0);
7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274
        }
    }
    alt (n) {
        case (0u) {
            cx.sess.err("main fn not found");
        }
        case (1u) {
            ret v;
        }
        case (_) {
            cx.sess.err("multiple main fns found");
        }
    }
    fail;
}

7275
fn trans_main_fn(@local_ctxt cx, ValueRef llcrate, ValueRef crate_map) {
7276
    auto T_main_args = vec(T_int(), T_int());
7277
    auto T_rust_start_args = vec(T_int(), T_int(), T_int(), T_int(), T_int());
7278

7279
    auto main_name;
7280
    if (Str.eq(std.OS.target_os(), "win32")) {
7281 7282 7283 7284 7285
        main_name = "WinMain@16";
    } else {
        main_name = "main";
    }

7286
    auto llmain =
7287
        decl_cdecl_fn(cx.ccx.llmod, main_name, T_fn(T_main_args, T_int()));
7288

7289
    auto llrust_start = decl_cdecl_fn(cx.ccx.llmod, "rust_start",
7290
                                      T_fn(T_rust_start_args, T_int()));
7291 7292 7293

    auto llargc = llvm.LLVMGetParam(llmain, 0u);
    auto llargv = llvm.LLVMGetParam(llmain, 1u);
7294
    auto llrust_main = find_main_fn(cx.ccx);
7295 7296 7297 7298 7299 7300 7301 7302 7303 7304

    //
    // Emit the moral equivalent of:
    //
    // main(int argc, char **argv) {
    //     rust_start(&_rust.main, &crate, argc, argv);
    // }
    //

    let BasicBlockRef llbb =
7305
        llvm.LLVMAppendBasicBlock(llmain, Str.buf(""));
7306
    auto b = new_builder(llbb);
7307

7308 7309
    auto start_args = vec(p2i(llrust_main), p2i(llcrate), llargc, llargv,
                          p2i(crate_map));
7310 7311 7312 7313

    b.Ret(b.Call(llrust_start, start_args));
}

7314 7315
fn declare_intrinsics(ModuleRef llmod) -> hashmap[str,ValueRef] {

7316 7317 7318 7319 7320 7321 7322 7323 7324 7325
    let vec[TypeRef] T_memcpy32_args = vec(T_ptr(T_i8()), T_ptr(T_i8()),
                                           T_i32(), T_i32(), T_i1());
    let vec[TypeRef] T_memcpy64_args = vec(T_ptr(T_i8()), T_ptr(T_i8()),
                                           T_i64(), T_i32(), T_i1());

    let vec[TypeRef] T_memset32_args = vec(T_ptr(T_i8()), T_i8(),
                                           T_i32(), T_i32(), T_i1());
    let vec[TypeRef] T_memset64_args = vec(T_ptr(T_i8()), T_i8(),
                                           T_i64(), T_i32(), T_i1());

7326
    let vec[TypeRef] T_trap_args = vec();
7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337

    auto memcpy32 = decl_cdecl_fn(llmod, "llvm.memcpy.p0i8.p0i8.i32",
                                  T_fn(T_memcpy32_args, T_void()));
    auto memcpy64 = decl_cdecl_fn(llmod, "llvm.memcpy.p0i8.p0i8.i64",
                                  T_fn(T_memcpy64_args, T_void()));

    auto memset32 = decl_cdecl_fn(llmod, "llvm.memset.p0i8.i32",
                                  T_fn(T_memset32_args, T_void()));
    auto memset64 = decl_cdecl_fn(llmod, "llvm.memset.p0i8.i64",
                                  T_fn(T_memset64_args, T_void()));

7338 7339 7340 7341
    auto trap = decl_cdecl_fn(llmod, "llvm.trap",
                              T_fn(T_trap_args, T_void()));

    auto intrinsics = new_str_hash[ValueRef]();
7342 7343 7344 7345
    intrinsics.insert("llvm.memcpy.p0i8.p0i8.i32", memcpy32);
    intrinsics.insert("llvm.memcpy.p0i8.p0i8.i64", memcpy64);
    intrinsics.insert("llvm.memset.p0i8.i32", memset32);
    intrinsics.insert("llvm.memset.p0i8.i64", memset64);
7346 7347
    intrinsics.insert("llvm.trap", trap);
    ret intrinsics;
7348 7349
}

7350 7351

fn trace_str(@block_ctxt cx, str s) {
7352 7353
    trans_upcall(cx, "upcall_trace_str", vec(p2i(C_cstr(cx.fcx.lcx.ccx, s))),
                 false);
7354 7355 7356
}

fn trace_word(@block_ctxt cx, ValueRef v) {
7357
    trans_upcall(cx, "upcall_trace_word", vec(v), false);
7358 7359 7360 7361 7362 7363 7364 7365
}

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();
7366
    bcx.build.Call(bcx.fcx.lcx.ccx.intrinsics.get("llvm.trap"), v);
7367
}
7368

7369
fn decl_no_op_type_glue(ModuleRef llmod, type_names tn) -> ValueRef {
7370
    auto ty = T_fn(vec(T_taskptr(tn), T_ptr(T_i8())), T_void());
7371 7372 7373 7374
    ret decl_fastcall_fn(llmod, abi.no_op_type_glue_name(), ty);
}

fn make_no_op_type_glue(ValueRef fun) {
7375
    auto bb_name = Str.buf("_rust_no_op_type_glue_bb");
7376
    auto llbb = llvm.LLVMAppendBasicBlock(fun, bb_name);
7377
    new_builder(llbb).RetVoid();
7378 7379
}

7380
fn make_vec_append_glue(ModuleRef llmod, type_names tn) -> ValueRef {
7381
    /*
7382
     * Args to vec_append_glue:
7383 7384 7385 7386 7387 7388 7389 7390 7391 7392
     *
     *   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.
     *
7393
     *   3. Dst vec ptr (i.e. ptr to ptr to rust_vec).
7394 7395
     *
     *   4. Src vec (i.e. ptr to rust_vec).
7396
     *
7397
     *   5. Flag indicating whether to skip trailing null on dst.
7398 7399 7400 7401 7402 7403
     *
     */

    auto ty = T_fn(vec(T_taskptr(tn),
                       T_ptr(T_tydesc(tn)),
                       T_ptr(T_tydesc(tn)),
7404 7405 7406
                       T_ptr(T_opaque_vec_ptr()),
                       T_opaque_vec_ptr(), T_bool()),
                   T_void());
7407

7408
    auto llfn = decl_fastcall_fn(llmod, abi.vec_append_glue_name(), ty);
7409 7410 7411
    ret llfn;
}

7412 7413 7414 7415 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450

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

7451
fn trans_vec_append_glue(@local_ctxt cx) {
7452

7453
    auto llfn = cx.ccx.glues.vec_append_glue;
7454 7455 7456 7457

    let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 0u);
    let ValueRef llvec_tydesc = llvm.LLVMGetParam(llfn, 1u);
    let ValueRef llelt_tydesc = llvm.LLVMGetParam(llfn, 2u);
7458 7459 7460
    let ValueRef lldst_vec_ptr = llvm.LLVMGetParam(llfn, 3u);
    let ValueRef llsrc_vec = llvm.LLVMGetParam(llfn, 4u);
    let ValueRef llskipnull = llvm.LLVMGetParam(llfn, 5u);
7461

7462
    let BasicBlockRef llallocas =
7463
        llvm.LLVMAppendBasicBlock(llfn, Str.buf("allocas"));
7464

7465 7466 7467 7468
    auto fcx = @rec(llfn=llfn,
                    lltaskptr=lltaskptr,
                    llenv=C_null(T_ptr(T_nil())),
                    llretptr=C_null(T_ptr(T_nil())),
7469
                    mutable llallocas = llallocas,
7470
                    mutable llself=none[self_vt],
7471 7472 7473 7474
                    mutable lliterbody=none[ValueRef],
                    llargs=new_def_hash[ValueRef](),
                    llobjfields=new_def_hash[ValueRef](),
                    lllocals=new_def_hash[ValueRef](),
7475
                    llupvars=new_def_hash[ValueRef](),
7476
                    mutable lltydescs=Vec.empty[ValueRef](),
7477
                    lcx=cx);
7478 7479

    auto bcx = new_top_block_ctxt(fcx);
7480
    auto lltop = bcx.llbb;
7481

7482 7483
    auto lldst_vec = bcx.build.Load(lldst_vec_ptr);

7484 7485
    // 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.
7486

7487
    auto llcopy_dst_ptr = alloca(bcx, T_int());
7488 7489
    auto llnew_vec_res =
        trans_upcall(bcx, "upcall_vec_grow",
7490 7491 7492
                     vec(vp2i(bcx, lldst_vec),
                         vec_fill_adjusted(bcx, llsrc_vec, llskipnull),
                         vp2i(bcx, llcopy_dst_ptr),
7493 7494
                         vp2i(bcx, llvec_tydesc)),
                     false);
7495 7496

    bcx = llnew_vec_res.bcx;
7497 7498
    auto llnew_vec = vi2p(bcx, llnew_vec_res.val,
                          T_opaque_vec_ptr());
7499
    llvm.LLVMSetValueName(llnew_vec, Str.buf("llnew_vec"));
7500

7501 7502
    auto copy_dst_cx = new_sub_block_ctxt(bcx, "copy new <- dst");
    auto copy_src_cx = new_sub_block_ctxt(bcx, "copy new <- src");
7503

7504
    auto pp0 = alloca(bcx, T_ptr(T_i8()));
7505
    bcx.build.Store(vec_p1_adjusted(bcx, llnew_vec, llskipnull), pp0);
7506
    llvm.LLVMSetValueName(pp0, Str.buf("pp0"));
7507 7508 7509 7510 7511 7512 7513 7514 7515 7516 7517 7518 7519 7520 7521

    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));
7522
        llvm.LLVMSetValueName(src_lim, Str.buf("src_lim"));
7523 7524 7525 7526 7527

        auto elt_llsz =
            cx.build.Load(cx.build.GEP(elt_tydesc,
                                       vec(C_int(0),
                                           C_int(abi.tydesc_field_size))));
7528
        llvm.LLVMSetValueName(elt_llsz, Str.buf("elt_llsz"));
7529

7530 7531 7532 7533 7534 7535 7536
        auto elt_llalign =
            cx.build.Load(cx.build.GEP(elt_tydesc,
                                       vec(C_int(0),
                                           C_int(abi.tydesc_field_align))));
        llvm.LLVMSetValueName(elt_llsz, Str.buf("elt_llalign"));


7537
        fn take_one(ValueRef elt_tydesc,
7538 7539 7540
                    @block_ctxt cx,
                    ValueRef dst, ValueRef src) -> result {
            call_tydesc_glue_full(cx, src,
7541
                                  elt_tydesc,
7542
                                  abi.tydesc_field_take_glue);
7543
            ret res(cx, src);
7544 7545
        }

7546
        auto bcx = iter_sequence_raw(cx, dst, src, src_lim,
7547
                                     elt_llsz, bind take_one(elt_tydesc,
7548
                                                             _, _, _)).bcx;
7549

7550
        ret call_memcpy(bcx, dst, src, n_bytes, elt_llalign);
7551 7552 7553
    }

    // Copy any dst elements in, omitting null if doing str.
7554

7555
    auto n_bytes = vec_fill_adjusted(copy_dst_cx, lldst_vec, llskipnull);
7556
    llvm.LLVMSetValueName(n_bytes, Str.buf("n_bytes"));
7557

7558 7559
    copy_dst_cx = copy_elts(copy_dst_cx,
                            llelt_tydesc,
7560
                            vec_p0(copy_dst_cx, llnew_vec),
7561 7562 7563
                            vec_p0(copy_dst_cx, lldst_vec),
                            n_bytes).bcx;

7564 7565 7566 7567
    put_vec_fill(copy_dst_cx, llnew_vec, vec_fill(copy_dst_cx, lldst_vec));

    copy_dst_cx.build.Store(vec_p1_adjusted(copy_dst_cx, llnew_vec,
                                            llskipnull), pp0);
7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579
    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,
7580 7581 7582
                 copy_src_cx.build.Add(vec_fill_adjusted(copy_src_cx,
                                                         llnew_vec,
                                                         llskipnull),
7583
                                        n_bytes));
7584 7585 7586 7587

    // 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();
7588 7589 7590

    // Tie up the llallocas -> lltop edge.
    new_builder(fcx.llallocas).Br(lltop);
7591 7592 7593
}


7594 7595 7596
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()),
7597
             exit_task_glue = decl_cdecl_fn(llmod, abi.exit_task_glue_name(),
7598
                                            T_fn(vec(T_int(),
7599
                                                     T_int(),
7600 7601
                                                     T_int(),
                                                     T_int(),
7602
                                                     T_int()),
7603
                                                 T_void())),
7604

7605
             native_glues_rust =
7606
                 Vec.init_fn[ValueRef](bind decl_native_glue(llmod, tn,
7607 7608
                    abi.ngt_rust, _), abi.n_native_glues + 1 as uint),
             native_glues_pure_rust =
7609
                 Vec.init_fn[ValueRef](bind decl_native_glue(llmod, tn,
7610
                    abi.ngt_pure_rust, _), abi.n_native_glues + 1 as uint),
7611
             native_glues_cdecl =
7612
                 Vec.init_fn[ValueRef](bind decl_native_glue(llmod, tn,
7613
                    abi.ngt_cdecl, _), abi.n_native_glues + 1 as uint),
7614
             no_op_type_glue = decl_no_op_type_glue(llmod, tn),
7615
             vec_append_glue = make_vec_append_glue(llmod, tn));
7616 7617
}

7618
fn make_common_glue(session.session sess, str output) {
7619 7620 7621
    // 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.
7622
    auto llmod =
7623
        llvm.LLVMModuleCreateWithNameInContext(Str.buf("rust_out"),
7624 7625
                                               llvm.LLVMGetGlobalContext());

7626 7627
    llvm.LLVMSetDataLayout(llmod, Str.buf(x86.get_data_layout()));
    llvm.LLVMSetTarget(llmod, Str.buf(x86.get_target_triple()));
7628
    auto td = mk_target_data(x86.get_data_layout());
7629
    auto tn = mk_type_names();
7630
    let ValueRef crate_ptr =
7631
        llvm.LLVMAddGlobal(llmod, T_crate(tn), Str.buf("rust_crate"));
7632

7633 7634
    auto intrinsics = declare_intrinsics(llmod);

7635
    llvm.LLVMSetModuleInlineAsm(llmod, Str.buf(x86.get_module_asm()));
7636

7637
    auto glues = make_glues(llmod, tn);
7638
    create_crate_constant(crate_ptr, glues);
7639

7640 7641
    trans.trans_exit_task_glue(glues, new_str_hash[ValueRef](), tn,
                               llmod);
7642

7643
    Link.Write.run_passes(sess, llmod, output);
7644 7645
}

7646 7647 7648 7649
fn create_module_map(@crate_ctxt ccx) -> ValueRef {
    auto elttype = T_struct(vec(T_int(), T_int()));
    auto maptype = T_array(elttype, ccx.module_data.size() + 1u);
    auto map = llvm.LLVMAddGlobal(ccx.llmod, maptype,
7650
                                  Str.buf("_rust_mod_map"));
7651 7652 7653 7654
    llvm.LLVMSetLinkage(map, lib.llvm.LLVMInternalLinkage as llvm.Linkage);
    let vec[ValueRef] elts = vec();
    for each (@tup(str, ValueRef) item in ccx.module_data.items()) {
        auto elt = C_struct(vec(p2i(C_cstr(ccx, item._0)), p2i(item._1)));
7655
        Vec.push[ValueRef](elts, elt);
7656 7657
    }
    auto term = C_struct(vec(C_int(0), C_int(0)));
7658
    Vec.push[ValueRef](elts, term);
7659 7660 7661 7662 7663 7664
    llvm.LLVMSetInitializer(map, C_array(elttype, elts));
    ret map;
}

fn crate_name(@crate_ctxt ccx, str deflt) -> str {
    for (@ast.meta_item item in ccx.sess.get_metadata()) {
7665
        if (Str.eq(item.node.name, "name")) {
7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678
            ret item.node.value;
        }
    }
    ret deflt;
}

// FIXME use hashed metadata instead of crate names once we have that
fn create_crate_map(@crate_ctxt ccx) -> ValueRef {
    let vec[ValueRef] subcrates = vec();
    auto i = 1;
    while (ccx.sess.has_external_crate(i)) {
        auto name = ccx.sess.get_external_crate(i).name;
        auto cr = llvm.LLVMAddGlobal(ccx.llmod, T_int(),
7679 7680
                                     Str.buf("_rust_crate_map_" + name));
        Vec.push[ValueRef](subcrates, p2i(cr));
7681 7682
        i += 1;
    }
7683
    Vec.push[ValueRef](subcrates, C_int(0));
7684
    auto sym_name = "_rust_crate_map_" + crate_name(ccx, "__none__");
7685
    auto arrtype = T_array(T_int(), Vec.len[ValueRef](subcrates));
7686
    auto maptype = T_struct(vec(T_int(), arrtype));
7687
    auto map = llvm.LLVMAddGlobal(ccx.llmod, maptype, Str.buf(sym_name));
7688 7689 7690 7691 7692 7693
    llvm.LLVMSetLinkage(map, lib.llvm.LLVMExternalLinkage as llvm.Linkage);
    llvm.LLVMSetInitializer(map, C_struct(vec(p2i(create_module_map(ccx)),
                                              C_array(T_int(), subcrates))));
    ret map;
}

7694
fn trans_crate(session.session sess, @ast.crate crate, ty.ctxt tcx,
7695
               ty.type_cache type_cache, str output)
7696
        -> ModuleRef {
7697
    auto llmod =
7698
        llvm.LLVMModuleCreateWithNameInContext(Str.buf("rust_out"),
7699 7700
                                               llvm.LLVMGetGlobalContext());

7701 7702
    llvm.LLVMSetDataLayout(llmod, Str.buf(x86.get_data_layout()));
    llvm.LLVMSetTarget(llmod, Str.buf(x86.get_target_triple()));
7703 7704 7705
    auto td = mk_target_data(x86.get_data_layout());
    auto tn = mk_type_names();
    let ValueRef crate_ptr =
7706
        llvm.LLVMAddGlobal(llmod, T_crate(tn), Str.buf("rust_crate"));
7707

7708
    auto intrinsics = declare_intrinsics(llmod);
7709

7710
    auto glues = make_glues(llmod, tn);
7711 7712
    auto hasher = ty.hash_ty;
    auto eqer = ty.eq_ty;
7713 7714 7715 7716 7717
    auto tag_sizes = Map.mk_hashmap[ty.t,uint](hasher, eqer);
    auto tydescs = Map.mk_hashmap[ty.t,@tydesc_info](hasher, eqer);
    auto lltypes = Map.mk_hashmap[ty.t,TypeRef](hasher, eqer);
    auto sha1s = Map.mk_hashmap[ty.t,str](hasher, eqer);
    auto abbrevs = Map.mk_hashmap[ty.t,metadata.ty_abbrev](hasher, eqer);
7718

7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737
    auto ccx = @rec(sess = sess,
                    llmod = llmod,
                    td = td,
                    tn = tn,
                    crate_ptr = crate_ptr,
                    externs = new_str_hash[ValueRef](),
                    intrinsics = intrinsics,
                    item_ids = new_def_hash[ValueRef](),
                    items = new_def_hash[@ast.item](),
                    native_items = new_def_hash[@ast.native_item](),
                    type_cache = type_cache,
                    item_symbols = new_def_hash[str](),
                    tag_sizes = tag_sizes,
                    discrims = new_def_hash[ValueRef](),
                    discrim_symbols = new_def_hash[str](),
                    fn_pairs = new_def_hash[ValueRef](),
                    consts = new_def_hash[ValueRef](),
                    obj_methods = new_def_hash[()](),
                    tydescs = tydescs,
7738
                    module_data = new_str_hash[ValueRef](),
7739
                    lltypes = lltypes,
7740 7741
                    glues = glues,
                    names = namegen(0),
7742
                    sha = std.SHA1.mk_sha1(),
7743
                    type_sha1s = sha1s,
7744
                    type_abbrevs = abbrevs,
7745
                    tcx = tcx);
7746
    auto cx = new_local_ctxt(ccx);
7747

7748
    create_typedefs(ccx);
7749

7750
    collect_items(ccx, crate);
7751 7752
    collect_tag_ctors(ccx, crate);
    trans_constants(ccx, crate);
7753
    trans_mod(cx, crate.node.module);
7754
    trans_vec_append_glue(cx);
7755
    auto crate_map = create_crate_map(ccx);
7756
    if (!sess.get_opts().shared) {
7757
        trans_main_fn(cx, crate_ptr, crate_map);
7758
    }
7759

7760
    // Translate the metadata.
7761
    middle.metadata.write_metadata(cx.ccx, crate);
7762

7763
    ret llmod;
7764 7765 7766 7767 7768 7769 7770 7771 7772
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
7773
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
7774 7775
// End:
//