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

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

21 22
import pretty.pprust;

23
import middle.ty.pat_ty;
P
Patrick Walton 已提交
24

25
import util.common;
26
import util.common.istr;
27
import util.common.new_def_hash;
28
import util.common.new_str_hash;
29 30 31

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

46 47
import lib.llvm.False;
import lib.llvm.True;
48

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

56 57
type glue_fns = rec(ValueRef activate_glue,
                    ValueRef yield_glue,
58
                    ValueRef exit_task_glue,
59
                    vec[ValueRef] native_glues_rust,
60
                    vec[ValueRef] native_glues_pure_rust,
61
                    vec[ValueRef] native_glues_cdecl,
62
                    ValueRef no_op_type_glue,
63
                    ValueRef memcpy_glue,
64
                    ValueRef bzero_glue,
65
                    ValueRef vec_append_glue);
66

67 68
type tydesc_info = rec(ValueRef tydesc,
                       ValueRef take_glue,
69 70
                       ValueRef drop_glue,
                       ValueRef cmp_glue);
71

72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
/*
 * 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.
 *
 */

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

121
type local_ctxt = rec(vec[str] path,
122
                      vec[str] module_path,
123 124 125
                      vec[ast.ty_param] obj_typarams,
                      vec[ast.obj_field] obj_fields,
                      @crate_ctxt ccx);
126

127

128
type self_vt = rec(ValueRef v, ty.t t);
129

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

144
tag cleanup {
145
    clean(fn(@block_ctxt cx) -> result);
146 147
}

148 149 150

tag block_kind {
    SCOPE_BLOCK;
151
    LOOP_SCOPE_BLOCK(option.t[@block_ctxt], @block_ctxt);
152 153 154
    NON_SCOPE_BLOCK;
}

155 156
state type block_ctxt = rec(BasicBlockRef llbb,
                            builder build,
157
                            block_parent parent,
158
                            block_kind kind,
159 160 161
                            mutable vec[cleanup] cleanups,
                            @fn_ctxt fcx);

162 163 164 165 166 167 168 169
// FIXME: we should be able to use option.t[@block_parent] here but
// the infinite-tag check in rustboot gets upset.

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

170

171 172 173
state type result = rec(mutable @block_ctxt bcx,
                        mutable ValueRef val);

174 175 176 177
fn sep() -> str {
    ret "_";
}

178
fn extend_path(@local_ctxt cx, str name) -> @local_ctxt {
179
  ret @rec(path = cx.path + vec(name) with *cx);
180 181 182 183 184 185 186
}

fn path_name(vec[str] path) -> str {
    ret _str.connect(path, sep());
}


187
fn mangle_name_by_type(@crate_ctxt ccx, vec[str] path, ty.t t) -> str {
188 189 190 191 192 193
    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;
194 195 196 197
            // NB: do *not* use abbrevs here as we want the symbol names
            // to be independent of one another in the crate.
            auto cx = @rec(ds=f, tcx=ccx.tcx,
                           use_abbrevs=false, abbrevs=ccx.type_abbrevs);
198 199 200 201 202 203
            ccx.sha.input_str(metadata.Encode.ty_str(cx, t));
            hash = _str.substr(ccx.sha.result_str(), 0u, 16u);
            ccx.type_sha1s.insert(t, hash);
        }
    }
    ret sep() + "rust" + sep() + hash + sep() + path_name(path);
204 205
}

206
fn mangle_name_by_seq(@crate_ctxt ccx, vec[str] path, str flav) -> str {
207
    ret sep() + "rust" + sep()
208 209
        + ccx.names.next(flav) + sep()
        + path_name(path);
210 211
}

212 213 214 215 216
fn res(@block_ctxt bcx, ValueRef val) -> result {
    ret rec(mutable bcx = bcx,
            mutable val = val);
}

217 218
fn ty_str(type_names tn, TypeRef t) -> str {
    ret lib.llvm.type_to_str(tn, t);
219 220 221 222 223 224
}

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

225 226
fn val_str(type_names tn, ValueRef v) -> str {
    ret ty_str(tn, val_ty(v));
227
}
228 229 230 231


// LLVM type constructors.

232 233 234 235 236 237 238 239 240 241 242
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.
243 244 245
    ret llvm.LLVMVoidType();
}

246 247 248 249 250
fn T_nil() -> TypeRef {
    // NB: See above in T_void().
    ret llvm.LLVMInt1Type();
}

251 252 253 254
fn T_i1() -> TypeRef {
    ret llvm.LLVMInt1Type();
}

255 256 257 258 259 260 261 262 263
fn T_i8() -> TypeRef {
    ret llvm.LLVMInt8Type();
}

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

fn T_i32() -> TypeRef {
264 265 266
    ret llvm.LLVMInt32Type();
}

267 268 269 270
fn T_i64() -> TypeRef {
    ret llvm.LLVMInt64Type();
}

271 272 273 274 275 276 277 278
fn T_f32() -> TypeRef {
    ret llvm.LLVMFloatType();
}

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

279 280 281 282
fn T_bool() -> TypeRef {
    ret T_i1();
}

283 284 285 286 287
fn T_int() -> TypeRef {
    // FIXME: switch on target type.
    ret T_i32();
}

288 289 290 291 292
fn T_float() -> TypeRef {
    // FIXME: switch on target type.
    ret T_f64();
}

293 294 295 296
fn T_char() -> TypeRef {
    ret T_i32();
}

297 298 299 300
fn T_fn(vec[TypeRef] inputs, TypeRef output) -> TypeRef {
    ret llvm.LLVMFunctionType(output,
                              _vec.buf[TypeRef](inputs),
                              _vec.len[TypeRef](inputs),
301 302 303
                              False);
}

304
fn T_fn_pair(type_names tn, TypeRef tfn) -> TypeRef {
305
    ret T_struct(vec(T_ptr(tfn),
306
                     T_opaque_closure_ptr(tn)));
307 308
}

309 310 311 312 313 314 315 316 317 318 319 320 321 322
fn T_ptr(TypeRef t) -> TypeRef {
    ret llvm.LLVMPointerType(t, 0u);
}

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

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

323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
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;
340 341
}

342 343 344 345 346 347 348 349 350 351
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 =
        _vec.init_elt[TypeRef](T_nil(), abi.n_tydesc_fields as uint);
    llvm.LLVMGetStructElementTypes(T_tydesc(tn),
                                   _vec.buf[TypeRef](tydesc_elts));
    auto t = llvm.LLVMGetElementType(tydesc_elts.(field));
    ret t;
}

352 353 354 355 356 357
fn T_glue_fn(type_names tn) -> TypeRef {
    auto s = "glue_fn";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }

358 359 360 361 362
    auto t = T_tydesc_field(tn, abi.tydesc_field_drop_glue);
    tn.associate(s, t);
    ret t;
}

363 364 365 366 367
fn T_dtor(@crate_ctxt ccx, TypeRef llself_ty) -> TypeRef {
    ret type_of_fn_full(ccx, ast.proto_fn, some[TypeRef](llself_ty),
                        _vec.empty[ty.arg](), ty.mk_nil(ccx.tcx), 0u);
}

368 369 370 371 372 373 374
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);
375 376
    tn.associate(s, t);
    ret t;
377 378
}

379 380 381 382 383 384
fn T_tydesc(type_names tn) -> TypeRef {

    auto s = "tydesc";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }
385 386 387

    auto th = mk_type_handle();
    auto abs_tydesc = llvm.LLVMResolveTypeHandle(th.llth);
388
    auto tydescpp = T_ptr(T_ptr(abs_tydesc));
389
    auto pvoid = T_ptr(T_i8());
390
    auto glue_fn_ty = T_ptr(T_fn(vec(T_ptr(T_nil()),
391
                                     T_taskptr(tn),
392
                                     T_ptr(T_nil()),
393
                                     tydescpp,
394
                                     pvoid), T_void()));
395
    auto cmp_glue_fn_ty = T_ptr(T_fn(vec(T_ptr(T_i1()),
396 397 398 399
                                         T_taskptr(tn),
                                         T_ptr(T_nil()),
                                         tydescpp,
                                         pvoid,
400 401
                                         pvoid,
                                         T_i8()), T_void()));
402
    auto tydesc = T_struct(vec(tydescpp,          // first_param
403 404
                               T_int(),           // size
                               T_int(),           // align
405 406 407 408 409 410
                               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
411 412
                               glue_fn_ty,        // is_stateful
                               cmp_glue_fn_ty));  // cmp_glue
413 414

    llvm.LLVMRefineType(abs_tydesc, tydesc);
415 416 417
    auto t = llvm.LLVMResolveTypeHandle(th.llth);
    tn.associate(s, t);
    ret t;
418 419
}

420 421 422 423
fn T_array(TypeRef t, uint n) -> TypeRef {
    ret llvm.LLVMArrayType(t, n);
}

424 425 426 427
fn T_vec(TypeRef t) -> TypeRef {
    ret T_struct(vec(T_int(),       // Refcount
                     T_int(),       // Alloc
                     T_int(),       // Fill
428
                     T_int(),       // Pad
429
                     T_array(t, 0u) // Body elements
430 431 432
                     ));
}

433 434 435 436
fn T_opaque_vec_ptr() -> TypeRef {
    ret T_ptr(T_vec(T_int()));
}

437 438
fn T_str() -> TypeRef {
    ret T_vec(T_i8());
439 440
}

441 442 443 444
fn T_box(TypeRef t) -> TypeRef {
    ret T_struct(vec(T_int(), t));
}

B
Brian Anderson 已提交
445 446 447 448 449 450 451 452
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
}

453 454 455 456 457 458 459 460 461 462 463 464
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
465 466 467 468 469
                          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
470 471
                          T_int(),      // int n_rust_syms
                          T_int(),      // int n_c_syms
472
                          T_int(),      // int n_libs
473
                          T_int()       // uintptr_t abi_tag
474 475 476
                          ));
    tn.associate(s, t);
    ret t;
477 478
}

479 480
fn T_taskptr(type_names tn) -> TypeRef {
    ret T_ptr(T_task(tn));
481 482
}

483 484
// This type must never be used directly; it must always be cast away.
fn T_typaram(type_names tn) -> TypeRef {
485 486 487 488 489
    auto s = "typaram";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }

490
    auto t = T_i8();
491 492
    tn.associate(s, t);
    ret t;
493 494
}

495 496 497 498
fn T_typaram_ptr(type_names tn) -> TypeRef {
    ret T_ptr(T_typaram(tn));
}

499 500
fn T_closure_ptr(type_names tn,
                 TypeRef lltarget_ty,
501 502
                 TypeRef llbindings_ty,
                 uint n_ty_params) -> TypeRef {
503 504 505 506

    // 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.
507
    ret T_ptr(T_box(T_struct(vec(T_ptr(T_tydesc(tn)),
508
                                 lltarget_ty,
509 510
                                 llbindings_ty,
                                 T_captured_tydescs(tn, n_ty_params))
511 512 513
                             )));
}

514 515 516 517 518 519 520
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()))),
521 522
                           T_nil(),
                           0u);
523 524
    tn.associate(s, t);
    ret t;
525 526
}

527 528 529 530 531 532 533 534 535 536 537
fn T_tag(type_names tn, uint size) -> TypeRef {
    auto s = "tag_" + _uint.to_str(size, 10u);
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }
    auto t = T_struct(vec(T_int(), T_array(T_i8(), size)));
    tn.associate(s, t);
    ret t;
}

fn T_opaque_tag(type_names tn) -> TypeRef {
538
    auto s = "opaque_tag";
539 540 541
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }
542
    auto t = T_struct(vec(T_int(), T_i8()));
543 544 545 546
    tn.associate(s, t);
    ret t;
}

547 548 549 550
fn T_opaque_tag_ptr(type_names tn) -> TypeRef {
    ret T_ptr(T_opaque_tag(tn));
}

551 552
fn T_captured_tydescs(type_names tn, uint n) -> TypeRef {
    ret T_struct(_vec.init_elt[TypeRef](T_ptr(T_tydesc(tn)), n));
553 554
}

555 556 557 558 559 560 561
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)));
    }
562

563
    ret T_ptr(T_box(T_obj(tn, n_captured_tydescs)));
564 565
}

566
fn T_opaque_obj_ptr(type_names tn) -> TypeRef {
567
    ret T_obj_ptr(tn, 0u);
568 569
}

570

571 572 573 574
// 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.
575
fn type_of(@crate_ctxt cx, ty.t t) -> TypeRef {
576
    if (ty.type_has_dynamic_size(cx.tcx, t)) {
577
        log_err "type_of() called on a type with dynamic size: " +
578
            ty.ty_to_str(cx.tcx, t);
579 580 581
        fail;
    }

582
    ret type_of_inner(cx, t);
583 584
}

585
fn type_of_explicit_args(@crate_ctxt cx, vec[ty.arg] inputs) -> vec[TypeRef] {
586 587
    let vec[TypeRef] atys = vec();
    for (ty.arg arg in inputs) {
588
        if (ty.type_has_dynamic_size(cx.tcx, arg.ty)) {
589
            check (arg.mode == ast.alias);
590
            atys += vec(T_typaram_ptr(cx.tn));
591
        } else {
592
            let TypeRef t;
593 594
            alt (arg.mode) {
                case (ast.alias) {
595
                    t = T_ptr(type_of_inner(cx, arg.ty));
596 597
                }
                case (_) {
598
                    t = type_of_inner(cx, arg.ty);
599 600
                }
            }
601
            atys += vec(t);
602 603 604 605
        }
    }
    ret atys;
}
606 607 608 609 610 611 612 613

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

614
fn type_of_fn_full(@crate_ctxt cx,
615
                   ast.proto proto,
616 617
                   option.t[TypeRef] obj_self,
                   vec[ty.arg] inputs,
618
                   ty.t output,
619
                   uint ty_param_count) -> TypeRef {
620
    let vec[TypeRef] atys = vec();
621

622
    // Arg 0: Output pointer.
623
    if (ty.type_has_dynamic_size(cx.tcx, output)) {
624
        atys += vec(T_typaram_ptr(cx.tn));
625
    } else {
626
        atys += vec(T_ptr(type_of_inner(cx, output)));
627 628
    }

629
    // Arg 1: Task pointer.
630
    atys += vec(T_taskptr(cx.tn));
631 632

    // Arg 2: Env (closure-bindings / self-obj)
633 634
    alt (obj_self) {
        case (some[TypeRef](?t)) {
635
            check (t as int != 0);
636
            atys += vec(t);
637
        }
638
        case (_) {
639
            atys += vec(T_opaque_closure_ptr(cx.tn));
640
        }
641 642
    }

643 644 645 646
    // Args >3: ty params, if not acquired via capture...
    if (obj_self == none[TypeRef]) {
        auto i = 0u;
        while (i < ty_param_count) {
647
            atys += vec(T_ptr(T_tydesc(cx.tn)));
648 649
            i += 1u;
        }
650 651
    }

652
    if (proto == ast.proto_iter) {
653 654 655
        // 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.
656 657
        atys +=
            vec(T_fn_pair(cx.tn,
658
                          type_of_fn_full(cx, ast.proto_fn, none[TypeRef],
659
                                          vec(rec(mode=ast.alias, ty=output)),
660
                                          ty.mk_nil(cx.tcx), 0u)));
661 662
    }

663
    // ... then explicit args.
664
    atys += type_of_explicit_args(cx, inputs);
665

666
    ret T_fn(atys, llvm.LLVMVoidType());
667 668
}

669
fn type_of_fn(@crate_ctxt cx,
670
              ast.proto proto,
671
              vec[ty.arg] inputs,
672
              ty.t output,
673 674 675
              uint ty_param_count) -> TypeRef {
    ret type_of_fn_full(cx, proto, none[TypeRef], inputs, output,
                        ty_param_count);
676 677
}

678 679
fn type_of_native_fn(@crate_ctxt cx, ast.native_abi abi,
                     vec[ty.arg] inputs,
680
                     ty.t output,
681
                     uint ty_param_count) -> TypeRef {
682 683
    let vec[TypeRef] atys = vec();
    if (abi == ast.native_abi_rust) {
684
        atys += vec(T_taskptr(cx.tn));
685 686 687
        auto t = ty.ty_native_fn(abi, inputs, output);
        auto i = 0u;
        while (i < ty_param_count) {
688
            atys += vec(T_ptr(T_tydesc(cx.tn)));
689 690 691 692
            i += 1u;
        }
    }
    atys += type_of_explicit_args(cx, inputs);
693
    ret T_fn(atys, type_of_inner(cx, output));
694 695
}

696
fn type_of_inner(@crate_ctxt cx, ty.t t) -> TypeRef {
697 698 699 700 701
    // Check the cache.
    if (cx.lltypes.contains_key(t)) {
        ret cx.lltypes.get(t);
    }

702 703
    let TypeRef llty = 0 as TypeRef;

704
    alt (ty.struct(cx.tcx, t)) {
705 706 707 708
        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(); }
709
        case (ty.ty_float) { llty = T_float(); }
710
        case (ty.ty_uint) { llty = T_int(); }
711
        case (ty.ty_machine(?tm)) {
712
            alt (tm) {
713 714 715 716 717 718 719 720 721 722
                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(); }
723 724
            }
        }
725 726
        case (ty.ty_char) { llty = T_char(); }
        case (ty.ty_str) { llty = T_ptr(T_str()); }
727
        case (ty.ty_tag(_, _)) {
728
            if (ty.type_has_dynamic_size(cx.tcx, t)) {
729 730 731 732 733
                llty = T_opaque_tag(cx.tn);
            } else {
                auto size = static_size_of_tag(cx, t);
                llty = T_tag(cx.tn, size);
            }
734
        }
735
        case (ty.ty_box(?mt)) {
736
            llty = T_ptr(T_box(type_of_inner(cx, mt.ty)));
737
        }
738
        case (ty.ty_vec(?mt)) {
739
            llty = T_ptr(T_vec(type_of_inner(cx, mt.ty)));
740
        }
B
Brian Anderson 已提交
741
        case (ty.ty_port(?t)) {
742
            llty = T_ptr(T_port(type_of_inner(cx, t)));
B
Brian Anderson 已提交
743 744
        }
        case (ty.ty_chan(?t)) {
745
            llty = T_ptr(T_chan(type_of_inner(cx, t)));
B
Brian Anderson 已提交
746
        }
747
        case (ty.ty_tup(?elts)) {
748
            let vec[TypeRef] tys = vec();
749
            for (ty.mt elt in elts) {
750
                tys += vec(type_of_inner(cx, elt.ty));
751
            }
752
            llty = T_struct(tys);
753
        }
754
        case (ty.ty_rec(?fields)) {
755
            let vec[TypeRef] tys = vec();
756
            for (ty.field f in fields) {
757
                tys += vec(type_of_inner(cx, f.mt.ty));
758
            }
759
            llty = T_struct(tys);
760
        }
761
        case (ty.ty_fn(?proto, ?args, ?out)) {
762
            llty = T_fn_pair(cx.tn, type_of_fn(cx, proto, args, out, 0u));
763
        }
764
        case (ty.ty_native_fn(?abi, ?args, ?out)) {
765
            auto nft = native_fn_wrapper_type(cx, 0u, t);
766
            llty = T_fn_pair(cx.tn, nft);
767
        }
768
        case (ty.ty_obj(?meths)) {
769 770 771
            auto th = mk_type_handle();
            auto self_ty = llvm.LLVMResolveTypeHandle(th.llth);

772
            let vec[TypeRef] mtys = vec(T_ptr(T_i8()));
773
            for (ty.method m in meths) {
774
                let TypeRef mty =
775
                    type_of_fn_full(cx, m.proto,
776
                                    some[TypeRef](self_ty),
777
                                    m.inputs, m.output, 0u);
778
                mtys += vec(T_ptr(mty));
779
            }
780
            let TypeRef vtbl = T_struct(mtys);
781
            let TypeRef pair = T_struct(vec(T_ptr(vtbl),
782
                                            T_opaque_obj_ptr(cx.tn)));
783

784 785 786
            auto abs_pair = llvm.LLVMResolveTypeHandle(th.llth);
            llvm.LLVMRefineType(abs_pair, pair);
            abs_pair = llvm.LLVMResolveTypeHandle(th.llth);
787
            llty = abs_pair;
788
        }
789
        case (ty.ty_var(_)) {
790
            log_err "ty_var in trans.type_of";
791 792
            fail;
        }
793
        case (ty.ty_param(_)) {
794
            llty = T_i8();
795
        }
796
        case (ty.ty_bound_param(_)) {
797
            log_err "ty_bound_param in trans.type_of";
798 799
            fail;
        }
800
        case (ty.ty_type) { llty = T_ptr(T_tydesc(cx.tn)); }
801
    }
802

803
    check (llty as int != 0);
804 805 806
    llvm.LLVMAddTypeName(cx.llmod,
                         _str.buf(ty.ty_to_short_str(cx.tcx,
                                                     cx.type_abbrevs, t)),
807
                         llty);
808
    cx.lltypes.insert(t, llty);
809
    ret llty;
810 811
}

812
fn type_of_arg(@local_ctxt cx, &ty.arg arg) -> TypeRef {
813
    alt (ty.struct(cx.ccx.tcx, arg.ty)) {
814 815
        case (ty.ty_param(_)) {
            if (arg.mode == ast.alias) {
816
                ret T_typaram_ptr(cx.ccx.tn);
817 818 819 820 821 822 823
            }
        }
        case (_) {
            // fall through
        }
    }

824
    auto typ;
825
    if (arg.mode == ast.alias) {
826
        typ = T_ptr(type_of_inner(cx.ccx, arg.ty));
827
    } else {
828
        typ = type_of_inner(cx.ccx, arg.ty);
829
    }
830
    ret typ;
831 832
}

833
fn type_of_ty_param_count_and_ty(@local_ctxt lcx,
834
                                 ty.ty_param_count_and_ty tpt) -> TypeRef {
835
    alt (ty.struct(lcx.ccx.tcx, tpt._1)) {
836
        case (ty.ty_fn(?proto, ?inputs, ?output)) {
837 838
            auto llfnty = type_of_fn(lcx.ccx, proto, inputs, output, tpt._0);
            ret T_fn_pair(lcx.ccx.tn, llfnty);
839 840 841 842 843
        }
        case (_) {
            // fall through
        }
    }
844
    ret type_of(lcx.ccx, tpt._1);
845 846 847
}


848 849 850 851 852 853 854 855 856
// 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 {
857 858 859 860 861 862 863
            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 已提交
864 865
                        c != (' ' as u8) && c != ('\t' as u8) &&
                        c != (';' as u8)) {
866 867 868 869 870
                        auto v = vec(c);
                        result += _str.from_bytes(v);
                    }
                }
            }
871 872 873 874 875
        }
    }
    ret result;
}

876 877 878 879 880 881
// LLVM constant constructors.

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

882
fn C_integral(int i, TypeRef t) -> ValueRef {
883 884 885 886 887 888
    // FIXME. We can't use LLVM.ULongLong with our existing minimal native
    // API, which only knows word-sized args.  Lucky for us LLVM has a "take a
    // string encoding" version.  Hilarious. Please fix to handle:
    //
    // ret llvm.LLVMConstInt(T_int(), t as LLVM.ULongLong, False);
    //
889 890 891
    ret llvm.LLVMConstIntOfString(t, _str.buf(istr(i)), 10);
}

892 893 894 895
fn C_float(str s) -> ValueRef {
    ret llvm.LLVMConstRealOfString(T_float(), _str.buf(s));
}

896 897 898 899
fn C_floating(str s, TypeRef t) -> ValueRef {
    ret llvm.LLVMConstRealOfString(t, _str.buf(s));
}

900 901 902 903 904
fn C_nil() -> ValueRef {
    // NB: See comment above in T_void().
    ret C_integral(0, T_i1());
}

905 906
fn C_bool(bool b) -> ValueRef {
    if (b) {
907
        ret C_integral(1, T_bool());
908
    } else {
909
        ret C_integral(0, T_bool());
910 911 912
    }
}

913 914
fn C_int(int i) -> ValueRef {
    ret C_integral(i, T_int());
915 916
}

917 918 919 920
fn C_i8(uint i) -> ValueRef {
    ret C_integral(i as int, T_i8());
}

921 922 923
// 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 {
924
    auto sc = llvm.LLVMConstString(_str.buf(s), _str.byte_len(s), False);
925
    auto g = llvm.LLVMAddGlobal(cx.llmod, val_ty(sc),
926 927
                                _str.buf(cx.names.next("str")));
    llvm.LLVMSetInitializer(g, sc);
928
    llvm.LLVMSetGlobalConstant(g, True);
929
    llvm.LLVMSetLinkage(g, lib.llvm.LLVMInternalLinkage
930
                        as llvm.Linkage);
931
    ret g;
932 933
}

934 935 936 937 938 939
// A rust boxed-and-length-annotated string.
fn C_str(@crate_ctxt cx, str s) -> ValueRef {
    auto len = _str.byte_len(s);
    auto box = C_struct(vec(C_int(abi.const_refcount as int),
                            C_int(len + 1u as int), // 'alloc'
                            C_int(len + 1u as int), // 'fill'
940
                            C_int(0),               // 'pad'
941 942 943 944 945 946
                            llvm.LLVMConstString(_str.buf(s),
                                                 len, False)));
    auto g = llvm.LLVMAddGlobal(cx.llmod, val_ty(box),
                                _str.buf(cx.names.next("str")));
    llvm.LLVMSetInitializer(g, box);
    llvm.LLVMSetGlobalConstant(g, True);
947
    llvm.LLVMSetLinkage(g, lib.llvm.LLVMInternalLinkage
948 949 950 951
                        as llvm.Linkage);
    ret llvm.LLVMConstPointerCast(g, T_ptr(T_str()));
}

952 953 954 955 956 957 958 959 960 961 962
fn C_zero_byte_arr(uint size) -> ValueRef {
    auto i = 0u;
    let vec[ValueRef] elts = vec();
    while (i < size) {
        elts += vec(C_integral(0, T_i8()));
        i += 1u;
    }
    ret llvm.LLVMConstArray(T_i8(), _vec.buf[ValueRef](elts),
                            _vec.len[ValueRef](elts));
}

963 964 965 966 967 968
fn C_struct(vec[ValueRef] elts) -> ValueRef {
    ret llvm.LLVMConstStruct(_vec.buf[ValueRef](elts),
                             _vec.len[ValueRef](elts),
                             False);
}

969 970 971 972 973
fn C_array(TypeRef ty, vec[ValueRef] elts) -> ValueRef {
    ret llvm.LLVMConstArray(ty, _vec.buf[ValueRef](elts),
                            _vec.len[ValueRef](elts));
}

974
fn decl_fn(ModuleRef llmod, str name, uint cc, TypeRef llty) -> ValueRef {
975 976
    let ValueRef llfn =
        llvm.LLVMAddFunction(llmod, _str.buf(name), llty);
977
    llvm.LLVMSetFunctionCallConv(llfn, cc);
978 979 980
    ret llfn;
}

981 982
fn decl_cdecl_fn(ModuleRef llmod, str name, TypeRef llty) -> ValueRef {
    ret decl_fn(llmod, name, lib.llvm.LLVMCCallConv, llty);
983 984
}

985 986
fn decl_fastcall_fn(ModuleRef llmod, str name, TypeRef llty) -> ValueRef {
    ret decl_fn(llmod, name, lib.llvm.LLVMFastCallConv, llty);
987 988
}

989
fn decl_internal_fastcall_fn(ModuleRef llmod,
990
                            str name, TypeRef llty) -> ValueRef {
991
    auto llfn = decl_fn(llmod, name, lib.llvm.LLVMFastCallConv, llty);
992
    llvm.LLVMSetLinkage(llfn, lib.llvm.LLVMInternalLinkage as llvm.Linkage);
993 994 995
    ret llfn;
}

996 997
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()));
998 999
}

1000
fn decl_native_glue(ModuleRef llmod, type_names tn,
1001 1002 1003 1004 1005 1006 1007 1008
                    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; }
    }

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

1017 1018
    if (!pass_task) {
        args += vec(T_int()); // taskptr, will not be passed
1019
    }
1020

1021
    args += _vec.init_elt[TypeRef](T_int(), n as uint);
1022

1023
    ret decl_fastcall_fn(llmod, s, T_fn(args, T_int()));
1024 1025
}

1026 1027 1028
fn get_extern_fn(&hashmap[str, ValueRef] externs,
                 ModuleRef llmod, str name,
                 uint cc, TypeRef ty) -> ValueRef {
1029 1030
    if (externs.contains_key(name)) {
        ret externs.get(name);
1031
    }
1032
    auto f = decl_fn(llmod, name, cc, ty);
1033
    externs.insert(name, f);
1034 1035 1036
    ret f;
}

1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
fn get_extern_const(&hashmap[str, ValueRef] externs,
                    ModuleRef llmod, str name, TypeRef ty) -> ValueRef {
    if (externs.contains_key(name)) {
        ret externs.get(name);
    }
    auto c = llvm.LLVMAddGlobal(llmod, ty, _str.buf(name));
    externs.insert(name, c);
    ret c;
}

fn get_simple_extern_fn(&hashmap[str, ValueRef] externs,
1048
                     ModuleRef llmod, str name, int n_args) -> ValueRef {
1049 1050 1051 1052 1053 1054
    auto inputs = _vec.init_elt[TypeRef](T_int(), n_args as uint);
    auto output = T_int();
    auto t = T_fn(inputs, output);
    ret get_extern_fn(externs, llmod, name, lib.llvm.LLVMCCallConv, t);
}

1055 1056
fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args, bool pure)
        -> result {
1057
    auto cxx = cx.fcx.lcx.ccx;
1058 1059
    auto lltaskptr = cx.build.PtrToInt(cx.fcx.lltaskptr, T_int());
    auto args2 = vec(lltaskptr) + args;
1060 1061 1062
    auto t = trans_native_call(cx.build, cxx.glues, lltaskptr,
                               cxx.externs, cxx.tn, cxx.llmod, name,
                               true, args2);
1063 1064 1065
    ret res(cx, t);
}

1066 1067 1068 1069
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 {
1070
    let int n = (_vec.len[ValueRef](args) as int);
1071
    let ValueRef llnative = get_simple_extern_fn(externs, llmod, name, n);
1072
    llnative = llvm.LLVMConstPointerCast(llnative, T_int());
1073

1074 1075
    let ValueRef llglue;
    if (pass_task) {
1076
        llglue = glues.native_glues_rust.(n);
1077
    } else {
1078
        llglue = glues.native_glues_cdecl.(n);
1079
    }
1080
    let vec[ValueRef] call_args = vec(llnative);
1081

1082 1083 1084
    if (!pass_task) {
        call_args += vec(lltaskptr);
    }
1085

1086
    for (ValueRef a in args) {
1087
        call_args += vec(b.ZExtOrBitCast(a, T_int()));
1088
    }
1089

1090
    ret b.FastCall(llglue, call_args);
1091 1092
}

1093
fn trans_non_gc_free(@block_ctxt cx, ValueRef v) -> result {
1094
    ret trans_upcall(cx, "upcall_free", vec(vp2i(cx, v), C_int(0)), false);
1095 1096
}

1097
fn find_scope_cx(@block_ctxt cx) -> @block_ctxt {
1098
    if (cx.kind != NON_SCOPE_BLOCK) {
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
        ret cx;
    }
    alt (cx.parent) {
        case (parent_some(?b)) {
            be find_scope_cx(b);
        }
        case (parent_none) {
            fail;
        }
    }
}

1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122
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;
        }
    }
}

1123 1124 1125 1126 1127
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);
}

1128 1129 1130 1131 1132
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);
}

1133 1134 1135 1136 1137 1138
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));
}

1139 1140 1141 1142 1143
// 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);
}

1144
fn llsize_of(TypeRef t) -> ValueRef {
1145 1146 1147
    ret llvm.LLVMConstIntCast(lib.llvm.llvm.LLVMSizeOf(t), T_int(), False);
}

1148
fn llalign_of(TypeRef t) -> ValueRef {
1149 1150 1151
    ret llvm.LLVMConstIntCast(lib.llvm.llvm.LLVMAlignOf(t), T_int(), False);
}

1152
fn size_of(@block_ctxt cx, ty.t t) -> result {
1153
    if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
1154
        ret res(cx, llsize_of(type_of(cx.fcx.lcx.ccx, t)));
1155 1156 1157 1158
    }
    ret dynamic_size_of(cx, t);
}

1159
fn align_of(@block_ctxt cx, ty.t t) -> result {
1160
    if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
1161
        ret res(cx, llalign_of(type_of(cx.fcx.lcx.ccx, t)));
1162 1163 1164 1165
    }
    ret dynamic_align_of(cx, t);
}

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


1175 1176 1177 1178
// 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.
1179 1180
fn simplify_type(@crate_ctxt ccx, ty.t typ) -> ty.t {
    fn simplifier(@crate_ctxt ccx, ty.t typ) -> ty.t {
1181
        alt (ty.struct(ccx.tcx, typ)) {
1182
            case (ty.ty_box(_)) {
1183
                ret ty.mk_imm_box(ccx.tcx, ty.mk_nil(ccx.tcx));
1184 1185 1186 1187
            }
            case (_) { ret typ; }
        }
    }
1188
    auto f = bind simplifier(ccx, _);
1189
    ret ty.fold_ty(ccx.tcx, f, typ);
1190 1191
}

1192
// Computes the size of the data part of a non-dynamically-sized tag.
1193
fn static_size_of_tag(@crate_ctxt cx, ty.t t) -> uint {
1194
    if (ty.type_has_dynamic_size(cx.tcx, t)) {
1195
        log_err "dynamically sized type passed to static_size_of_tag()";
1196 1197 1198 1199 1200 1201 1202
        fail;
    }

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

B
Brian Anderson 已提交
1203
    auto tid;
1204
    let vec[ty.t] subtys;
1205
    alt (ty.struct(cx.tcx, t)) {
1206 1207 1208 1209 1210
        case (ty.ty_tag(?tid_, ?subtys_)) {
            tid = tid_;
            subtys = subtys_;
        }
        case (_) {
1211
            log_err "non-tag passed to static_size_of_tag()";
1212 1213 1214 1215 1216 1217 1218
            fail;
        }
    }

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

1222
        // Perform any type parameter substitutions.
1223 1224
        tup_ty = ty.bind_params_in_type(cx.tcx, tup_ty);
        tup_ty = ty.substitute_type_params(cx.tcx, subtys, tup_ty);
1225

1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237
        // 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;
}

1238 1239
fn dynamic_size_of(@block_ctxt cx, ty.t t) -> result {
    fn align_elements(@block_ctxt cx, vec[ty.t] elts) -> result {
1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250
        //
        // 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;
1251
        for (ty.t e in elts) {
1252 1253 1254 1255 1256
            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);
1257
            off = bcx.build.Add(aligned_off, elt_size.val);
1258 1259 1260 1261 1262 1263
            max_align = umax(bcx, max_align, elt_align.val);
        }
        off = align_to(bcx, off, max_align);
        ret res(bcx, off);
    }

1264
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
1265
        case (ty.ty_param(?p)) {
1266
            auto szptr = field_of_tydesc(cx, t, false, abi.tydesc_field_size);
1267
            ret res(szptr.bcx, szptr.bcx.build.Load(szptr.val));
1268 1269
        }
        case (ty.ty_tup(?elts)) {
1270
            let vec[ty.t] tys = vec();
1271 1272 1273 1274
            for (ty.mt mt in elts) {
                tys += vec(mt.ty);
            }
            ret align_elements(cx, tys);
1275 1276
        }
        case (ty.ty_rec(?flds)) {
1277
            let vec[ty.t] tys = vec();
1278
            for (ty.field f in flds) {
1279
                tys += vec(f.mt.ty);
1280
            }
1281
            ret align_elements(cx, tys);
1282
        }
1283 1284 1285 1286
        case (ty.ty_tag(?tid, ?tps)) {
            auto bcx = cx;

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

1290
            auto variants = tag_variants(bcx.fcx.lcx.ccx, tid);
1291 1292
            for (variant_info variant in variants) {
                // Perform type substitution on the raw argument types.
1293 1294 1295
                let vec[ty.t] raw_tys = variant.args;
                let vec[ty.t] tys = vec();
                for (ty.t raw_ty in raw_tys) {
1296
                    auto t = ty.bind_params_in_type(cx.fcx.lcx.ccx.tcx,
1297
                                                    raw_ty);
1298
                    t = ty.substitute_type_params(cx.fcx.lcx.ccx.tcx, tps, t);
1299 1300 1301
                    tys += vec(t);
                }

1302 1303 1304 1305 1306 1307 1308 1309
                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);
            }

1310 1311 1312
            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);
1313
        }
1314 1315 1316
    }
}

1317
fn dynamic_align_of(@block_ctxt cx, ty.t t) -> result {
1318
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
1319
        case (ty.ty_param(?p)) {
1320
            auto aptr = field_of_tydesc(cx, t, false, abi.tydesc_field_align);
1321
            ret res(aptr.bcx, aptr.bcx.build.Load(aptr.val));
1322 1323 1324
        }
        case (ty.ty_tup(?elts)) {
            auto a = C_int(1);
1325
            auto bcx = cx;
1326 1327
            for (ty.mt e in elts) {
                auto align = align_of(bcx, e.ty);
1328 1329
                bcx = align.bcx;
                a = umax(bcx, a, align.val);
1330
            }
1331
            ret res(bcx, a);
1332 1333 1334
        }
        case (ty.ty_rec(?flds)) {
            auto a = C_int(1);
1335
            auto bcx = cx;
1336
            for (ty.field f in flds) {
1337
                auto align = align_of(bcx, f.mt.ty);
1338 1339
                bcx = align.bcx;
                a = umax(bcx, a, align.val);
1340
            }
1341
            ret res(bcx, a);
1342
        }
1343 1344 1345
        case (ty.ty_tag(_, _)) {
            ret res(cx, C_int(1)); // FIXME: stub
        }
1346 1347 1348
    }
}

1349
// Replacement for the LLVM 'GEP' instruction when field-indexing into a
1350 1351 1352 1353
// 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.
1354

1355
fn GEP_tup_like(@block_ctxt cx, ty.t t,
1356
                ValueRef base, vec[int] ixs) -> result {
1357

1358
    check (ty.type_is_tup_like(cx.fcx.lcx.ccx.tcx, t));
1359 1360 1361

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

1362
    if (! ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
1363 1364
        let vec[ValueRef] v = vec();
        for (int i in ixs) {
1365
            v += vec(C_int(i));
1366
        }
1367
        ret res(cx, cx.build.GEP(base, v));
1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386
    }

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

1387
    fn split_type(@crate_ctxt ccx, ty.t t, vec[int] ixs, uint n)
1388
        -> rec(vec[ty.t] prefix, ty.t target) {
1389 1390 1391 1392 1393 1394 1395

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

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

1396
        check (len > 1u);
1397 1398 1399 1400 1401

        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.
1402
            check (ixs.(n) == 0);
1403
            ret split_type(ccx, t, ixs, n+1u);
1404 1405
        }

1406
        check (n < len);
1407 1408

        let int ix = ixs.(n);
1409
        let vec[ty.t] prefix = vec();
1410 1411
        let int i = 0;
        while (i < ix) {
1412
            _vec.push[ty.t](prefix,
1413
                            ty.get_element_type(ccx.tcx, t, i as uint));
1414
            i += 1 ;
1415 1416
        }

1417
        auto selected = ty.get_element_type(ccx.tcx, t, i as uint);
1418 1419 1420 1421 1422 1423 1424 1425 1426

        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.
1427
            auto inner = split_type(ccx, selected, ixs, n+1u);
1428 1429 1430 1431 1432 1433 1434 1435 1436
            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.

1437
    auto s = split_type(cx.fcx.lcx.ccx, t, ixs, 0u);
1438
    auto prefix_ty = ty.mk_imm_tup(cx.fcx.lcx.ccx.tcx, s.prefix);
1439 1440 1441 1442 1443
    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));
1444

1445
    if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, s.target)) {
1446
        ret res(bcx, bumped);
1447
    }
1448

1449
    auto typ = T_ptr(type_of(bcx.fcx.lcx.ccx, s.target));
1450
    ret res(bcx, bcx.build.PointerCast(bumped, typ));
1451 1452
}

1453 1454 1455 1456
// 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.
1457 1458 1459 1460
fn GEP_tag(@block_ctxt cx,
           ValueRef llblobptr,
           &ast.def_id tag_id,
           &ast.def_id variant_id,
1461
           vec[ty.t] ty_substs,
1462
           int ix)
1463
        -> result {
1464
    auto variant = tag_variant_with_id(cx.fcx.lcx.ccx, tag_id, variant_id);
1465

1466 1467
    // Synthesize a tuple type so that GEP_tup_like() can work its magic.
    // Separately, store the type of the element we're interested in.
1468
    auto arg_tys = variant.args;
1469
    auto elem_ty = ty.mk_nil(cx.fcx.lcx.ccx.tcx); // typestate infelicity
1470
    auto i = 0;
1471 1472
    let vec[ty.t] true_arg_tys = vec();
    for (ty.t aty in arg_tys) {
1473 1474
        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,
1475
                                           arg_ty);
1476
        true_arg_tys += vec(arg_ty);
1477
        if (i == ix) {
1478
            elem_ty = arg_ty;
1479 1480 1481 1482
        }

        i += 1;
    }
1483

1484
    auto tup_ty = ty.mk_imm_tup(cx.fcx.lcx.ccx.tcx, true_arg_tys);
1485 1486 1487 1488

    // 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;
1489
    if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, tup_ty)) {
1490
        auto llty = type_of(cx.fcx.lcx.ccx, tup_ty);
1491 1492 1493 1494 1495 1496 1497 1498 1499 1500
        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;
1501
    if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, elem_ty)) {
1502
        auto llelemty = type_of(rslt.bcx.fcx.lcx.ccx, elem_ty);
1503 1504 1505 1506 1507 1508 1509 1510
        val = rslt.bcx.build.PointerCast(rslt.val, T_ptr(llelemty));
    } else {
        val = rslt.val;
    }

    ret res(rslt.bcx, val);
}

1511

1512
fn trans_raw_malloc(@block_ctxt cx, TypeRef llptr_ty, ValueRef llsize)
1513
        -> result {
1514 1515
    // FIXME: need a table to collect tydesc globals.
    auto tydesc = C_int(0);
1516
    auto rslt = trans_upcall(cx, "upcall_malloc", vec(llsize, tydesc), false);
1517
    rslt = res(rslt.bcx, vi2p(rslt.bcx, rslt.val, llptr_ty));
1518 1519 1520
    ret rslt;
}

1521
fn trans_malloc_boxed(@block_ctxt cx, ty.t t) -> result {
1522 1523
    // Synthesize a fake box type structurally so we have something
    // to measure the size of.
1524 1525 1526
    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);
1527
    auto sz = size_of(cx, boxed_body);
1528
    auto llty = type_of(cx.fcx.lcx.ccx, box_ptr);
1529
    ret trans_raw_malloc(sz.bcx, llty, sz.val);
1530 1531 1532
}


1533 1534 1535 1536 1537
// 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.
1538 1539 1540
fn field_of_tydesc(@block_ctxt cx, ty.t t, bool escapes, int field)
        -> result {
    auto tydesc = get_tydesc(cx, t, escapes);
1541 1542
    ret res(tydesc.bcx,
            tydesc.bcx.build.GEP(tydesc.val, vec(C_int(0), C_int(field))));
1543
}
1544

1545
// Given a type containing ty params, build a vector containing a ValueRef for
1546 1547
// 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
1548
// constructing derived tydescs.
1549
fn linearize_ty_params(@block_ctxt cx, ty.t t) ->
1550
        tup(vec[uint], vec[ValueRef]) {
1551
    let vec[ValueRef] param_vals = vec();
1552
    let vec[uint] param_defs = vec();
1553
    type rr = rec(@block_ctxt cx,
1554
                  mutable vec[ValueRef] vals,
1555
                  mutable vec[uint] defs);
1556

1557
    fn linearizer(@rr r, ty.t t) {
1558
        alt(ty.struct(r.cx.fcx.lcx.ccx.tcx, t)) {
1559 1560 1561 1562 1563
            case (ty.ty_param(?pid)) {
                let bool seen = false;
                for (uint d in r.defs) {
                    if (d == pid) {
                        seen = true;
1564 1565
                    }
                }
1566
                if (!seen) {
1567
                    r.vals += vec(r.cx.fcx.lltydescs.(pid));
1568 1569
                    r.defs += vec(pid);
                }
1570
            }
1571
            case (_) { }
1572 1573 1574 1575 1576 1577 1578 1579
        }
    }


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

1580
    auto f = bind linearizer(x, _);
1581
    ty.walk_ty(cx.fcx.lcx.ccx.tcx, f, t);
1582 1583 1584 1585

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

1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606
fn trans_stack_local_derived_tydesc(@block_ctxt cx, ValueRef llsz,
        ValueRef llalign, ValueRef lltydescs) -> result {
    auto lltydesc = alloca(cx, T_tydesc(cx.fcx.lcx.ccx.tn));

    // By convention, desc 0 is the root descriptor.
    auto llroottydesc = cx.build.Load(cx.build.GEP(lltydescs,
                                                   vec(C_int(0), C_int(0))));
    llroottydesc = cx.build.Load(llroottydesc);
    cx.build.Store(llroottydesc, lltydesc);

    // Store a pointer to the rest of the descriptors.
    auto llfirstparam = cx.build.GEP(lltydescs, vec(C_int(0), C_int(1)));
    cx.build.Store(llfirstparam,
                   cx.build.GEP(lltydesc, vec(C_int(0), C_int(0))));

    cx.build.Store(llsz, cx.build.GEP(lltydesc, vec(C_int(0), C_int(1))));
    cx.build.Store(llalign, cx.build.GEP(lltydesc, vec(C_int(0), C_int(2))));

    ret res(cx, lltydesc);
}

1607
fn get_tydesc(&@block_ctxt cx, ty.t t, bool escapes) -> result {
1608
    // Is the supplied type a type param? If so, return the passed-in tydesc.
1609
    alt (ty.type_param(cx.fcx.lcx.ccx.tcx, t)) {
1610
        case (some[uint](?id)) { ret res(cx, cx.fcx.lltydescs.(id)); }
1611
        case (none[uint])      { /* fall through */ }
1612
    }
1613 1614

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

1616 1617 1618
    if (ty.type_contains_params(cx.fcx.lcx.ccx.tcx, t)) {

        let uint n_params = ty.count_ty_params(cx.fcx.lcx.ccx.tcx, t);
1619
        auto tys = linearize_ty_params(cx, t);
1620

1621 1622
        check (n_params == _vec.len[uint](tys._0));
        check (n_params == _vec.len[ValueRef](tys._1));
1623

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

1626
        auto tydescs = alloca(cx, T_array(T_ptr(T_tydesc(cx.fcx.lcx.ccx.tn)),
1627
                                          1u /* for root*/ + n_params));
1628

1629
        auto i = 0;
1630 1631 1632
        auto tdp = cx.build.GEP(tydescs, vec(C_int(0), C_int(i)));
        cx.build.Store(root, tdp);
        i += 1;
1633 1634
        for (ValueRef td in tys._1) {
            auto tdp = cx.build.GEP(tydescs, vec(C_int(0), C_int(i)));
1635
            cx.build.Store(td, tdp);
1636
            i += 1;
1637 1638 1639 1640 1641 1642 1643 1644
        }

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

1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656
        auto v;
        if (escapes) {
            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 {
            v = trans_stack_local_derived_tydesc(bcx, sz.val, align.val,
                                                 tydescs);
        }
1657

1658
        ret res(v.bcx, vi2p(v.bcx, v.val,
1659
                            T_ptr(T_tydesc(cx.fcx.lcx.ccx.tn))));
1660 1661 1662
    }

    // Otherwise, generate a tydesc if necessary, and return it.
1663
    let vec[uint] tps = vec();
1664 1665
    auto st = get_static_tydesc(cx, t, tps).tydesc;
    ret res(cx, st);
1666 1667 1668 1669 1670 1671 1672 1673 1674
}

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]) {
1675 1676 1677 1678 1679 1680 1681

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

            /*
1682 1683 1684 1685 1686 1687 1688
            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);
1689 1690 1691 1692
            */

            auto info = declare_tydesc(cx.fcx.lcx, t);
            cx.fcx.lcx.ccx.tydescs.insert(t, info);
1693 1694 1695
            define_tydesc(cx.fcx.lcx, t, ty_params);
            ret info;
        }
1696
    }
1697 1698
}

1699 1700 1701
// 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.
1702
fn declare_tydesc(@local_ctxt cx, ty.t t) -> @tydesc_info {
1703 1704 1705 1706 1707 1708
    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");
1709
    auto ccx = cx.ccx;
1710

1711 1712
    auto llsize;
    auto llalign;
1713
    if (!ty.type_has_dynamic_size(ccx.tcx, t)) {
1714
        auto llty = type_of(ccx, t);
1715 1716 1717 1718 1719 1720 1721 1722 1723
        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);
    }

1724
    auto glue_fn_ty = T_ptr(T_glue_fn(ccx.tn));
1725

1726
    auto name = mangle_name_by_seq(ccx, cx.path, "tydesc");
1727
    auto gvar = llvm.LLVMAddGlobal(ccx.llmod, T_tydesc(ccx.tn),
1728
                                   _str.buf(name));
1729
    auto tydesc = C_struct(vec(C_null(T_ptr(T_ptr(T_tydesc(ccx.tn)))),
1730 1731
                               llsize,
                               llalign,
1732 1733 1734 1735 1736 1737
                               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
1738 1739
                               C_null(glue_fn_ty),    // is_stateful
                               cmp_glue));            // cmp_glue
1740 1741 1742

    llvm.LLVMSetInitializer(gvar, tydesc);
    llvm.LLVMSetGlobalConstant(gvar, True);
1743
    llvm.LLVMSetLinkage(gvar, lib.llvm.LLVMInternalLinkage
1744
                        as llvm.Linkage);
1745

1746
    auto info = @rec(
1747 1748
        tydesc=gvar,
        take_glue=take_glue,
1749 1750
        drop_glue=drop_glue,
        cmp_glue=cmp_glue
1751
    );
1752

1753
    ret info;
1754 1755
}

1756
tag make_generic_glue_helper_fn {
1757
    mgghf_single(fn(@block_ctxt cx, ValueRef v, ty.t t));
1758
    mgghf_cmp;
1759 1760
}

1761
// declare_tydesc() above must have been called first.
1762
fn define_tydesc(@local_ctxt cx, ty.t t, vec[uint] ty_params) {
1763
    auto info = cx.ccx.tydescs.get(t);
1764 1765 1766
    auto gvar = info.tydesc;

    auto tg = make_take_glue;
1767
    make_generic_glue(cx, t, info.take_glue, mgghf_single(tg), ty_params);
1768
    auto dg = make_drop_glue;
1769
    make_generic_glue(cx, t, info.drop_glue, mgghf_single(dg), ty_params);
1770
    make_generic_glue(cx, t, info.cmp_glue, mgghf_cmp, ty_params);
1771 1772
}

1773
fn declare_generic_glue(@local_ctxt cx,
1774
                        ty.t t,
1775 1776
                        TypeRef llfnty,
                        str name) -> ValueRef {
1777
    auto gcx = @rec(path=vec("glue", name) with *cx);
1778
    auto fn_nm = mangle_name_by_seq(cx.ccx, cx.path, "glue");
1779 1780
    fn_nm = sanitize(fn_nm);
    auto llfn = decl_internal_fastcall_fn(cx.ccx.llmod, fn_nm, llfnty);
1781
    ret llfn;
1782
}
1783

1784
fn make_generic_glue(@local_ctxt cx,
1785
                     ty.t t,
1786 1787 1788
                     ValueRef llfn,
                     make_generic_glue_helper_fn helper,
                     vec[uint] ty_params) -> ValueRef {
1789
    auto fcx = new_fn_ctxt(cx, llfn);
1790
    auto bcx = new_top_block_ctxt(fcx);
1791
    auto lltop = bcx.llbb;
1792

1793 1794 1795 1796
    // 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.
1797

1798
    auto llty;
1799
    if (ty.type_has_dynamic_size(cx.ccx.tcx, t)) {
1800 1801 1802 1803
        llty = T_ptr(T_i8());
    } else {
        llty = T_ptr(type_of(cx.ccx, t));
    }
1804

1805
    auto ty_param_count = _vec.len[uint](ty_params);
1806

1807
    auto lltyparams = llvm.LLVMGetParam(llfn, 3u);
1808

1809 1810 1811 1812 1813 1814 1815 1816 1817 1818
    auto lltydescs = _vec.empty_mut[ValueRef]();
    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);
        _vec.grow_set[ValueRef](lltydescs, ty_params.(p), 0 as ValueRef,
                                llparam);
        p += 1u;
    }
    bcx.fcx.lltydescs = _vec.freeze[ValueRef](lltydescs);
1819

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

1823 1824 1825 1826 1827 1828
    alt (helper) {
        case (mgghf_single(?single_fn)) {
            single_fn(bcx, llval0, t);
        }
        case (mgghf_cmp) {
            auto llrawptr1 = llvm.LLVMGetParam(llfn, 5u);
1829
            auto llval1 = bcx.build.BitCast(llrawptr1, llty);
1830

1831
            auto llcmpval = llvm.LLVMGetParam(llfn, 6u);
1832

1833
            make_cmp_glue(bcx, llval0, llval1, t, llcmpval);
1834
        }
1835
    }
1836

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

1840 1841 1842
    ret llfn;
}

1843
fn make_take_glue(@block_ctxt cx, ValueRef v, ty.t t) {
1844
    // NB: v is an *alias* of type t here, not a direct value.
1845
    auto bcx;
1846
    if (ty.type_is_boxed(cx.fcx.lcx.ccx.tcx, t)) {
1847
        bcx = incr_refcnt_of_boxed(cx, cx.build.Load(v)).bcx;
1848

1849
    } else if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, t)) {
1850 1851 1852 1853
        bcx = iter_structural_ty(cx, v, t,
                                 bind take_ty(_, _, _)).bcx;
    } else {
        bcx = cx;
1854
    }
1855
    bcx.build.RetVoid();
1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876
}

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

1877
fn make_drop_glue(@block_ctxt cx, ValueRef v0, ty.t t) {
1878
    // NB: v0 is an *alias* of type t here, not a direct value.
1879
    auto rslt;
1880
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
1881
        case (ty.ty_str) {
1882
            auto v = cx.build.Load(v0);
1883
            rslt = decr_refcnt_and_if_zero
G
Graydon Hoare 已提交
1884 1885 1886
                (cx, v, bind trans_non_gc_free(_, v),
                 "free string",
                 T_int(), C_int(0));
1887 1888
        }

1889
        case (ty.ty_vec(_)) {
G
Graydon Hoare 已提交
1890
            fn hit_zero(@block_ctxt cx, ValueRef v,
1891
                        ty.t t) -> result {
G
Graydon Hoare 已提交
1892 1893
                auto res = iter_sequence(cx, v, t,
                                         bind drop_ty(_,_,_));
1894 1895 1896
                // FIXME: switch gc/non-gc on layer of the type.
                ret trans_non_gc_free(res.bcx, v);
            }
1897
            auto v = cx.build.Load(v0);
1898 1899 1900 1901
            rslt = decr_refcnt_and_if_zero(cx, v,
                                          bind hit_zero(_, v, t),
                                          "free vector",
                                          T_int(), C_int(0));
1902 1903
        }

1904
        case (ty.ty_box(?body_mt)) {
G
Graydon Hoare 已提交
1905
            fn hit_zero(@block_ctxt cx, ValueRef v,
1906
                        ty.t body_ty) -> result {
1907 1908 1909 1910
                auto body = cx.build.GEP(v,
                                         vec(C_int(0),
                                             C_int(abi.box_rc_field_body)));

1911
                auto body_val = load_if_immediate(cx, body, body_ty);
1912 1913 1914 1915
                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);
            }
1916
            auto v = cx.build.Load(v0);
1917 1918 1919 1920
            rslt = decr_refcnt_and_if_zero(cx, v,
                                           bind hit_zero(_, v, body_mt.ty),
                                           "free box",
                                           T_int(), C_int(0));
1921 1922
        }

B
Brian Anderson 已提交
1923 1924 1925
        case (ty.ty_port(_)) {
            fn hit_zero(@block_ctxt cx, ValueRef v) -> result {
                ret trans_upcall(cx, "upcall_del_port",
1926
                                 vec(vp2i(cx, v)), true);
B
Brian Anderson 已提交
1927
            }
1928
            auto v = cx.build.Load(v0);
1929 1930 1931 1932
            rslt = decr_refcnt_and_if_zero(cx, v,
                                           bind hit_zero(_, v),
                                           "free port",
                                           T_int(), C_int(0));
B
Brian Anderson 已提交
1933 1934 1935 1936 1937
        }

        case (ty.ty_chan(_)) {
            fn hit_zero(@block_ctxt cx, ValueRef v) -> result {
                ret trans_upcall(cx, "upcall_del_chan",
1938
                                 vec(vp2i(cx, v)), true);
B
Brian Anderson 已提交
1939
            }
1940
            auto v = cx.build.Load(v0);
1941 1942 1943 1944
            rslt = decr_refcnt_and_if_zero(cx, v,
                                           bind hit_zero(_, v),
                                           "free chan",
                                           T_int(), C_int(0));
B
Brian Anderson 已提交
1945 1946
        }

1947
        case (ty.ty_obj(_)) {
1948
            fn hit_zero(@block_ctxt cx, ValueRef b, ValueRef o) -> result {
1949
                auto body =
1950
                    cx.build.GEP(b,
1951 1952 1953 1954 1955 1956
                                 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)));
1957
                auto tydesc = cx.build.Load(tydescptr);
1958

1959 1960 1961
                // FIXME: disabled for now.
                // auto cx_ = maybe_call_dtor(cx, o);
                auto cx_ = cx;
1962 1963 1964

                // Call through the obj's own fields-drop glue first.
                call_tydesc_glue_full(cx_, body, tydesc,
1965
                                      abi.tydesc_field_drop_glue);
1966 1967 1968

                // Then free the body.
                // FIXME: switch gc/non-gc on layer of the type.
1969
                ret trans_non_gc_free(cx_, b);
1970 1971
            }
            auto box_cell =
1972
                cx.build.GEP(v0,
1973 1974 1975 1976 1977
                             vec(C_int(0),
                                 C_int(abi.obj_field_box)));

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

1978
            rslt = decr_refcnt_and_if_zero(cx, boxptr,
1979
                                           bind hit_zero(_, boxptr, v0),
1980 1981
                                           "free obj",
                                           T_int(), C_int(0));
1982 1983
        }

1984
        case (ty.ty_fn(_,_,_)) {
1985 1986 1987 1988 1989 1990 1991
            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)));
1992 1993 1994 1995
                auto bindings =
                    cx.build.GEP(body,
                                 vec(C_int(0),
                                     C_int(abi.closure_elt_bindings)));
1996 1997 1998 1999 2000

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

2002
                call_tydesc_glue_full(cx, bindings, cx.build.Load(tydescptr),
2003
                                      abi.tydesc_field_drop_glue);
2004

2005 2006 2007 2008 2009 2010

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

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

2017 2018 2019 2020
            rslt = decr_refcnt_and_if_zero(cx, boxptr,
                                           bind hit_zero(_, boxptr),
                                           "free fn",
                                           T_int(), C_int(0));
2021 2022
        }

2023
        case (_) {
2024
            if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, t)) {
2025 2026
                rslt = iter_structural_ty(cx, v0, t,
                                          bind drop_ty(_, _, _));
2027

2028 2029 2030
            } 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)) {
2031
                rslt = res(cx, C_nil());
2032 2033
            } else {
                rslt = res(cx, C_nil());
2034 2035 2036
            }
        }
    }
2037 2038

    rslt.bcx.build.RetVoid();
2039 2040
}

2041 2042
fn decr_refcnt_and_if_zero(@block_ctxt cx,
                           ValueRef box_ptr,
2043
                           fn(@block_ctxt cx) -> result inner,
2044
                           str inner_name,
2045
                           TypeRef t_else, ValueRef v_else) -> result {
2046

2047
    auto load_rc_cx = new_sub_block_ctxt(cx, "load rc");
2048 2049 2050 2051
    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");

2052 2053
    auto null_test = cx.build.IsNull(box_ptr);
    cx.build.CondBr(null_test, next_cx.llbb, load_rc_cx.llbb);
2054

2055 2056 2057 2058 2059 2060 2061 2062 2063 2064

    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);
2065 2066 2067 2068

    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);
2069 2070 2071 2072
    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);
2073

2074
    auto phi = next_cx.build.Phi(t_else,
2075
                                 vec(v_else, v_else, v_else, inner_res.val),
2076
                                 vec(cx.llbb,
2077
                                     load_rc_cx.llbb,
2078
                                     rc_adj_cx.llbb,
2079 2080
                                     inner_res.bcx.llbb));

2081
    ret res(next_cx, phi);
2082 2083
}

2084 2085 2086 2087 2088
// Structural comparison: a rather involved form of glue.

fn make_cmp_glue(@block_ctxt cx,
                 ValueRef lhs0,
                 ValueRef rhs0,
2089
                 ty.t t,
2090 2091 2092 2093
                 ValueRef llop) {
    auto lhs = load_if_immediate(cx, lhs0, t);
    auto rhs = load_if_immediate(cx, rhs0, t);

2094
    if (ty.type_is_scalar(cx.fcx.lcx.ccx.tcx, t)) {
2095 2096
        make_scalar_cmp_glue(cx, lhs, rhs, t, llop);

2097
    } else if (ty.type_is_box(cx.fcx.lcx.ccx.tcx, t)) {
2098 2099 2100 2101 2102 2103 2104
        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();

2105 2106
    } else if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, t)
               || ty.type_is_sequence(cx.fcx.lcx.ccx.tcx, t)) {
2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139

        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());
        llvm.LLVMSetValueName(flag, _str.buf("flag"));

        auto r;
2140
        if (ty.type_is_sequence(cx.fcx.lcx.ccx.tcx, t)) {
2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166

            // 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,
                                                  C_i8(abi.cmp_glue_op_lt));
            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,
2167
                 ty.t t) -> result {
2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178

            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.

2179
                if (!ty.type_has_dynamic_size(last_cx.fcx.lcx.ccx.tcx, t)) {
2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200
                    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,
                                      C_i8(abi.cmp_glue_op_eq));
            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());
        }

2201
        if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, t)) {
2202 2203 2204 2205 2206 2207 2208 2209 2210
            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));
2211
            auto elt_ty = ty.sequence_element_type(cx.fcx.lcx.ccx.tcx, t);
2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227
            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],
2228
                   "attempt to compare values of type " +
2229
                   ty.ty_to_str(cx.fcx.lcx.ccx.tcx, t));
2230 2231 2232 2233
    }
}

// A helper function to create scalar comparison glue.
2234
fn make_scalar_cmp_glue(@block_ctxt cx, ValueRef lhs, ValueRef rhs, ty.t t,
2235
                        ValueRef llop) {
2236
    if (ty.type_is_fp(cx.fcx.lcx.ccx.tcx, t)) {
2237 2238 2239 2240
        make_fp_cmp_glue(cx, lhs, rhs, t, llop);
        ret;
    }

2241 2242
    if (ty.type_is_integral(cx.fcx.lcx.ccx.tcx, t) ||
            ty.type_is_bool(cx.fcx.lcx.ccx.tcx, t)) {
2243 2244 2245 2246
        make_integral_cmp_glue(cx, lhs, rhs, t, llop);
        ret;
    }

2247
    if (ty.type_is_nil(cx.fcx.lcx.ccx.tcx, t)) {
2248 2249 2250 2251 2252 2253
        cx.build.Store(C_bool(true), cx.fcx.llretptr);
        cx.build.RetVoid();
        ret;
    }

    trans_fail(cx, none[common.span],
2254
               "attempt to compare values of type " +
2255
               ty.ty_to_str(cx.fcx.lcx.ccx.tcx, t));
2256 2257 2258
}

// A helper function to create floating point comparison glue.
2259
fn make_fp_cmp_glue(@block_ctxt cx, ValueRef lhs, ValueRef rhs, ty.t fptype,
2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332
                    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);
    llvm.LLVMAddCase(llswitch, C_i8(abi.cmp_glue_op_eq), eq_cx.llbb);
    llvm.LLVMAddCase(llswitch, C_i8(abi.cmp_glue_op_lt), lt_cx.llbb);
    llvm.LLVMAddCase(llswitch, C_i8(abi.cmp_glue_op_le), le_cx.llbb);

    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);
    llvm.LLVMAddCase(llswitch, C_i8(abi.cmp_glue_op_eq), eq_cx.llbb);
    llvm.LLVMAddCase(llswitch, C_i8(abi.cmp_glue_op_lt), lt_cx.llbb);
    llvm.LLVMAddCase(llswitch, C_i8(abi.cmp_glue_op_le), le_cx.llbb);

    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,
2333
                          ty.t intype, ValueRef llop) {
2334
    auto r = compare_integral_values(cx, lhs, rhs,
2335
        ty.type_is_signed(cx.fcx.lcx.ccx.tcx, intype), llop);
2336 2337
    r.bcx.build.Store(r.val, r.bcx.fcx.llretptr);
    r.bcx.build.RetVoid();
2338 2339 2340
}


2341 2342
// Tag information

2343
type variant_info = rec(vec[ty.t] args, ty.t ctor_ty, ast.def_id id);
2344 2345 2346

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

2351
    check (cx.items.contains_key(id));
2352
    alt (cx.items.get(id).node) {
2353 2354 2355 2356
        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);
2357
                let vec[ty.t] arg_tys = vec();
2358
                if (_vec.len[ast.variant_arg](variant.node.args) > 0u) {
2359
                    for (ty.arg a in ty.ty_fn_args(cx.tcx, ctor_ty)) {
2360 2361 2362 2363 2364 2365 2366 2367
                        arg_tys += vec(a.ty);
                    }
                }
                auto did = variant.node.id;
                result += vec(rec(args=arg_tys, ctor_ty=ctor_ty, id=did));
            }
            ret result;
        }
2368 2369 2370 2371
    }
    fail;   // not reached
}

2372
// Returns information about the tag variant with the given ID.
2373 2374
fn tag_variant_with_id(@crate_ctxt cx,
                       &ast.def_id tag_id,
2375
                       &ast.def_id variant_id) -> variant_info {
2376 2377 2378
    auto variants = tag_variants(cx, tag_id);

    auto i = 0u;
2379
    while (i < _vec.len[variant_info](variants)) {
2380
        auto variant = variants.(i);
2381
        if (common.def_eq(variant.id, variant_id)) {
2382 2383 2384 2385 2386
            ret variant;
        }
        i += 1u;
    }

2387
    log_err "tag_variant_with_id(): no variant exists with that ID";
2388 2389 2390
    fail;
}

2391

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

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

2396
type val_pair_and_ty_fn =
2397
    fn(@block_ctxt cx, ValueRef av, ValueRef bv, ty.t t) -> result;
2398

2399
// Iterates through the elements of a structural type.
2400 2401
fn iter_structural_ty(@block_ctxt cx,
                      ValueRef v,
2402
                      ty.t t,
2403 2404
                      val_and_ty_fn f)
    -> result {
2405 2406 2407 2408
    fn adaptor_fn(val_and_ty_fn f,
                  @block_ctxt cx,
                  ValueRef av,
                  ValueRef bv,
2409
                  ty.t t) -> result {
2410 2411 2412 2413 2414 2415 2416 2417 2418 2419
        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,
2420
                           ty.t t,
2421 2422
                           val_pair_and_ty_fn f)
    -> result {
2423
    let result r = res(cx, C_nil());
2424

2425
    fn iter_boxpp(@block_ctxt cx,
2426 2427 2428 2429 2430
                  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);
2431 2432
        auto tnil = ty.mk_nil(cx.fcx.lcx.ccx.tcx);
        auto tbox = ty.mk_imm_box(cx.fcx.lcx.ccx.tcx, tnil);
2433 2434 2435

        auto inner_cx = new_sub_block_ctxt(cx, "iter box");
        auto next_cx = new_sub_block_ctxt(cx, "next");
2436
        auto null_test = cx.build.IsNull(box_a_ptr);
2437 2438
        cx.build.CondBr(null_test, next_cx.llbb, inner_cx.llbb);

2439
        auto r = f(inner_cx, box_a_ptr, box_b_ptr, tbox);
2440
        r.bcx.build.Br(next_cx.llbb);
2441
        ret res(next_cx, C_nil());
2442 2443
    }

2444
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
2445
        case (ty.ty_tup(?args)) {
2446
            let int i = 0;
2447
            for (ty.mt arg in args) {
2448 2449 2450 2451
                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;
2452
                r = f(r.bcx,
2453 2454
                      load_if_immediate(r.bcx, elt_a, arg.ty),
                      load_if_immediate(r.bcx, elt_b, arg.ty),
2455
                      arg.ty);
2456 2457 2458
                i += 1;
            }
        }
2459
        case (ty.ty_rec(?fields)) {
2460
            let int i = 0;
2461
            for (ty.field fld in fields) {
2462 2463 2464 2465
                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;
2466
                r = f(r.bcx,
2467 2468
                      load_if_immediate(r.bcx, llfld_a, fld.mt.ty),
                      load_if_immediate(r.bcx, llfld_b, fld.mt.ty),
2469
                      fld.mt.ty);
2470 2471 2472
                i += 1;
            }
        }
2473
        case (ty.ty_tag(?tid, ?tps)) {
2474
            auto variants = tag_variants(cx.fcx.lcx.ccx, tid);
2475
            auto n_variants = _vec.len[variant_info](variants);
2476

2477
            // Cast the tags to types we can GEP into.
2478
            auto lltagty = T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn);
2479 2480 2481 2482 2483 2484 2485
            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)));
2486 2487
            auto lldiscrim_a = cx.build.Load(lldiscrim_a_ptr);

2488 2489 2490 2491
            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)));
2492
            auto lldiscrim_b = cx.build.Load(lldiscrim_b_ptr);
G
Graydon Hoare 已提交
2493

2494 2495 2496
            // NB: we must hit the discriminant first so that structural
            // comparison know not to proceed when the discriminants differ.
            auto bcx = cx;
2497
            bcx = f(bcx, lldiscrim_a, lldiscrim_b,
2498
                    ty.mk_int(cx.fcx.lcx.ccx.tcx)).bcx;
2499 2500

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

2503
            auto llswitch = bcx.build.Switch(lldiscrim_a, unr_cx.llbb,
2504
                                             n_variants);
G
Graydon Hoare 已提交
2505

2506
            auto next_cx = new_sub_block_ctxt(bcx, "tag-iter-next");
2507 2508

            auto i = 0u;
2509
            for (variant_info variant in variants) {
2510
                auto variant_cx = new_sub_block_ctxt(bcx,
2511
                                                     "tag-iter-variant-" +
2512 2513 2514
                                                     _uint.to_str(i, 10u));
                llvm.LLVMAddCase(llswitch, C_int(i as int), variant_cx.llbb);

2515
                if (_vec.len[ty.t](variant.args) > 0u) {
2516
                    // N-ary variant.
2517
                    auto fn_ty = variant.ctor_ty;
2518
                    alt (ty.struct(bcx.fcx.lcx.ccx.tcx, fn_ty)) {
2519
                        case (ty.ty_fn(_, ?args, _)) {
2520
                            auto j = 0;
2521 2522
                            for (ty.arg a in args) {
                                auto v = vec(C_int(0), C_int(j as int));
2523

2524
                                auto rslt = GEP_tag(variant_cx, llunion_a_ptr,
2525
                                    tid, variant.id, tps, j);
2526 2527
                                auto llfldp_a = rslt.val;
                                variant_cx = rslt.bcx;
2528

2529
                                rslt = GEP_tag(variant_cx, llunion_b_ptr, tid,
2530
                                    variant.id, tps, j);
2531 2532
                                auto llfldp_b = rslt.val;
                                variant_cx = rslt.bcx;
2533

2534
                                auto ty_subst = ty.bind_params_in_type(
2535
                                    cx.fcx.lcx.ccx.tcx, a.ty);
2536
                                ty_subst = ty.substitute_type_params(
2537
                                    cx.fcx.lcx.ccx.tcx, tps, ty_subst);
2538

2539
                                auto llfld_a =
2540
                                    load_if_immediate(variant_cx,
2541
                                                         llfldp_a,
2542 2543
                                                         ty_subst);

2544
                                auto llfld_b =
2545
                                    load_if_immediate(variant_cx,
2546 2547 2548 2549 2550
                                                         llfldp_b,
                                                         ty_subst);

                                auto res = f(variant_cx,
                                             llfld_a, llfld_b, ty_subst);
2551
                                variant_cx = res.bcx;
2552
                                j += 1;
2553 2554
                            }
                        }
2555
                        case (_) { fail; }
2556
                    }
2557 2558 2559 2560 2561

                    variant_cx.build.Br(next_cx.llbb);
                } else {
                    // Nullary variant; nothing to do.
                    variant_cx.build.Br(next_cx.llbb);
2562 2563 2564 2565 2566 2567 2568
                }

                i += 1u;
            }

            ret res(next_cx, C_nil());
        }
2569
        case (ty.ty_fn(_,_,_)) {
2570 2571 2572 2573 2574 2575
            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,
2576 2577
                             vec(C_int(0),
                                 C_int(abi.fn_field_box)));
2578
            ret iter_boxpp(cx, box_cell_a, box_cell_b, f);
2579
        }
2580
        case (ty.ty_obj(_)) {
2581 2582 2583 2584 2585 2586
            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,
2587 2588
                             vec(C_int(0),
                                 C_int(abi.obj_field_box)));
2589
            ret iter_boxpp(cx, box_cell_a, box_cell_b, f);
2590
        }
2591
        case (_) {
2592
            cx.fcx.lcx.ccx.sess.unimpl("type in iter_structural_ty_full");
2593
        }
2594
    }
2595
    ret r;
2596 2597
}

2598 2599
// Iterates through a pointer range, until the src* hits the src_lim*.
fn iter_sequence_raw(@block_ctxt cx,
2600
                     ValueRef dst,     // elt*
2601 2602 2603
                     ValueRef src,     // elt*
                     ValueRef src_lim, // elt*
                     ValueRef elt_sz,
2604
                     val_pair_fn f) -> result {
2605 2606 2607

    auto bcx = cx;

2608
    let ValueRef dst_int = vp2i(bcx, dst);
2609 2610 2611 2612 2613 2614 2615 2616 2617
    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);

2618 2619
    let ValueRef dst_curr = cond_cx.build.Phi(T_int(),
                                              vec(dst_int), vec(bcx.llbb));
2620 2621 2622
    let ValueRef src_curr = cond_cx.build.Phi(T_int(),
                                              vec(src_int), vec(bcx.llbb));

2623
    auto end_test = cond_cx.build.ICmp(lib.llvm.LLVMIntULT,
2624 2625 2626 2627
                                       src_curr, src_lim_int);

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

2628
    auto dst_curr_ptr = vi2p(body_cx, dst_curr, T_ptr(T_i8()));
2629
    auto src_curr_ptr = vi2p(body_cx, src_curr, T_ptr(T_i8()));
2630

2631
    auto body_res = f(body_cx, dst_curr_ptr, src_curr_ptr);
2632 2633
    body_cx = body_res.bcx;

2634
    auto dst_next = body_cx.build.Add(dst_curr, elt_sz);
2635
    auto src_next = body_cx.build.Add(src_curr, elt_sz);
2636 2637
    body_cx.build.Br(cond_cx.llbb);

2638 2639
    cond_cx.build.AddIncomingToPhi(dst_curr, vec(dst_next),
                                   vec(body_cx.llbb));
2640 2641 2642 2643 2644 2645 2646 2647 2648 2649
    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*
2650
                       ty.t elt_ty,
2651 2652
                       val_and_ty_fn f) -> result {
    fn adaptor_fn(val_and_ty_fn f,
2653
                  ty.t elt_ty,
2654
                  @block_ctxt cx,
2655 2656
                  ValueRef dst,
                  ValueRef src) -> result {
2657
        auto llptrty;
2658
        if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, elt_ty)) {
2659
            auto llty = type_of(cx.fcx.lcx.ccx, elt_ty);
2660 2661 2662 2663 2664 2665
            llptrty = T_ptr(llty);
        } else {
            llptrty = T_ptr(T_ptr(T_i8()));
        }

        auto p = cx.build.PointerCast(src, llptrty);
2666
        ret f(cx, load_if_immediate(cx, p, elt_ty), elt_ty);
2667 2668
    }

2669
    auto elt_sz = size_of(cx, elt_ty);
2670 2671
    be iter_sequence_raw(elt_sz.bcx, src, src, src_lim, elt_sz.val,
                         bind adaptor_fn(f, elt_ty, _, _, _));
2672 2673 2674
}


2675 2676 2677
// Iterates through the elements of a vec or str.
fn iter_sequence(@block_ctxt cx,
                 ValueRef v,
2678
                 ty.t t,
2679 2680 2681 2682
                 val_and_ty_fn f) -> result {

    fn iter_sequence_body(@block_ctxt cx,
                          ValueRef v,
2683
                          ty.t elt_ty,
2684 2685 2686 2687 2688 2689 2690
                          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)));
2691

2692
        auto llunit_ty;
2693
        if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, elt_ty)) {
2694 2695
            llunit_ty = T_i8();
        } else {
2696
            llunit_ty = type_of(cx.fcx.lcx.ccx, elt_ty);
2697 2698
        }

2699
        auto bcx = cx;
2700

2701
        auto len = bcx.build.Load(lenptr);
2702
        if (trailing_null) {
2703 2704
            auto unit_sz = size_of(bcx, elt_ty);
            bcx = unit_sz.bcx;
2705
            len = bcx.build.Sub(len, unit_sz.val);
2706 2707
        }

2708 2709
        auto p1 = vi2p(bcx, bcx.build.Add(vp2i(bcx, p0), len),
                       T_ptr(llunit_ty));
2710

2711
        ret iter_sequence_inner(bcx, p0, p1, elt_ty, f);
2712 2713
    }

2714
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
2715 2716
        case (ty.ty_vec(?elt)) {
            ret iter_sequence_body(cx, v, elt.ty, f, false);
2717
        }
2718
        case (ty.ty_str) {
2719
            auto et = ty.mk_mach(cx.fcx.lcx.ccx.tcx, common.ty_u8);
2720
            ret iter_sequence_body(cx, v, et, f, true);
2721
        }
2722
        case (_) { fail; }
2723
    }
2724
    cx.fcx.lcx.ccx.sess.bug("bad type in trans.iter_sequence");
2725 2726 2727
    fail;
}

2728 2729 2730 2731 2732 2733 2734 2735 2736
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);
2737

2738 2739 2740 2741 2742
    cx.build.FastCall(llfn, vec(C_null(T_ptr(T_nil())),
                                cx.fcx.lltaskptr,
                                C_null(T_ptr(T_nil())),
                                lltydescs,
                                llrawptr));
2743 2744
}

2745
fn call_tydesc_glue(@block_ctxt cx, ValueRef v,
2746 2747
                    ty.t t, bool escapes, int field) -> result {
    auto td = get_tydesc(cx, t, escapes);
2748 2749 2750
    call_tydesc_glue_full(td.bcx,
                          spill_if_immediate(td.bcx, v, t),
                          td.val, field);
2751
    ret res(td.bcx, C_nil());
2752 2753
}

2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774
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);
    dtor_ptr = cx.build.BitCast(dtor_ptr,
                                T_ptr(T_dtor(cx.fcx.lcx.ccx, val_ty(v))));
    
    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);

    // FIXME need to pass type params (?)
    dtor_cx.build.FastCall(dtor_ptr, vec(C_null(T_ptr(T_nil())),
                                        cx.fcx.lltaskptr, v));
    dtor_cx.build.Br(after_cx.llbb);
    ret after_cx;
}

2775 2776 2777 2778
fn call_cmp_glue(@block_ctxt cx,
                 ValueRef lhs,
                 ValueRef rhs,
                 ty.t t,
2779 2780 2781 2782 2783 2784 2785 2786 2787 2788
                 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()));

2789
    auto r = get_tydesc(cx, t, false);
2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813
    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));
}

2814
fn take_ty(@block_ctxt cx, ValueRef v, ty.t t) -> result {
2815
    if (!ty.type_is_scalar(cx.fcx.lcx.ccx.tcx, t)) {
2816
        ret call_tydesc_glue(cx, v, t, false, abi.tydesc_field_take_glue);
2817
    }
2818
    ret res(cx, C_nil());
2819 2820
}

2821 2822
fn drop_slot(@block_ctxt cx,
             ValueRef slot,
2823
             ty.t t) -> result {
2824
    auto llptr = load_if_immediate(cx, slot, t);
2825 2826 2827 2828 2829 2830
    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;
2831 2832
}

2833 2834
fn drop_ty(@block_ctxt cx,
           ValueRef v,
2835
           ty.t t) -> result {
2836

2837
    if (!ty.type_is_scalar(cx.fcx.lcx.ccx.tcx, t)) {
2838
        ret call_tydesc_glue(cx, v, t, false, abi.tydesc_field_drop_glue);
2839
    }
2840
    ret res(cx, C_nil());
2841 2842
}

2843 2844 2845 2846
fn call_memcpy(@block_ctxt cx,
               ValueRef dst,
               ValueRef src,
               ValueRef n_bytes) -> result {
2847 2848
    auto src_ptr = cx.build.PointerCast(src, T_ptr(T_i8()));
    auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
2849
    auto size = cx.build.IntCast(n_bytes, T_int());
2850
    ret res(cx, cx.build.FastCall(cx.fcx.lcx.ccx.glues.memcpy_glue,
2851
                                  vec(dst_ptr, src_ptr, size)));
2852 2853
}

2854 2855 2856 2857 2858
fn call_bzero(@block_ctxt cx,
              ValueRef dst,
              ValueRef n_bytes) -> result {
    auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
    auto size = cx.build.IntCast(n_bytes, T_int());
2859
    ret res(cx, cx.build.FastCall(cx.fcx.lcx.ccx.glues.bzero_glue,
2860 2861 2862
                                  vec(dst_ptr, size)));
}

2863 2864 2865
fn memcpy_ty(@block_ctxt cx,
             ValueRef dst,
             ValueRef src,
2866
             ty.t t) -> result {
2867
    if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
2868
        auto llszptr = field_of_tydesc(cx, t, false, abi.tydesc_field_size);
2869 2870
        auto llsz = llszptr.bcx.build.Load(llszptr.val);
        ret call_memcpy(llszptr.bcx, dst, src, llsz);
2871 2872 2873 2874 2875 2876

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

2877 2878 2879 2880 2881
tag copy_action {
    INIT;
    DROP_EXISTING;
}

2882
fn copy_ty(@block_ctxt cx,
2883
           copy_action action,
2884 2885
           ValueRef dst,
           ValueRef src,
2886
           ty.t t) -> result {
2887 2888
    if (ty.type_is_scalar(cx.fcx.lcx.ccx.tcx, t) ||
            ty.type_is_native(cx.fcx.lcx.ccx.tcx, t)) {
2889 2890
        ret res(cx, cx.build.Store(src, dst));

2891
    } else if (ty.type_is_nil(cx.fcx.lcx.ccx.tcx, t)) {
2892 2893
        ret res(cx, C_nil());

2894
    } else if (ty.type_is_boxed(cx.fcx.lcx.ccx.tcx, t)) {
2895
        auto r = take_ty(cx, src, t);
2896
        if (action == DROP_EXISTING) {
2897
            r = drop_ty(r.bcx, r.bcx.build.Load(dst), t);
2898 2899 2900
        }
        ret res(r.bcx, r.bcx.build.Store(src, dst));

2901 2902
    } else if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, t) ||
               ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
2903
        auto r = take_ty(cx, src, t);
2904
        if (action == DROP_EXISTING) {
2905 2906
            r = drop_ty(r.bcx, dst, t);
        }
2907
        ret memcpy_ty(r.bcx, dst, src, t);
2908 2909
    }

2910
    cx.fcx.lcx.ccx.sess.bug("unexpected type in trans.copy_ty: " +
2911
                        ty.ty_to_str(cx.fcx.lcx.ccx.tcx, t));
2912 2913 2914
    fail;
}

2915
fn trans_lit(@crate_ctxt cx, &ast.lit lit, &ast.ann ann) -> ValueRef {
2916
    alt (lit.node) {
2917
        case (ast.lit_int(?i)) {
2918
            ret C_int(i);
2919 2920
        }
        case (ast.lit_uint(?u)) {
2921
            ret C_int(u as int);
2922
        }
2923 2924 2925 2926 2927 2928
        case (ast.lit_mach_int(?tm, ?i)) {
            // FIXME: the entire handling of mach types falls apart
            // if target int width is larger than host, at the moment;
            // re-do the mach-int types using 'big' when that works.
            auto t = T_int();
            alt (tm) {
G
Graydon Hoare 已提交
2929 2930 2931 2932 2933 2934 2935 2936 2937
                case (common.ty_u8) { t = T_i8(); }
                case (common.ty_u16) { t = T_i16(); }
                case (common.ty_u32) { t = T_i32(); }
                case (common.ty_u64) { t = T_i64(); }

                case (common.ty_i8) { t = T_i8(); }
                case (common.ty_i16) { t = T_i16(); }
                case (common.ty_i32) { t = T_i32(); }
                case (common.ty_i64) { t = T_i64(); }
2938
            }
2939
            ret C_integral(i, t);
2940
        }
2941 2942 2943
        case(ast.lit_float(?fs)) {
            ret C_float(fs);
        }
2944 2945 2946 2947 2948 2949 2950 2951
        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);
        }
2952
        case (ast.lit_char(?c)) {
2953
            ret C_integral(c as int, T_char());
2954 2955
        }
        case (ast.lit_bool(?b)) {
2956
            ret C_bool(b);
2957 2958
        }
        case (ast.lit_nil) {
2959
            ret C_nil();
2960 2961
        }
        case (ast.lit_str(?s)) {
2962
            ret C_str(cx, s);
2963 2964 2965 2966
        }
    }
}

2967
fn target_type(@crate_ctxt cx, ty.t t) -> ty.t {
2968
    alt (ty.struct(cx.tcx, t)) {
2969
        case (ty.ty_int) {
2970
            auto struct_ty = ty.mk_mach(cx.tcx,
2971
                                        cx.sess.get_targ_cfg().int_type);
2972
            ret ty.copy_cname(cx.tcx, struct_ty, t);
2973
        }
2974
        case (ty.ty_uint) {
2975
            auto struct_ty = ty.mk_mach(cx.tcx,
2976
                                        cx.sess.get_targ_cfg().uint_type);
2977
            ret ty.copy_cname(cx.tcx, struct_ty, t);
2978
        }
2979
        case (_) { /* fall through */ }
2980 2981 2982 2983
    }
    ret t;
}

2984 2985

// Converts an annotation to a type
2986
fn node_ann_type(@crate_ctxt cx, &ast.ann a) -> ty.t {
2987
    ret target_type(cx, ty.ann_to_monotype(cx.tcx, a));
2988 2989
}

2990
fn node_ann_ty_params(&ast.ann a) -> vec[ty.t] {
2991 2992
    alt (a) {
        case (ast.ann_none) {
2993
            log_err "missing type annotation";
2994 2995
            fail;
        }
2996
        case (ast.ann_type(_, ?tps_opt, _)) {
2997
            alt (tps_opt) {
2998
                case (none[vec[ty.t]]) {
2999
                    log_err "type annotation has no ty params";
3000 3001
                    fail;
                }
3002
                case (some[vec[ty.t]](?tps)) { ret tps; }
3003 3004 3005 3006 3007
            }
        }
    }
}

3008 3009 3010 3011
fn node_type(@crate_ctxt cx, &ast.ann a) -> TypeRef {
    ret type_of(cx, node_ann_type(cx, a));
}

3012 3013
fn trans_unary(@block_ctxt cx, ast.unop op,
               @ast.expr e, &ast.ann a) -> result {
3014 3015

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

3018 3019
    alt (op) {
        case (ast.bitnot) {
3020
            sub = autoderef(sub.bcx, sub.val,
3021
                            ty.expr_ty(cx.fcx.lcx.ccx.tcx, e));
3022
            ret res(sub.bcx, sub.bcx.build.Not(sub.val));
3023 3024
        }
        case (ast.not) {
3025
            sub = autoderef(sub.bcx, sub.val,
3026
                            ty.expr_ty(cx.fcx.lcx.ccx.tcx, e));
3027
            ret res(sub.bcx, sub.bcx.build.Not(sub.val));
3028 3029
        }
        case (ast.neg) {
3030
            sub = autoderef(sub.bcx, sub.val,
3031 3032
                            ty.expr_ty(cx.fcx.lcx.ccx.tcx, e));
            if(ty.struct(cx.fcx.lcx.ccx.tcx, e_ty) == ty.ty_float) {
3033 3034 3035 3036 3037
                ret res(sub.bcx, sub.bcx.build.FNeg(sub.val));
            }
            else {
                ret res(sub.bcx, sub.bcx.build.Neg(sub.val));
            }
3038
        }
3039
        case (ast.box(_)) {
3040
            auto e_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, e);
3041
            auto e_val = sub.val;
3042
            auto box_ty = node_ann_type(sub.bcx.fcx.lcx.ccx, a);
3043 3044
            sub = trans_malloc_boxed(sub.bcx, e_ty);
            find_scope_cx(cx).cleanups +=
3045
                vec(clean(bind drop_ty(_, sub.val, box_ty)));
3046

3047 3048
            auto box = sub.val;
            auto rc = sub.bcx.build.GEP(box,
3049 3050
                                        vec(C_int(0),
                                            C_int(abi.box_rc_field_refcnt)));
3051 3052 3053 3054
            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);
3055 3056 3057 3058

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

3064
            sub = copy_ty(sub.bcx, INIT, body, e_val, e_ty);
3065
            ret res(sub.bcx, box);
3066
        }
3067
        case (ast.deref) {
3068
            log_err "deref expressions should have been translated using " +
3069 3070
                "trans_lval(), not trans_unary()";
            fail;
3071
        }
3072 3073 3074 3075
    }
    fail;
}

3076
fn trans_compare(@block_ctxt cx0, ast.binop op, ty.t t0,
3077
                 ValueRef lhs0, ValueRef rhs0) -> result {
3078
    // Autoderef both sides.
3079 3080 3081 3082 3083 3084 3085 3086 3087 3088
    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;

3089
    auto t = autoderefed_ty(cx.fcx.lcx.ccx, t0);
3090

3091 3092 3093
    // Determine the operation we need.
    // FIXME: Use or-patterns when we have them.
    auto llop;
3094
    alt (op) {
3095 3096 3097 3098 3099 3100
        case (ast.eq) { llop = C_i8(abi.cmp_glue_op_eq); }
        case (ast.lt) { llop = C_i8(abi.cmp_glue_op_lt); }
        case (ast.le) { llop = C_i8(abi.cmp_glue_op_le); }
        case (ast.ne) { llop = C_i8(abi.cmp_glue_op_eq); }
        case (ast.ge) { llop = C_i8(abi.cmp_glue_op_lt); }
        case (ast.gt) { llop = C_i8(abi.cmp_glue_op_le); }
3101 3102
    }

3103
    auto rslt = call_cmp_glue(cx, lhs, rhs, t, llop);
3104

3105 3106
    // Invert the result if necessary.
    // FIXME: Use or-patterns when we have them.
3107
    alt (op) {
3108 3109 3110 3111 3112 3113
        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)); }
3114 3115 3116
    }
}

3117
fn trans_vec_append(@block_ctxt cx, ty.t t,
3118 3119
                    ValueRef lhs, ValueRef rhs) -> result {

3120
    auto elt_ty = ty.sequence_element_type(cx.fcx.lcx.ccx.tcx, t);
3121 3122

    auto skip_null = C_bool(false);
3123
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
3124 3125 3126 3127 3128 3129
        case (ty.ty_str) { skip_null = C_bool(true); }
        case (_) { }
    }

    auto bcx = cx;

3130
    auto llvec_tydesc = get_tydesc(bcx, t, false);
3131 3132
    bcx = llvec_tydesc.bcx;

3133
    auto llelt_tydesc = get_tydesc(bcx, elt_ty, false);
3134 3135
    bcx = llelt_tydesc.bcx;

3136 3137 3138
    auto dst = bcx.build.PointerCast(lhs, T_ptr(T_opaque_vec_ptr()));
    auto src = bcx.build.PointerCast(rhs, T_opaque_vec_ptr());

3139
    ret res(bcx, bcx.build.FastCall(cx.fcx.lcx.ccx.glues.vec_append_glue,
3140 3141 3142 3143
                                    vec(cx.fcx.lltaskptr,
                                        llvec_tydesc.val,
                                        llelt_tydesc.val,
                                        dst, src, skip_null)));
3144 3145
}

3146
fn trans_vec_add(@block_ctxt cx, ty.t t,
3147
                 ValueRef lhs, ValueRef rhs) -> result {
3148
    auto r = alloc_ty(cx, t);
3149 3150
    auto tmp = r.val;
    r = copy_ty(r.bcx, INIT, tmp, lhs, t);
3151
    auto bcx = trans_vec_append(r.bcx, t, tmp, rhs).bcx;
3152
    tmp = load_if_immediate(bcx, tmp, t);
3153 3154
    find_scope_cx(cx).cleanups +=
        vec(clean(bind drop_ty(_, tmp, t)));
3155
    ret res(bcx, tmp);
3156 3157 3158
}


3159
fn trans_eager_binop(@block_ctxt cx, ast.binop op, ty.t intype,
3160
                     ValueRef lhs, ValueRef rhs) -> result {
3161

3162
    auto is_float = false;
3163
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, intype)) {
3164 3165 3166 3167 3168 3169 3170
        case (ty.ty_float) {
            is_float = true;
        }
        case (_) {
            is_float = false;
        }
    }
3171

3172
    alt (op) {
3173
        case (ast.add) {
3174
            if (ty.type_is_sequence(cx.fcx.lcx.ccx.tcx, intype)) {
3175
                ret trans_vec_add(cx, intype, lhs, rhs);
3176
            }
3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192
            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));
            }
        }

3193
        case (ast.mul) {
3194 3195 3196 3197 3198 3199
            if (is_float) {
                ret res(cx, cx.build.FMul(lhs, rhs));
            }
            else {
                ret res(cx, cx.build.Mul(lhs, rhs));
            }
3200
        }
3201

3202
        case (ast.div) {
3203 3204 3205
            if (is_float) {
                ret res(cx, cx.build.FDiv(lhs, rhs));
            }
3206
            if (ty.type_is_signed(cx.fcx.lcx.ccx.tcx, intype)) {
3207
                ret res(cx, cx.build.SDiv(lhs, rhs));
3208
            } else {
3209
                ret res(cx, cx.build.UDiv(lhs, rhs));
3210 3211 3212
            }
        }
        case (ast.rem) {
3213 3214 3215
            if (is_float) {
                ret res(cx, cx.build.FRem(lhs, rhs));
            }
3216
            if (ty.type_is_signed(cx.fcx.lcx.ccx.tcx, intype)) {
3217
                ret res(cx, cx.build.SRem(lhs, rhs));
3218
            } else {
3219
                ret res(cx, cx.build.URem(lhs, rhs));
3220 3221
            }
        }
3222

3223 3224 3225 3226 3227 3228
        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)); }
3229
        case (_) {
3230
            ret trans_compare(cx, op, intype, lhs, rhs);
3231 3232 3233 3234 3235
        }
    }
    fail;
}

3236
fn autoderef(@block_ctxt cx, ValueRef v, ty.t t) -> result {
3237
    let ValueRef v1 = v;
3238
    let ty.t t1 = t;
3239 3240

    while (true) {
3241
        alt (ty.struct(cx.fcx.lcx.ccx.tcx, t1)) {
3242
            case (ty.ty_box(?mt)) {
3243 3244 3245
                auto body = cx.build.GEP(v1,
                                         vec(C_int(0),
                                             C_int(abi.box_rc_field_body)));
3246
                t1 = mt.ty;
3247 3248 3249 3250 3251

                // 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.
3252
                if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, mt.ty)) {
3253
                    auto llty = type_of(cx.fcx.lcx.ccx, mt.ty);
3254 3255 3256 3257 3258
                    v1 = cx.build.PointerCast(body, T_ptr(llty));
                } else {
                    v1 = body;
                }

3259
                v1 = load_if_immediate(cx, v1, t1);
3260 3261 3262 3263 3264 3265 3266 3267
            }
            case (_) {
                ret res(cx, v1);
            }
        }
    }
}

3268
fn autoderefed_ty(@crate_ctxt ccx, ty.t t) -> ty.t {
3269
    let ty.t t1 = t;
3270 3271

    while (true) {
3272
        alt (ty.struct(ccx.tcx, t1)) {
3273 3274
            case (ty.ty_box(?mt)) {
                t1 = mt.ty;
3275 3276 3277 3278 3279 3280 3281 3282
            }
            case (_) {
                ret t1;
            }
        }
    }
}

3283 3284
fn trans_binary(@block_ctxt cx, ast.binop op,
                @ast.expr a, @ast.expr b) -> result {
3285

3286 3287 3288 3289 3290 3291
    // First couple cases are lazy:

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

3295
            auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
3296
            auto rhs_res = trans_expr(rhs_cx, b);
3297
            rhs_res = autoderef(rhs_res.bcx, rhs_res.val,
3298
                                ty.expr_ty(cx.fcx.lcx.ccx.tcx, b));
3299

3300
            auto lhs_false_cx = new_scope_block_ctxt(cx, "lhs false");
3301
            auto lhs_false_res = res(lhs_false_cx, C_bool(false));
3302 3303 3304

            lhs_res.bcx.build.CondBr(lhs_res.val,
                                     rhs_cx.llbb,
3305 3306 3307 3308
                                     lhs_false_cx.llbb);

            ret join_results(cx, T_bool(),
                             vec(lhs_false_res, rhs_res));
3309 3310 3311 3312 3313
        }

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

3317
            auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
3318
            auto rhs_res = trans_expr(rhs_cx, b);
3319
            rhs_res = autoderef(rhs_res.bcx, rhs_res.val,
3320
                                ty.expr_ty(cx.fcx.lcx.ccx.tcx, b));
3321

3322
            auto lhs_true_cx = new_scope_block_ctxt(cx, "lhs true");
3323
            auto lhs_true_res = res(lhs_true_cx, C_bool(true));
3324 3325

            lhs_res.bcx.build.CondBr(lhs_res.val,
3326
                                     lhs_true_cx.llbb,
3327
                                     rhs_cx.llbb);
3328 3329 3330

            ret join_results(cx, T_bool(),
                             vec(lhs_true_res, rhs_res));
3331
        }
3332 3333

        case (_) {
3334 3335
            // Remaining cases are eager:
            auto lhs = trans_expr(cx, a);
3336
            auto lhty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, a);
3337
            lhs = autoderef(lhs.bcx, lhs.val, lhty);
3338
            auto rhs = trans_expr(lhs.bcx, b);
3339
            auto rhty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, b);
3340
            rhs = autoderef(rhs.bcx, rhs.val, rhty);
3341
            ret trans_eager_binop(rhs.bcx, op,
3342
                autoderefed_ty(cx.fcx.lcx.ccx, lhty), lhs.val, rhs.val);
3343
        }
3344 3345 3346 3347
    }
    fail;
}

3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358
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)) {
3359 3360 3361
            live += vec(r);
            vals += vec(r.val);
            bbs += vec(r.bcx.llbb);
3362 3363 3364 3365 3366 3367 3368 3369
        }
    }

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

3374
        case (_) { /* fall through */ }
3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385
    }

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

3386
fn trans_if(@block_ctxt cx, @ast.expr cond,
3387
            &ast.block thn, &option.t[@ast.expr] els) -> result {
3388 3389 3390

    auto cond_res = trans_expr(cx, cond);

3391
    auto then_cx = new_scope_block_ctxt(cx, "then");
3392 3393
    auto then_res = trans_block(then_cx, thn);

3394
    auto else_cx = new_scope_block_ctxt(cx, "else");
3395

3396 3397
    auto else_res;
    auto expr_llty;
3398
    alt (els) {
3399
        case (some[@ast.expr](?elexpr)) {
3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411
            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);
                }
            }
3412 3413 3414

            // If we have an else expression, then the entire
            // if expression can have a non-nil type.
3415
            // FIXME: This isn't quite right, particularly re: dynamic types
3416 3417
            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)) {
3418
                expr_llty = T_typaram_ptr(cx.fcx.lcx.ccx.tn);
3419
            } else {
3420
                expr_llty = type_of(else_res.bcx.fcx.lcx.ccx, expr_ty);
3421
                if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, expr_ty)) {
3422 3423
                    expr_llty = T_ptr(expr_llty);
                }
3424
            }
3425 3426 3427 3428
        }
        case (_) {
            else_res = res(else_cx, C_nil());
            expr_llty = T_nil();
3429 3430 3431
        }
    }

3432
    cond_res.bcx.build.CondBr(cond_res.val,
3433 3434
                              then_cx.llbb,
                              else_cx.llbb);
3435

3436
    ret join_results(cx, expr_llty,
3437
                     vec(then_res, else_res));
3438 3439
}

G
Graydon Hoare 已提交
3440 3441 3442 3443 3444 3445
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,
3446
             ty.t t, ast.block body,
3447
             @block_ctxt outer_next_cx) -> result {
G
Graydon Hoare 已提交
3448 3449

        auto next_cx = new_sub_block_ctxt(cx, "next");
3450 3451 3452
        auto scope_cx =
            new_loop_scope_block_ctxt(cx, option.some[@block_ctxt](next_cx),
                                      outer_next_cx, "for loop scope");
G
Graydon Hoare 已提交
3453 3454 3455

        cx.build.Br(scope_cx.llbb);
        auto local_res = alloc_local(scope_cx, local);
3456
        auto bcx = copy_ty(local_res.bcx, INIT, local_res.val, curr, t).bcx;
3457 3458
        scope_cx.cleanups +=
            vec(clean(bind drop_slot(_, local_res.val, t)));
3459
        bcx = trans_block(bcx, body).bcx;
G
Graydon Hoare 已提交
3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471
        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;
        }
    }

3472
    auto next_cx = new_sub_block_ctxt(cx, "next");
3473
    auto seq_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, seq);
G
Graydon Hoare 已提交
3474
    auto seq_res = trans_expr(cx, seq);
3475 3476 3477 3478
    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 已提交
3479 3480
}

3481 3482 3483 3484 3485 3486

// 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)
3487
        -> vec[ast.def_id] {
3488
    type env = @rec(
3489 3490 3491
        mutable vec[ast.def_id] refs,
        hashmap[ast.def_id,()] decls
    );
3492

M
Marijn Haverbeke 已提交
3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509
    fn walk_expr(env e, @ast.expr expr) {
        alt (expr.node) {
            case (ast.expr_path(?path, ?d, _)) {
                alt (option.get[ast.def](d)) {
                    case (ast.def_arg(?did)) {
                        _vec.push[ast.def_id](e.refs, did);
                    }
                    case (ast.def_local(?did)) {
                        _vec.push[ast.def_id](e.refs, did);
                    }
                    case (ast.def_upvar(?did)) {
                        _vec.push[ast.def_id](e.refs, did);
                    }
                    case (_) {}
                }
            }
            case (_) {}
3510 3511 3512
        }
    }

M
Marijn Haverbeke 已提交
3513 3514 3515 3516 3517 3518 3519
    fn walk_decl(env e, @ast.decl decl) {
        alt (decl.node) {
            case (ast.decl_local(?local)) {
                e.decls.insert(local.id, ());
            }
            case (_) {}
        }
3520 3521 3522 3523 3524 3525 3526
    }

    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 已提交
3527 3528 3529 3530
    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);
3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542

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

3543 3544 3545 3546
fn trans_for_each(@block_ctxt cx,
                  @ast.decl decl,
                  @ast.expr seq,
                  &ast.block body) -> result {
3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572
    /*
     * 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.

3573
    auto lcx = cx.fcx.lcx;
3574
    // FIXME: possibly support alias-mode here?
3575
    auto decl_ty = ty.mk_nil(lcx.ccx.tcx);
3576
    auto decl_id;
3577 3578
    alt (decl.node) {
        case (ast.decl_local(?local)) {
3579
            decl_ty = node_ann_type(lcx.ccx, local.ann);
3580
            decl_id = local.id;
3581 3582 3583
        }
    }

3584
    auto upvars = collect_upvars(cx, body, decl_id);
3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595
    auto upvar_count = _vec.len[ast.def_id](upvars);

    auto llbindingsptr;
    if (upvar_count > 0u) {
        // Gather up the upvars.
        let vec[ValueRef] llbindings = vec();
        let vec[TypeRef] llbindingtys = vec();
        for (ast.def_id did in upvars) {
            auto llbinding;
            alt (cx.fcx.lllocals.find(did)) {
                case (none[ValueRef]) {
3596 3597 3598 3599 3600 3601
                    alt (cx.fcx.llupvars.find(did)) {
                        case (none[ValueRef]) {
                            llbinding = cx.fcx.llargs.get(did);
                        }
                        case (some[ValueRef](?llval)) { llbinding = llval; }
                    }
3602 3603 3604 3605 3606 3607 3608 3609
                }
                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.
3610
        llbindingsptr = alloca(cx, T_struct(llbindingtys));
3611 3612 3613 3614 3615 3616 3617 3618 3619 3620
        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()));
3621 3622
    }

3623
    // Create an environment and populate it with the bindings.
3624
    auto tydesc_count = _vec.len[ValueRef](cx.fcx.lltydescs);
3625
    auto llenvptrty = T_closure_ptr(lcx.ccx.tn, T_ptr(T_nil()),
3626
                                    val_ty(llbindingsptr), tydesc_count);
3627
    auto llenvptr = alloca(cx, llvm.LLVMGetElementType(llenvptrty));
3628 3629 3630 3631 3632 3633

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

3635 3636 3637 3638 3639
    // 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),
3640
                                         C_int(abi.closure_elt_ty_params)));
3641 3642 3643 3644 3645 3646 3647 3648
    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;
    }

3649 3650
    // Step 2: Declare foreach body function.

3651
    let str s = mangle_name_by_seq(lcx.ccx, lcx.path, "foreach");
3652 3653 3654 3655 3656 3657 3658

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

3659 3660 3661 3662
    auto iter_body_llty =
        type_of_fn_full(lcx.ccx, ast.proto_fn,
                        none[TypeRef],
                        vec(rec(mode=ast.alias, ty=decl_ty)),
3663
                        ty.mk_nil(lcx.ccx.tcx), 0u);
3664

3665
    let ValueRef lliterbody = decl_internal_fastcall_fn(lcx.ccx.llmod,
3666
                                                       s, iter_body_llty);
3667

3668
    auto fcx = new_fn_ctxt(lcx, lliterbody);
3669
    auto bcx = new_top_block_ctxt(fcx);
3670
    auto lltop = bcx.llbb;
3671

3672 3673
    // Populate the upvars from the environment.
    auto llremoteenvptr = bcx.build.PointerCast(fcx.llenv, llenvptrty);
3674 3675 3676 3677
    auto llremotebindingsptrptr =
        bcx.build.GEP(llremoteenvptr, vec(C_int(0),
                                          C_int(abi.box_rc_field_body),
                                          C_int(abi.closure_elt_bindings)));
3678 3679
    auto llremotebindingsptr = bcx.build.Load(llremotebindingsptrptr);

3680
    i = 0u;
3681 3682 3683 3684 3685 3686 3687 3688 3689 3690
    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;
    }

3691
    // Populate the type parameters from the environment.
3692 3693 3694 3695 3696
    auto llremotetydescsptr =
        bcx.build.GEP(llremoteenvptr,
                      vec(C_int(0),
                          C_int(abi.box_rc_field_body),
                          C_int(abi.closure_elt_ty_params)));
3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707

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

3708 3709
    // Add an upvar for the loop variable alias.
    fcx.llupvars.insert(decl_id, llvm.LLVMGetParam(fcx.llfn, 3u));
3710

3711
    auto r = trans_block(bcx, body);
3712 3713 3714 3715

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

3716
    r.bcx.build.RetVoid();
3717 3718


3719
    // Step 3: Call iter passing [lliterbody, llenv], plus other args.
3720 3721

    alt (seq.node) {
3722

3723
        case (ast.expr_call(?f, ?args, ?ann)) {
3724

3725
            auto pair = alloca(cx, T_fn_pair(lcx.ccx.tn,
3726
                                             iter_body_llty));
3727 3728 3729 3730 3731
            auto code_cell = cx.build.GEP(pair,
                                          vec(C_int(0),
                                              C_int(abi.fn_field_code)));
            cx.build.Store(lliterbody, code_cell);

3732 3733 3734
            auto env_cell = cx.build.GEP(pair, vec(C_int(0),
                                                   C_int(abi.fn_field_box)));
            auto llenvblobptr = cx.build.PointerCast(llenvptr,
3735
                T_opaque_closure_ptr(lcx.ccx.tn));
3736 3737
            cx.build.Store(llenvblobptr, env_cell);

3738
            // log "lliterbody: " + val_str(lcx.ccx.tn, lliterbody);
3739
            r = trans_call(cx, f,
3740
                           some[ValueRef](cx.build.Load(pair)),
3741 3742
                           args,
                           ann);
3743
            ret res(r.bcx, C_nil());
3744 3745
        }
    }
3746 3747 3748 3749
    fail;
}


3750 3751
fn trans_while(@block_ctxt cx, @ast.expr cond,
               &ast.block body) -> result {
3752

3753
    auto cond_cx = new_scope_block_ctxt(cx, "while cond");
3754
    auto next_cx = new_sub_block_ctxt(cx, "next");
3755 3756
    auto body_cx = new_loop_scope_block_ctxt(cx, option.none[@block_ctxt],
                                             next_cx, "while loop body");
3757 3758

    auto body_res = trans_block(body_cx, body);
3759 3760 3761
    auto cond_res = trans_expr(cond_cx, cond);

    body_res.bcx.build.Br(cond_cx.llbb);
3762 3763 3764

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

    cx.build.Br(cond_cx.llbb);
3767 3768 3769
    ret res(next_cx, C_nil());
}

3770 3771
fn trans_do_while(@block_ctxt cx, &ast.block body,
                  @ast.expr cond) -> result {
3772

3773
    auto next_cx = new_sub_block_ctxt(cx, "next");
3774 3775
    auto body_cx = new_loop_scope_block_ctxt(cx, option.none[@block_ctxt],
                                             next_cx, "do-while loop body");
3776 3777

    auto body_res = trans_block(body_cx, body);
3778 3779 3780 3781 3782 3783
    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);
3784 3785 3786
    ret res(next_cx, body_res.val);
}

P
Patrick Walton 已提交
3787 3788
// Pattern matching translation

3789 3790
fn trans_pat_match(@block_ctxt cx, @ast.pat pat, ValueRef llval,
                   @block_ctxt next_cx) -> result {
P
Patrick Walton 已提交
3791 3792 3793
    alt (pat.node) {
        case (ast.pat_wild(_)) { ret res(cx, llval); }
        case (ast.pat_bind(_, _, _)) { ret res(cx, llval); }
3794 3795

        case (ast.pat_lit(?lt, ?ann)) {
3796
            auto lllit = trans_lit(cx.fcx.lcx.ccx, *lt, ann);
3797 3798
            auto lltype = ty.ann_to_type(ann);
            auto lleq = trans_compare(cx, ast.eq, lltype, llval, lllit);
3799

3800 3801
            auto matched_cx = new_sub_block_ctxt(lleq.bcx, "matched_cx");
            lleq.bcx.build.CondBr(lleq.val, matched_cx.llbb, next_cx.llbb);
3802 3803 3804
            ret res(matched_cx, llval);
        }

P
Patrick Walton 已提交
3805
        case (ast.pat_tag(?id, ?subpats, ?vdef_opt, ?ann)) {
3806
            auto lltagptr = cx.build.PointerCast(llval,
3807
                T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn));
3808 3809 3810

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

P
Patrick Walton 已提交
3813 3814 3815
            auto vdef = option.get[ast.variant_def](vdef_opt);
            auto variant_id = vdef._1;
            auto variant_tag = 0;
3816

3817
            auto variants = tag_variants(cx.fcx.lcx.ccx, vdef._0);
P
Patrick Walton 已提交
3818
            auto i = 0;
3819 3820
            for (variant_info v in variants) {
                auto this_variant_id = v.id;
P
Patrick Walton 已提交
3821
                if (variant_id._0 == this_variant_id._0 &&
G
Graydon Hoare 已提交
3822
                    variant_id._1 == this_variant_id._1) {
P
Patrick Walton 已提交
3823 3824 3825 3826 3827 3828 3829
                    variant_tag = i;
                }
                i += 1;
            }

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

3830
            auto lleq = cx.build.ICmp(lib.llvm.LLVMIntEQ, lldiscrim,
P
Patrick Walton 已提交
3831 3832 3833
                                      C_int(variant_tag));
            cx.build.CondBr(lleq, matched_cx.llbb, next_cx.llbb);

3834 3835
            auto ty_params = node_ann_ty_params(ann);

P
Patrick Walton 已提交
3836
            if (_vec.len[@ast.pat](subpats) > 0u) {
3837
                auto llblobptr = matched_cx.build.GEP(lltagptr,
3838
                    vec(C_int(0), C_int(1)));
P
Patrick Walton 已提交
3839 3840
                auto i = 0;
                for (@ast.pat subpat in subpats) {
3841 3842
                    auto rslt = GEP_tag(matched_cx, llblobptr, vdef._0,
                                        vdef._1, ty_params, i);
3843 3844 3845
                    auto llsubvalptr = rslt.val;
                    matched_cx = rslt.bcx;

3846
                    auto llsubval = load_if_immediate(matched_cx,
3847
                        llsubvalptr, pat_ty(cx.fcx.lcx.ccx.tcx, subpat));
P
Patrick Walton 已提交
3848 3849 3850
                    auto subpat_res = trans_pat_match(matched_cx, subpat,
                                                      llsubval, next_cx);
                    matched_cx = subpat_res.bcx;
3851 3852

                    i += 1;
P
Patrick Walton 已提交
3853 3854 3855 3856 3857 3858 3859 3860 3861 3862
                }
            }

            ret res(matched_cx, llval);
        }
    }

    fail;
}

3863 3864
fn trans_pat_binding(@block_ctxt cx, @ast.pat pat,
                     ValueRef llval, bool bind_alias)
3865
    -> result {
P
Patrick Walton 已提交
3866 3867
    alt (pat.node) {
        case (ast.pat_wild(_)) { ret res(cx, llval); }
3868
        case (ast.pat_lit(_, _)) { ret res(cx, llval); }
P
Patrick Walton 已提交
3869
        case (ast.pat_bind(?id, ?def_id, ?ann)) {
3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883
            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;
                llvm.LLVMSetValueName(dst, _str.buf(id));
                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 已提交
3884
        }
3885
        case (ast.pat_tag(_, ?subpats, ?vdef_opt, ?ann)) {
P
Patrick Walton 已提交
3886 3887
            if (_vec.len[@ast.pat](subpats) == 0u) { ret res(cx, llval); }

3888 3889 3890 3891
            // Get the appropriate variant for this tag.
            auto vdef = option.get[ast.variant_def](vdef_opt);

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

3895 3896
            auto ty_param_substs = node_ann_ty_params(ann);

P
Patrick Walton 已提交
3897 3898 3899
            auto this_cx = cx;
            auto i = 0;
            for (@ast.pat subpat in subpats) {
3900 3901
                auto rslt = GEP_tag(this_cx, llblobptr, vdef._0, vdef._1,
                                    ty_param_substs, i);
3902
                this_cx = rslt.bcx;
P
Patrick Walton 已提交
3903
                auto subpat_res = trans_pat_binding(this_cx, subpat,
3904
                                                    rslt.val, true);
P
Patrick Walton 已提交
3905
                this_cx = subpat_res.bcx;
3906
                i += 1;
P
Patrick Walton 已提交
3907 3908 3909 3910 3911 3912 3913
            }

            ret res(this_cx, llval);
        }
    }
}

3914 3915
fn trans_alt(@block_ctxt cx, @ast.expr expr,
             vec[ast.arm] arms, ast.ann ann) -> result {
P
Patrick Walton 已提交
3916 3917 3918
    auto expr_res = trans_expr(cx, expr);

    auto this_cx = expr_res.bcx;
3919
    let vec[result] arm_results = vec();
P
Patrick Walton 已提交
3920 3921 3922 3923 3924 3925 3926 3927 3928
    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,
3929
                                             expr_res.val, false);
P
Patrick Walton 已提交
3930 3931

        auto block_res = trans_block(binding_res.bcx, arm.block);
3932
        arm_results += vec(block_res);
P
Patrick Walton 已提交
3933 3934 3935 3936

        this_cx = next_cx;
    }

3937
    auto default_cx = this_cx;
3938
    auto default_res = trans_fail(default_cx, some[common.span](expr.span),
3939
                                  "non-exhaustive match failure");
P
Patrick Walton 已提交
3940

3941
    // FIXME: This isn't quite right, particularly re: dynamic types
3942 3943
    auto expr_ty = ty.ann_to_type(ann);
    auto expr_llty;
3944
    if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, expr_ty)) {
3945
        expr_llty = T_typaram_ptr(cx.fcx.lcx.ccx.tn);
3946
    } else {
3947
        expr_llty = type_of(cx.fcx.lcx.ccx, expr_ty);
3948
        if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, expr_ty)) {
3949 3950 3951 3952 3953
            expr_llty = T_ptr(expr_llty);
        }
    }

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

3956
type generic_info = rec(ty.t item_type,
3957 3958
                        vec[ValueRef] tydescs);

3959 3960
type lval_result = rec(result res,
                       bool is_mem,
3961
                       option.t[generic_info] generic,
3962
                       option.t[ValueRef] llobj,
3963
                       option.t[ty.t] method_ty);
3964 3965 3966 3967

fn lval_mem(@block_ctxt cx, ValueRef val) -> lval_result {
    ret rec(res=res(cx, val),
            is_mem=true,
3968
            generic=none[generic_info],
3969
            llobj=none[ValueRef],
3970
            method_ty=none[ty.t]);
3971 3972 3973 3974 3975
}

fn lval_val(@block_ctxt cx, ValueRef val) -> lval_result {
    ret rec(res=res(cx, val),
            is_mem=false,
3976
            generic=none[generic_info],
3977
            llobj=none[ValueRef],
3978
            method_ty=none[ty.t]);
3979
}
3980

3981
fn trans_external_path(@block_ctxt cx, ast.def_id did,
3982
                       ty.ty_param_count_and_ty tpt) -> lval_result {
3983 3984 3985 3986
    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));
3987 3988 3989
    ret lval_val(cx, v);
}

3990
fn lval_generic_fn(@block_ctxt cx,
3991
                   ty.ty_param_count_and_ty tpt,
3992 3993
                   ast.def_id fn_id,
                   &ast.ann ann)
3994
        -> lval_result {
3995
    auto lv;
3996
    if (cx.fcx.lcx.ccx.sess.get_targ_crate_num() == fn_id._0) {
3997
        // Internal reference.
3998
        check (cx.fcx.lcx.ccx.fn_pairs.contains_key(fn_id));
3999
        lv = lval_val(cx, cx.fcx.lcx.ccx.fn_pairs.get(fn_id));
4000 4001
    } else {
        // External reference.
4002
        lv = trans_external_path(cx, fn_id, tpt);
4003
    }
4004 4005

    auto monoty;
4006
    let vec[ty.t] tys;
4007 4008
    alt (ann) {
        case (ast.ann_none) {
4009
            cx.fcx.lcx.ccx.sess.bug("no type annotation for path!");
4010 4011
            fail;
        }
4012
        case (ast.ann_type(?monoty_, ?tps, _)) {
4013
            monoty = monoty_;
4014
            tys = option.get[vec[ty.t]](tps);
4015 4016
        }
    }
4017

4018
    if (_vec.len[ty.t](tys) != 0u) {
4019
        auto bcx = lv.res.bcx;
4020
        let vec[ValueRef] tydescs = vec();
4021
        for (ty.t t in tys) {
4022 4023
            // TODO: Doesn't always escape.
            auto td = get_tydesc(bcx, t, true);
4024
            bcx = td.bcx;
4025
            _vec.push[ValueRef](tydescs, td.val);
4026 4027 4028 4029 4030 4031 4032 4033 4034 4035
        }
        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;
}

4036
fn lookup_discriminant(@local_ctxt lcx, ast.def_id tid, ast.def_id vid)
4037
        -> ValueRef {
4038
    alt (lcx.ccx.discrims.find(vid)) {
4039 4040
        case (none[ValueRef]) {
            // It's an external discriminant that we haven't seen yet.
4041
            check (lcx.ccx.sess.get_targ_crate_num() != vid._0);
4042 4043 4044
            auto sym = creader.get_symbol(lcx.ccx.sess, vid);
            auto gvar = llvm.LLVMAddGlobal(lcx.ccx.llmod, T_int(),
                                           _str.buf(sym));
4045 4046 4047
            llvm.LLVMSetLinkage(gvar,
                                lib.llvm.LLVMExternalLinkage as llvm.Linkage);
            llvm.LLVMSetGlobalConstant(gvar, True);
4048
            lcx.ccx.discrims.insert(vid, gvar);
4049 4050 4051 4052 4053 4054
            ret gvar;
        }
        case (some[ValueRef](?llval)) { ret llval; }
    }
}

4055
fn trans_path(@block_ctxt cx, &ast.path p, &option.t[ast.def] dopt,
G
Graydon Hoare 已提交
4056
              &ast.ann ann) -> lval_result {
4057 4058 4059 4060
    alt (dopt) {
        case (some[ast.def](?def)) {
            alt (def) {
                case (ast.def_arg(?did)) {
4061 4062
                    alt (cx.fcx.llargs.find(did)) {
                        case (none[ValueRef]) {
4063
                            check (cx.fcx.llupvars.contains_key(did));
4064 4065 4066 4067 4068 4069
                            ret lval_mem(cx, cx.fcx.llupvars.get(did));
                        }
                        case (some[ValueRef](?llval)) {
                            ret lval_mem(cx, llval);
                        }
                    }
4070 4071
                }
                case (ast.def_local(?did)) {
4072 4073
                    alt (cx.fcx.lllocals.find(did)) {
                        case (none[ValueRef]) {
4074
                            check (cx.fcx.llupvars.contains_key(did));
4075 4076 4077 4078 4079 4080
                            ret lval_mem(cx, cx.fcx.llupvars.get(did));
                        }
                        case (some[ValueRef](?llval)) {
                            ret lval_mem(cx, llval);
                        }
                    }
G
Graydon Hoare 已提交
4081
                }
P
Patrick Walton 已提交
4082
                case (ast.def_binding(?did)) {
4083
                    check (cx.fcx.lllocals.contains_key(did));
4084
                    ret lval_mem(cx, cx.fcx.lllocals.get(did));
P
Patrick Walton 已提交
4085
                }
4086
                case (ast.def_obj_field(?did)) {
4087
                    check (cx.fcx.llobjfields.contains_key(did));
4088 4089
                    ret lval_mem(cx, cx.fcx.llobjfields.get(did));
                }
4090
                case (ast.def_fn(?did)) {
4091
                    auto tyt = ty.lookup_item_type(cx.fcx.lcx.ccx.sess,
4092
                        cx.fcx.lcx.ccx.tcx, cx.fcx.lcx.ccx.type_cache, did);
4093
                    ret lval_generic_fn(cx, tyt, did, ann);
4094
                }
4095
                case (ast.def_obj(?did)) {
4096
                    auto tyt = ty.lookup_item_type(cx.fcx.lcx.ccx.sess,
4097
                        cx.fcx.lcx.ccx.tcx, cx.fcx.lcx.ccx.type_cache, did);
4098
                    ret lval_generic_fn(cx, tyt, did, ann);
4099
                }
4100
                case (ast.def_variant(?tid, ?vid)) {
4101
                    auto v_tyt = ty.lookup_item_type(cx.fcx.lcx.ccx.sess,
4102 4103
                        cx.fcx.lcx.ccx.tcx, cx.fcx.lcx.ccx.type_cache, vid);
                    alt (ty.struct(cx.fcx.lcx.ccx.tcx, v_tyt._1)) {
4104 4105 4106
                        case (ty.ty_fn(_, _, _)) {
                            // N-ary variant.
                            ret lval_generic_fn(cx, v_tyt, vid, ann);
4107
                        }
4108 4109
                        case (_) {
                            // Nullary variant.
4110
                            auto tag_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
4111
                            auto lldiscrim_gv =
4112
                                lookup_discriminant(cx.fcx.lcx, tid, vid);
4113 4114 4115 4116 4117 4118
                            auto lldiscrim = cx.build.Load(lldiscrim_gv);

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

                            auto lltagty;
4119 4120
                            if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx,
                                                         tag_ty)) {
4121
                                lltagty = T_opaque_tag(cx.fcx.lcx.ccx.tn);
4122
                            } else {
4123
                                lltagty = type_of(cx.fcx.lcx.ccx, tag_ty);
4124
                            }
4125 4126
                            auto lltagptr = alloc_result.bcx.build.
                                PointerCast(lltagblob, T_ptr(lltagty));
4127

4128 4129 4130 4131
                            auto lldiscrimptr = alloc_result.bcx.build.GEP(
                                lltagptr, vec(C_int(0), C_int(0)));
                            alloc_result.bcx.build.Store(lldiscrim,
                                                         lldiscrimptr);
4132

4133 4134
                            ret lval_val(alloc_result.bcx, lltagptr);
                        }
4135
                    }
4136
                }
4137
                case (ast.def_const(?did)) {
4138
                    // TODO: externals
4139
                    check (cx.fcx.lcx.ccx.consts.contains_key(did));
4140
                    ret lval_mem(cx, cx.fcx.lcx.ccx.consts.get(did));
4141
                }
4142
                case (ast.def_native_fn(?did)) {
4143
                    auto tyt = ty.lookup_item_type(cx.fcx.lcx.ccx.sess,
4144
                        cx.fcx.lcx.ccx.tcx,
4145
                        cx.fcx.lcx.ccx.type_cache, did);
4146
                    ret lval_generic_fn(cx, tyt, did, ann);
4147
                }
4148
                case (_) {
4149
                    cx.fcx.lcx.ccx.sess.unimpl("def variant in trans");
G
Graydon Hoare 已提交
4150 4151 4152
                }
            }
        }
4153
        case (none[ast.def]) {
4154
            cx.fcx.lcx.ccx.sess.err("unresolved expr_path in trans");
4155 4156 4157 4158 4159
        }
    }
    fail;
}

4160
fn trans_field(@block_ctxt cx, &ast.span sp, ValueRef v, ty.t t0,
4161
               &ast.ident field, &ast.ann ann) -> lval_result {
4162 4163

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

4166
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
4167
        case (ty.ty_tup(_)) {
4168
            let uint ix = ty.field_num(cx.fcx.lcx.ccx.sess, sp, field);
4169
            auto v = GEP_tup_like(r.bcx, t, r.val, vec(0, ix as int));
4170
            ret lval_mem(v.bcx, v.val);
4171
        }
4172
        case (ty.ty_rec(?fields)) {
4173 4174
            let uint ix = ty.field_idx(cx.fcx.lcx.ccx.sess, sp, field,
                                       fields);
4175
            auto v = GEP_tup_like(r.bcx, t, r.val, vec(0, ix as int));
4176
            ret lval_mem(v.bcx, v.val);
4177
        }
4178
        case (ty.ty_obj(?methods)) {
4179 4180
            let uint ix = ty.method_idx(cx.fcx.lcx.ccx.sess, sp, field,
                                        methods);
4181 4182 4183 4184
            auto vtbl = r.bcx.build.GEP(r.val,
                                        vec(C_int(0),
                                            C_int(abi.obj_field_vtbl)));
            vtbl = r.bcx.build.Load(vtbl);
4185
            // +1 because slot #0 contains the destructor
4186
            auto v =  r.bcx.build.GEP(vtbl, vec(C_int(0),
4187
                                                C_int((ix + 1u) as int)));
4188 4189

            auto lvo = lval_mem(r.bcx, v);
4190
            let ty.t fn_ty = ty.method_ty_to_fn_ty(cx.fcx.lcx.ccx.tcx,
4191
                                                   methods.(ix));
4192
            ret rec(llobj = some[ValueRef](r.val),
4193
                    method_ty = some[ty.t](fn_ty)
4194
                    with lvo);
4195
        }
4196
        case (_) {cx.fcx.lcx.ccx.sess.unimpl("field variant in trans_field");}
4197 4198 4199 4200
    }
    fail;
}

4201 4202
fn trans_index(@block_ctxt cx, &ast.span sp, @ast.expr base,
               @ast.expr idx, &ast.ann ann) -> lval_result {
4203

G
Graydon Hoare 已提交
4204
    auto lv = trans_expr(cx, base);
4205
    lv = autoderef(lv.bcx, lv.val, ty.expr_ty(cx.fcx.lcx.ccx.tcx, base));
G
Graydon Hoare 已提交
4206 4207
    auto ix = trans_expr(lv.bcx, idx);
    auto v = lv.val;
4208
    auto bcx = ix.bcx;
4209

4210 4211
    // Cast to an LLVM integer. Rust is less strict than LLVM in this regard.
    auto ix_val;
4212 4213
    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());
4214 4215 4216 4217 4218 4219 4220 4221
    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;
    }

4222
    auto unit_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
4223
    auto unit_sz = size_of(bcx, unit_ty);
4224
    bcx = unit_sz.bcx;
4225
    llvm.LLVMSetValueName(unit_sz.val, _str.buf("unit_sz"));
4226 4227

    auto scaled_ix = bcx.build.Mul(ix_val, unit_sz.val);
4228
    llvm.LLVMSetValueName(scaled_ix, _str.buf("scaled_ix"));
4229

4230 4231
    auto lim = bcx.build.GEP(v, vec(C_int(0), C_int(abi.vec_elt_fill)));
    lim = bcx.build.Load(lim);
4232

4233 4234
    auto bounds_check = bcx.build.ICmp(lib.llvm.LLVMIntULT,
                                       scaled_ix, lim);
4235

4236 4237 4238
    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);
4239 4240

    // fail: bad bounds check.
4241 4242
    auto fail_res = trans_fail(fail_cx, some[common.span](sp),
                               "bounds check");
4243 4244

    auto body = next_cx.build.GEP(v, vec(C_int(0), C_int(abi.vec_elt_data)));
4245
    auto elt;
4246
    if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, unit_ty)) {
4247 4248 4249 4250
        body = next_cx.build.PointerCast(body, T_ptr(T_array(T_i8(), 0u)));
        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));
4251 4252

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

4257
    ret lval_mem(next_cx, elt);
4258 4259
}

4260 4261 4262 4263
// 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).

4264
fn trans_lval(@block_ctxt cx, @ast.expr e) -> lval_result {
4265
    alt (e.node) {
4266 4267
        case (ast.expr_path(?p, ?dopt, ?ann)) {
            ret trans_path(cx, p, dopt, ann);
4268 4269
        }
        case (ast.expr_field(?base, ?ident, ?ann)) {
4270
            auto r = trans_expr(cx, base);
4271
            auto t = ty.expr_ty(cx.fcx.lcx.ccx.tcx, base);
4272
            ret trans_field(r.bcx, e.span, r.val, t, ident, ann);
4273
        }
4274 4275 4276
        case (ast.expr_index(?base, ?idx, ?ann)) {
            ret trans_index(cx, e.span, base, idx, ann);
        }
4277
        case (ast.expr_unary(?unop, ?base, ?ann)) {
4278
            check (unop == ast.deref);
4279 4280 4281 4282 4283 4284 4285

            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);
        }
4286
        case (ast.expr_self_method(?ident, ?ann)) {
4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299
            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;
                }

            }
        }
4300
        case (_) {
4301 4302
            cx.fcx.lcx.ccx.sess.span_unimpl(e.span,
                                            "expr variant in trans_lval");
4303
        }
G
Graydon Hoare 已提交
4304 4305 4306 4307
    }
    fail;
}

4308
fn trans_cast(@block_ctxt cx, @ast.expr e, &ast.ann ann) -> result {
4309 4310
    auto e_res = trans_expr(cx, e);
    auto llsrctype = val_ty(e_res.val);
4311 4312
    auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
    auto lldsttype = type_of(cx.fcx.lcx.ccx, t);
4313
    if (!ty.type_is_fp(cx.fcx.lcx.ccx.tcx, t)) {
4314
        // TODO: native-to-native casts
4315 4316
        if (ty.type_is_native(cx.fcx.lcx.ccx.tcx,
                              ty.expr_ty(cx.fcx.lcx.ccx.tcx, e))) {
4317
            e_res.val = e_res.bcx.build.PtrToInt(e_res.val, lldsttype);
4318
        } else if (ty.type_is_native(cx.fcx.lcx.ccx.tcx, t)) {
4319
            e_res.val = e_res.bcx.build.IntToPtr(e_res.val, lldsttype);
4320
        } else if (llvm.LLVMGetIntTypeWidth(lldsttype) >
4321
            llvm.LLVMGetIntTypeWidth(llsrctype)) {
4322
            if (ty.type_is_signed(cx.fcx.lcx.ccx.tcx, t)) {
4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339
                // 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 {
4340
        cx.fcx.lcx.ccx.sess.unimpl("fp cast");
4341 4342 4343 4344
    }
    ret e_res;
}

4345
fn trans_bind_thunk(@local_ctxt cx,
4346 4347
                    ty.t incoming_fty,
                    ty.t outgoing_fty,
4348
                    vec[option.t[@ast.expr]] args,
4349 4350
                    ty.t closure_ty,
                    vec[ty.t] bound_tys,
4351
                    uint ty_param_count) -> ValueRef {
4352 4353 4354
    // Construct a thunk-call with signature incoming_fty, and that copies
    // args forward into a call to outgoing_fty.

4355
    let str s = mangle_name_by_seq(cx.ccx, cx.path, "thunk");
4356 4357 4358
    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);
4359

4360
    auto fcx = new_fn_ctxt(cx, llthunk);
4361
    auto bcx = new_top_block_ctxt(fcx);
4362
    auto lltop = bcx.llbb;
4363

4364
    auto llclosure_ptr_ty =
4365
        type_of(cx.ccx, ty.mk_imm_box(cx.ccx.tcx, closure_ty));
4366
    auto llclosure = bcx.build.PointerCast(fcx.llenv, llclosure_ptr_ty);
4367

4368 4369 4370 4371 4372 4373
    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,
4374 4375 4376
                                         vec(C_int(0),
                                             C_int(abi.fn_field_box)));
    lltargetclosure = bcx.build.Load(lltargetclosure);
4377

4378 4379
    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);
4380 4381

    auto llretptr = fcx.llretptr;
4382
    if (ty.type_has_dynamic_size(cx.ccx.tcx, outgoing_ret_ty)) {
4383
        llretptr = bcx.build.PointerCast(llretptr, T_typaram_ptr(cx.ccx.tn));
4384 4385 4386
    }

    let vec[ValueRef] llargs = vec(llretptr,
4387
                                   fcx.lltaskptr,
4388
                                   lltargetclosure);
4389 4390 4391 4392 4393

    // Copy in the type parameters.
    let uint i = 0u;
    while (i < ty_param_count) {
        auto lltyparam_ptr =
4394 4395 4396 4397 4398 4399
            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;
4400 4401 4402
        auto td = bcx.build.Load(lltyparam_ptr.val);
        llargs += vec(td);
        fcx.lltydescs += vec(td);
4403 4404 4405
        i += 1u;
    }

4406
    let uint a = 3u;    // retptr, task ptr, env come first
4407
    let int b = 0;
4408
    let uint outgoing_arg_index = 0u;
4409
    let vec[TypeRef] llout_arg_tys =
4410
        type_of_explicit_args(cx.ccx, outgoing_args);
4411

4412
    for (option.t[@ast.expr] arg in args) {
4413 4414 4415 4416

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

4417 4418 4419
        alt (arg) {

            // Arg provided at binding time; thunk copies it from closure.
4420 4421
            case (some[@ast.expr](?e)) {
                auto e_ty = ty.expr_ty(cx.ccx.tcx, e);
4422 4423 4424 4425 4426 4427
                auto bound_arg =
                    GEP_tup_like(bcx, closure_ty, llclosure,
                                 vec(0,
                                     abi.box_rc_field_body,
                                     abi.closure_elt_bindings,
                                     b));
4428

4429
                bcx = bound_arg.bcx;
4430 4431 4432
                auto val = bound_arg.val;

                if (out_arg.mode == ast.val) {
4433 4434 4435 4436 4437 4438 4439
                    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);
                    }
4440 4441
                } else if (ty.type_contains_params(cx.ccx.tcx,
                                                   out_arg.ty)) {
4442
                    check (out_arg.mode == ast.alias);
4443 4444 4445
                    val = bcx.build.PointerCast(val, llout_arg_ty);
                }

4446
                llargs += vec(val);
4447 4448 4449 4450 4451 4452
                b += 1;
            }

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

4454
                if (ty.type_contains_params(cx.ccx.tcx, out_arg.ty)) {
4455
                    check (out_arg.mode == ast.alias);
4456
                    passed_arg = bcx.build.PointerCast(passed_arg,
4457
                                                       llout_arg_ty);
4458
                }
4459

4460
                llargs += vec(passed_arg);
4461 4462 4463
                a += 1u;
            }
        }
4464

4465
        outgoing_arg_index += 1u;
4466 4467 4468
    }

    // FIXME: turn this call + ret into a tail call.
4469
    auto lltargetfn = bcx.build.GEP(lltarget.val,
4470 4471
                                    vec(C_int(0),
                                        C_int(abi.fn_field_code)));
4472 4473 4474

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

4483
    lltargetfn = bcx.build.Load(lltargetfn);
4484

4485
    auto r = bcx.build.FastCall(lltargetfn, llargs);
4486
    bcx.build.RetVoid();
4487

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

4491 4492 4493
    ret llthunk;
}

4494 4495 4496
fn trans_bind(@block_ctxt cx, @ast.expr f,
              vec[option.t[@ast.expr]] args,
              &ast.ann ann) -> result {
4497 4498
    auto f_res = trans_lval(cx, f);
    if (f_res.is_mem) {
4499
        cx.fcx.lcx.ccx.sess.unimpl("re-binding existing function");
4500
    } else {
4501 4502
        let vec[@ast.expr] bound = vec();

4503 4504 4505 4506 4507
        for (option.t[@ast.expr] argopt in args) {
            alt (argopt) {
                case (none[@ast.expr]) {
                }
                case (some[@ast.expr](?e)) {
4508
                    _vec.push[@ast.expr](bound, e);
4509 4510 4511
                }
            }
        }
4512 4513

        // Figure out which tydescs we need to pass, if any.
4514
        let ty.t outgoing_fty;
B
Brian Anderson 已提交
4515
        let vec[ValueRef] lltydescs;
4516 4517
        alt (f_res.generic) {
            case (none[generic_info]) {
4518
                outgoing_fty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, f);
B
Brian Anderson 已提交
4519
                lltydescs = vec();
4520 4521 4522 4523 4524 4525 4526 4527 4528
            }
            case (some[generic_info](?ginfo)) {
                outgoing_fty = ginfo.item_type;
                lltydescs = ginfo.tydescs;
            }
        }
        auto ty_param_count = _vec.len[ValueRef](lltydescs);

        if (_vec.len[@ast.expr](bound) == 0u && ty_param_count == 0u) {
4529 4530 4531 4532
            // Trivial 'binding': just return the static pair-ptr.
            ret f_res.res;
        } else {
            auto bcx = f_res.res.bcx;
4533
            auto pair_t = node_type(cx.fcx.lcx.ccx, ann);
4534
            auto pair_v = alloca(bcx, pair_t);
4535 4536

            // Translate the bound expressions.
4537
            let vec[ty.t] bound_tys = vec();
4538
            let vec[ValueRef] bound_vals = vec();
4539
            auto i = 0u;
4540 4541 4542
            for (@ast.expr e in bound) {
                auto arg = trans_expr(bcx, e);
                bcx = arg.bcx;
4543

4544
                _vec.push[ValueRef](bound_vals, arg.val);
4545
                _vec.push[ty.t](bound_tys,
4546
                                 ty.expr_ty(cx.fcx.lcx.ccx.tcx, e));
4547 4548

                i += 1u;
4549 4550 4551
            }

            // Synthesize a closure type.
4552
            let ty.t bindings_ty = ty.mk_imm_tup(cx.fcx.lcx.ccx.tcx,
4553
                                                  bound_tys);
4554 4555 4556 4557

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

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

4563
            let vec[ty.t] closure_tys =
4564 4565 4566
                vec(tydesc_ty,
                    outgoing_fty,
                    bindings_ty,
4567
                    ty.mk_imm_tup(cx.fcx.lcx.ccx.tcx, captured_tys));
4568

4569
            let ty.t closure_ty = ty.mk_imm_tup(cx.fcx.lcx.ccx.tcx,
4570
                                                 closure_tys);
4571 4572

            auto r = trans_malloc_boxed(bcx, closure_ty);
4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588
            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)));
4589
            auto bindings_tydesc = get_tydesc(bcx, bindings_ty, true);
4590 4591
            bcx = bindings_tydesc.bcx;
            bcx.build.Store(bindings_tydesc.val, bound_tydesc);
4592

4593 4594 4595 4596 4597 4598
            // 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.
4599
            auto llfnty = type_of_fn(bcx.fcx.lcx.ccx,
4600 4601 4602
                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),
4603
                ty_param_count);
4604
            auto llclosurety = T_ptr(T_fn_pair(bcx.fcx.lcx.ccx.tn, llfnty));
4605

4606 4607
            // Store thunk-target.
            auto bound_target =
4608 4609
                bcx.build.GEP(closure,
                              vec(C_int(0),
4610
                                  C_int(abi.closure_elt_target)));
4611
            auto src = bcx.build.Load(f_res.res.val);
4612
            bound_target = bcx.build.PointerCast(bound_target, llclosurety);
4613
            bcx.build.Store(src, bound_target);
4614

4615
            // Copy expr values into boxed bindings.
4616
            i = 0u;
4617 4618 4619 4620
            auto bindings =
                bcx.build.GEP(closure,
                              vec(C_int(0),
                                  C_int(abi.closure_elt_bindings)));
4621 4622
            for (ValueRef v in bound_vals) {
                auto bound = bcx.build.GEP(bindings,
4623
                                           vec(C_int(0), C_int(i as int)));
4624
                bcx = copy_ty(bcx, INIT, bound, v, bound_tys.(i)).bcx;
4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644
                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;
                    }
4645 4646

                    outgoing_fty = ginfo.item_type;
4647
                }
4648 4649
            }

4650 4651 4652 4653
            // 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)));
4654

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

4657
            let ValueRef llthunk =
4658
                trans_bind_thunk(cx.fcx.lcx, pair_ty, outgoing_fty,
4659
                                 args, closure_ty, bound_tys,
4660
                                 ty_param_count);
4661 4662 4663 4664 4665 4666 4667

            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)));
4668 4669 4670
            bcx.build.Store
                (bcx.build.PointerCast
                 (box,
4671
                  T_opaque_closure_ptr(bcx.fcx.lcx.ccx.tn)),
4672
                 pair_box);
4673

4674
            find_scope_cx(cx).cleanups +=
4675
                vec(clean(bind drop_slot(_, pair_v, pair_ty)));
4676

4677 4678
            ret res(bcx, pair_v);
        }
4679 4680 4681
    }
}

4682 4683 4684 4685 4686 4687 4688
fn trans_arg_expr(@block_ctxt cx,
                  ty.arg arg,
                  TypeRef lldestty0,
                  @ast.expr e) -> result {

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

4691
    if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, e_ty)) {
4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721
        auto re = trans_expr(bcx, e);
        val = re.val;
        bcx = re.bcx;
    } else if (arg.mode == ast.alias) {
        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;
    }

4722 4723 4724 4725
    if (arg.mode != ast.alias) {
        bcx = take_ty(bcx, val, e_ty).bcx;
    }

4726
    if (ty.type_contains_params(cx.fcx.lcx.ccx.tcx, arg.ty)) {
4727 4728 4729
        auto lldestty = lldestty0;
        if (arg.mode == ast.val) {
            // FIXME: we'd prefer to use &&, but rustboot doesn't like it
4730
            if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, e_ty)) {
4731 4732 4733 4734 4735 4736 4737 4738
                lldestty = T_ptr(lldestty);
            }
        }
        val = bcx.build.PointerCast(val, lldestty);
    }

    if (arg.mode == ast.val) {
        // FIXME: we'd prefer to use &&, but rustboot doesn't like it
4739
        if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, e_ty)) {
4740 4741 4742 4743 4744 4745 4746 4747
            // 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);
}

4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args

fn trans_args(@block_ctxt cx,
              ValueRef llenv,
              option.t[ValueRef] llobj,
              option.t[generic_info] gen,
4759
              option.t[ValueRef] lliterbody,
4760
              &vec[@ast.expr] es,
4761
              ty.t fn_ty)
4762 4763
    -> tup(@block_ctxt, vec[ValueRef], ValueRef) {

4764
    let vec[ty.arg] args = ty.ty_fn_args(cx.fcx.lcx.ccx.tcx, fn_ty);
4765 4766 4767 4768 4769 4770
    let vec[ValueRef] llargs = vec();
    let vec[ValueRef] lltydescs = vec();
    let @block_ctxt bcx = cx;


    // Arg 0: Output pointer.
4771
    auto retty = ty.ty_fn_ret(cx.fcx.lcx.ccx.tcx, fn_ty);
4772 4773 4774 4775
    auto llretslot_res = alloc_ty(bcx, retty);
    bcx = llretslot_res.bcx;
    auto llretslot = llretslot_res.val;

4776 4777 4778
    alt (gen) {
        case (some[generic_info](?g)) {
            lltydescs = g.tydescs;
4779 4780
            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);
4781 4782 4783 4784
        }
        case (_) {
        }
    }
4785
    if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, retty)) {
4786 4787
        llargs += vec(bcx.build.PointerCast
                      (llretslot, T_typaram_ptr(cx.fcx.lcx.ccx.tn)));
4788
    } else if (ty.type_contains_params(cx.fcx.lcx.ccx.tcx, retty)) {
4789 4790 4791 4792 4793
        // 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.
4794 4795
        llargs +=
            vec(cx.build.PointerCast(llretslot,
4796
                                     T_ptr(type_of(bcx.fcx.lcx.ccx, retty))));
4797
    } else {
4798
        llargs += vec(llretslot);
4799 4800 4801 4802
    }


    // Arg 1: Task pointer.
4803
    llargs += vec(bcx.fcx.lltaskptr);
4804 4805 4806 4807 4808 4809 4810

    // 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).
4811
            llargs += vec(bcx.build.Load(ob));
4812 4813
        }
        case (_) {
4814
            llargs += vec(llenv);
4815 4816 4817 4818 4819 4820
        }
    }

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

4821 4822 4823 4824
    // ... then possibly an lliterbody argument.
    alt (lliterbody) {
        case (none[ValueRef]) {}
        case (some[ValueRef](?lli)) {
4825
            llargs += vec(lli);
4826 4827 4828
        }
    }

4829
    // ... then explicit args.
4830 4831 4832 4833

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

4836 4837
    auto i = 0u;
    for (@ast.expr e in es) {
4838 4839 4840
        auto r = trans_arg_expr(bcx, args.(i), arg_tys.(i), e);
        bcx = r.bcx;
        llargs += vec(r.val);
4841 4842 4843 4844 4845 4846
        i += 1u;
    }

    ret tup(bcx, llargs, llretslot);
}

4847
fn trans_call(@block_ctxt cx, @ast.expr f,
4848 4849 4850
              option.t[ValueRef] lliterbody,
              vec[@ast.expr] args,
              &ast.ann ann) -> result {
4851 4852 4853 4854 4855

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

4856
    auto f_res = trans_lval(cx, f);
4857
    auto faddr = f_res.res.val;
4858
    auto llenv = C_null(T_opaque_closure_ptr(cx.fcx.lcx.ccx.tn));
4859 4860 4861 4862 4863 4864 4865 4866 4867

    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;
4868 4869
            auto pair = faddr;
            faddr = bcx.build.GEP(pair, vec(C_int(0),
G
Graydon Hoare 已提交
4870
                                            C_int(abi.fn_field_code)));
4871
            faddr = bcx.build.Load(faddr);
4872

4873 4874 4875 4876
            auto llclosure = bcx.build.GEP(pair,
                                           vec(C_int(0),
                                               C_int(abi.fn_field_box)));
            llenv = bcx.build.Load(llclosure);
4877
        }
4878
    }
4879

4880
    let ty.t fn_ty;
4881
    alt (f_res.method_ty) {
4882
        case (some[ty.t](?meth)) {
4883 4884
            // self-call
            fn_ty = meth;
4885
        }
4886

4887
        case (_) {
4888
            fn_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, f);
4889 4890

        }
4891

4892
    }
4893

4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905
    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;

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

4908
    for (ValueRef arg in llargs) {
4909
        log "arg: " + val_str(cx.fcx.lcx.ccx.tn, arg);
4910
    }
4911 4912 4913 4914 4915
    */

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

4916 4917
    alt (lliterbody) {
        case (none[ValueRef]) {
4918
            if (!ty.type_is_nil(cx.fcx.lcx.ccx.tcx, ret_ty)) {
4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931
                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.
        }
4932 4933 4934 4935
    }
    ret res(bcx, retval);
}

4936 4937
fn trans_tup(@block_ctxt cx, vec[ast.elt] elts,
             &ast.ann ann) -> result {
4938
    auto bcx = cx;
4939
    auto t = node_ann_type(bcx.fcx.lcx.ccx, ann);
4940 4941 4942 4943
    auto tup_res = alloc_ty(bcx, t);
    auto tup_val = tup_res.val;
    bcx = tup_res.bcx;

4944 4945
    find_scope_cx(cx).cleanups +=
        vec(clean(bind drop_ty(_, tup_val, t)));
G
Graydon Hoare 已提交
4946
    let int i = 0;
4947

4948
    for (ast.elt e in elts) {
4949
        auto e_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, e.expr);
4950 4951 4952 4953 4954
        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 已提交
4955 4956
        i += 1;
    }
4957
    ret res(bcx, tup_val);
G
Graydon Hoare 已提交
4958 4959
}

4960 4961
fn trans_vec(@block_ctxt cx, vec[@ast.expr] args,
             &ast.ann ann) -> result {
4962
    auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
4963
    auto unit_ty = t;
4964
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
4965 4966
        case (ty.ty_vec(?mt)) {
            unit_ty = mt.ty;
G
Graydon Hoare 已提交
4967 4968
        }
        case (_) {
4969
            cx.fcx.lcx.ccx.sess.bug("non-vec type in trans_vec");
G
Graydon Hoare 已提交
4970 4971 4972
        }
    }

4973 4974 4975
    auto bcx = cx;
    auto unit_sz = size_of(bcx, unit_ty);
    bcx = unit_sz.bcx;
4976 4977
    auto data_sz = bcx.build.Mul(C_int(_vec.len[@ast.expr](args) as int),
                                 unit_sz.val);
G
Graydon Hoare 已提交
4978 4979

    // FIXME: pass tydesc properly.
4980 4981
    auto sub = trans_upcall(bcx, "upcall_new_vec", vec(data_sz, C_int(0)),
                            false);
4982
    bcx = sub.bcx;
G
Graydon Hoare 已提交
4983

4984
    auto llty = type_of(bcx.fcx.lcx.ccx, t);
4985
    auto vec_val = vi2p(bcx, sub.val, llty);
4986 4987
    find_scope_cx(bcx).cleanups +=
        vec(clean(bind drop_ty(_, vec_val, t)));
G
Graydon Hoare 已提交
4988

4989 4990 4991 4992
    auto body = bcx.build.GEP(vec_val, vec(C_int(0),
                                           C_int(abi.vec_elt_data)));

    auto pseudo_tup_ty =
4993
        ty.mk_imm_tup(cx.fcx.lcx.ccx.tcx,
4994
                      _vec.init_elt[ty.t](unit_ty,
4995
                                           _vec.len[@ast.expr](args)));
G
Graydon Hoare 已提交
4996
    let int i = 0;
4997

G
Graydon Hoare 已提交
4998
    for (@ast.expr e in args) {
4999 5000 5001 5002
        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;
5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016

        // 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;
5017
        if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, unit_ty)) {
5018
            auto llunit_ty = type_of(cx.fcx.lcx.ccx, unit_ty);
5019 5020 5021 5022 5023 5024
            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 已提交
5025 5026
        i += 1;
    }
5027 5028 5029
    auto fill = bcx.build.GEP(vec_val,
                              vec(C_int(0), C_int(abi.vec_elt_fill)));
    bcx.build.Store(data_sz, fill);
5030

5031
    ret res(bcx, vec_val);
G
Graydon Hoare 已提交
5032 5033
}

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

5037
    auto bcx = cx;
5038
    auto t = node_ann_type(bcx.fcx.lcx.ccx, ann);
5039 5040 5041 5042
    auto rec_res = alloc_ty(bcx, t);
    auto rec_val = rec_res.val;
    bcx = rec_res.bcx;

5043 5044
    find_scope_cx(cx).cleanups +=
        vec(clean(bind drop_ty(_, rec_val, t)));
5045
    let int i = 0;
5046

G
Graydon Hoare 已提交
5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058
    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();
5059
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
G
Graydon Hoare 已提交
5060 5061 5062 5063
        case (ty.ty_rec(?flds)) { ty_fields = flds; }
    }

    for (ty.field tf in ty_fields) {
5064
        auto e_ty = tf.mt.ty;
5065 5066
        auto dst_res = GEP_tup_like(bcx, t, rec_val, vec(0, i));
        bcx = dst_res.bcx;
G
Graydon Hoare 已提交
5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079

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

        for (ast.field f in fields) {
            if (_str.eq(f.ident, tf.ident)) {
                expr_provided = true;
                src_res = trans_expr(bcx, f.expr);
            }
        }
        if (!expr_provided) {
            src_res = GEP_tup_like(bcx, t, base_val, vec(0, i));
            src_res = res(src_res.bcx,
5080
                          load_if_immediate(bcx, src_res.val, e_ty));
G
Graydon Hoare 已提交
5081 5082 5083 5084
        }

        bcx = src_res.bcx;
        bcx = copy_ty(bcx, INIT, dst_res.val, src_res.val, e_ty).bcx;
5085 5086
        i += 1;
    }
5087
    ret res(bcx, rec_val);
5088 5089
}

G
Graydon Hoare 已提交
5090

G
Graydon Hoare 已提交
5091

5092
fn trans_expr(@block_ctxt cx, @ast.expr e) -> result {
5093
    alt (e.node) {
5094
        case (ast.expr_lit(?lit, ?ann)) {
5095
            ret res(cx, trans_lit(cx.fcx.lcx.ccx, *lit, ann));
5096 5097
        }

5098
        case (ast.expr_unary(?op, ?x, ?ann)) {
5099 5100 5101
            if (op != ast.deref) {
                ret trans_unary(cx, op, x, ann);
            }
5102 5103
        }

P
Patrick Walton 已提交
5104
        case (ast.expr_binary(?op, ?x, ?y, _)) {
5105
            ret trans_binary(cx, op, x, y);
5106
        }
5107

P
Patrick Walton 已提交
5108
        case (ast.expr_if(?cond, ?thn, ?els, _)) {
5109
            ret trans_if(cx, cond, thn, els);
5110 5111
        }

G
Graydon Hoare 已提交
5112 5113 5114 5115
        case (ast.expr_for(?decl, ?seq, ?body, _)) {
            ret trans_for(cx, decl, seq, body);
        }

5116 5117 5118 5119
        case (ast.expr_for_each(?decl, ?seq, ?body, _)) {
            ret trans_for_each(cx, decl, seq, body);
        }

5120
        case (ast.expr_while(?cond, ?body, _)) {
5121
            ret trans_while(cx, cond, body);
5122 5123
        }

5124
        case (ast.expr_do_while(?body, ?cond, _)) {
5125
            ret trans_do_while(cx, body, cond);
5126 5127
        }

5128 5129
        case (ast.expr_alt(?expr, ?arms, ?ann)) {
            ret trans_alt(cx, expr, arms, ann);
P
Patrick Walton 已提交
5130 5131
        }

P
Patrick Walton 已提交
5132
        case (ast.expr_block(?blk, _)) {
5133 5134 5135 5136 5137 5138 5139 5140
            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);
5141
        }
5142

5143
        case (ast.expr_assign(?dst, ?src, ?ann)) {
5144
            auto lhs_res = trans_lval(cx, dst);
5145
            check (lhs_res.is_mem);
5146
            auto rhs_res = trans_expr(lhs_res.res.bcx, src);
5147
            auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
G
Graydon Hoare 已提交
5148
            // FIXME: calculate copy init-ness in typestate.
5149 5150
            ret copy_ty(rhs_res.bcx, DROP_EXISTING,
                        lhs_res.res.val, rhs_res.val, t);
5151
        }
G
Graydon Hoare 已提交
5152

5153
        case (ast.expr_assign_op(?op, ?dst, ?src, ?ann)) {
5154
            auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
5155
            auto lhs_res = trans_lval(cx, dst);
5156
            check (lhs_res.is_mem);
5157
            auto rhs_res = trans_expr(lhs_res.res.bcx, src);
5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169
            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);
5170 5171
            auto v = trans_eager_binop(rhs_res.bcx, op, t,
                                       lhs_val, rhs_res.val);
5172
            // FIXME: calculate copy init-ness in typestate.
5173 5174
            ret copy_ty(v.bcx, DROP_EXISTING,
                        lhs_res.res.val, v.val, t);
5175 5176
        }

5177 5178 5179 5180
        case (ast.expr_bind(?f, ?args, ?ann)) {
            ret trans_bind(cx, f, args, ann);
        }

G
Graydon Hoare 已提交
5181
        case (ast.expr_call(?f, ?args, ?ann)) {
5182
            ret trans_call(cx, f, none[ValueRef], args, ann);
5183 5184
        }

5185
        case (ast.expr_cast(?e, _, ?ann)) {
5186
            ret trans_cast(cx, e, ann);
5187
        }
G
Graydon Hoare 已提交
5188

5189
        case (ast.expr_vec(?args, _, ?ann)) {
G
Graydon Hoare 已提交
5190 5191 5192
            ret trans_vec(cx, args, ann);
        }

G
Graydon Hoare 已提交
5193 5194 5195
        case (ast.expr_tup(?args, ?ann)) {
            ret trans_tup(cx, args, ann);
        }
G
Graydon Hoare 已提交
5196

5197 5198
        case (ast.expr_rec(?args, ?base, ?ann)) {
            ret trans_rec(cx, args, base, ann);
5199 5200
        }

5201
        case (ast.expr_ext(_, _, _, ?expanded, _)) {
5202
            ret trans_expr(cx, expanded);
5203 5204
        }

5205
        case (ast.expr_fail(_)) {
5206
            ret trans_fail(cx, some[common.span](e.span), "explicit failure");
5207 5208
        }

M
Marijn Haverbeke 已提交
5209 5210
        case (ast.expr_log(?lvl, ?a, _)) {
            ret trans_log(lvl, cx, a);
5211 5212
        }

5213
        case (ast.expr_check_expr(?a, _)) {
5214 5215 5216
            ret trans_check_expr(cx, a);
        }

5217
        case (ast.expr_break(?a)) {
5218 5219 5220
            ret trans_break(cx);
        }

5221
        case (ast.expr_cont(?a)) {
5222 5223 5224
            ret trans_cont(cx);
        }

5225
        case (ast.expr_ret(?e, _)) {
5226 5227 5228
            ret trans_ret(cx, e);
        }

5229
        case (ast.expr_put(?e, _)) {
5230 5231 5232
            ret trans_put(cx, e);
        }

5233
        case (ast.expr_be(?e, _)) {
5234 5235 5236
            ret trans_be(cx, e);
        }

B
Brian Anderson 已提交
5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252
        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);
        }

5253
        case (_) {
5254
            // The expression is an lvalue. Fall through.
5255
        }
5256
    }
5257 5258 5259 5260

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

5261
    auto t = ty.expr_ty(cx.fcx.lcx.ccx.tcx, e);
5262
    auto sub = trans_lval(cx, e);
5263
    ret res(sub.res.bcx, load_if_immediate(sub.res.bcx, sub.res.val, t));
5264 5265
}

5266
// We pass structural values around the compiler "by pointer" and
5267 5268 5269 5270 5271
// 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.

5272
fn type_is_immediate(@crate_ctxt ccx, ty.t t) -> bool {
5273 5274 5275
    ret ty.type_is_scalar(ccx.tcx, t) ||
        ty.type_is_boxed(ccx.tcx, t) ||
        ty.type_is_native(ccx.tcx, t);
5276 5277 5278 5279 5280 5281 5282 5283
}

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

5285
fn spill_if_immediate(@block_ctxt cx, ValueRef v, ty.t t) -> ValueRef {
5286
    if (type_is_immediate(cx.fcx.lcx.ccx, t)) {
5287 5288 5289 5290 5291
        ret do_spill(cx, v);
    }
    ret v;
}

5292
fn load_if_immediate(@block_ctxt cx, ValueRef v, ty.t t) -> ValueRef {
5293
    if (type_is_immediate(cx.fcx.lcx.ccx, t)) {
5294 5295
        ret cx.build.Load(v);
    }
5296
    ret v;
5297 5298
}

M
Marijn Haverbeke 已提交
5299
fn trans_log(int lvl, @block_ctxt cx, @ast.expr e) -> result {
5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314
    auto lcx = cx.fcx.lcx;
    auto modname = _str.connect(lcx.module_path, ".");
    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(),
                                    _str.buf("_rust_mod_log_" + modname));
        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);
    }

5315
    auto log_cx = new_scope_block_ctxt(cx, "log");
5316 5317
    auto after_cx = new_sub_block_ctxt(cx, "after");
    auto load = cx.build.Load(global);
M
Marijn Haverbeke 已提交
5318
    auto test = cx.build.ICmp(lib.llvm.LLVMIntSGE, load, C_int(lvl));
5319 5320 5321
    cx.build.CondBr(test, log_cx.llbb, after_cx.llbb);

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

5324
    auto log_bcx = sub.bcx;
5325
    if (ty.type_is_fp(cx.fcx.lcx.ccx.tcx, e_ty)) {
5326 5327
        let TypeRef tr;
        let bool is32bit = false;
5328
        alt (ty.struct(cx.fcx.lcx.ccx.tcx, e_ty)) {
5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340
            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) {
5341
            auto uval = trans_upcall(log_bcx,
5342
                                     "upcall_log_float",
5343 5344
                                     vec(C_int(lvl), sub.val),
                                     false);
5345
            log_bcx = uval.bcx;
5346
        } else {
5347
            auto tmp = alloca(log_bcx, tr);
5348
            sub.bcx.build.Store(sub.val, tmp);
5349
            auto uval = trans_upcall(log_bcx,
5350
                                     "upcall_log_double",
5351
                                     vec(C_int(lvl), vp2i(log_bcx, tmp)),
5352
                                     false);
5353
            log_bcx = uval.bcx;
5354
        }
5355
    } else {
5356
        alt (ty.struct(cx.fcx.lcx.ccx.tcx, e_ty)) {
5357
            case (ty.ty_str) {
5358 5359 5360 5361 5362
                auto v = vp2i(log_bcx, sub.val);
                log_bcx = trans_upcall(log_bcx,
                                       "upcall_log_str",
                                       vec(C_int(lvl), v),
                                       false).bcx;
5363 5364
            }
            case (_) {
M
Marijn Haverbeke 已提交
5365
                auto v = vec(C_int(lvl), sub.val);
5366 5367 5368
                log_bcx = trans_upcall(log_bcx,
                                       "upcall_log_int",
                                       v, false).bcx;
5369
            }
5370 5371
        }
    }
5372

5373 5374 5375
    log_bcx = trans_block_cleanups(log_bcx, log_cx);
    log_bcx.build.Br(after_cx.llbb);

5376
    ret res(after_cx, C_nil());
5377 5378
}

5379
fn trans_check_expr(@block_ctxt cx, @ast.expr e) -> result {
5380 5381
    auto cond_res = trans_expr(cx, e);

5382
    auto expr_str = pretty.pprust.expr_to_str(e);
5383
    auto fail_cx = new_sub_block_ctxt(cx, "fail");
5384
    auto fail_res = trans_fail(fail_cx, some[common.span](e.span), expr_str);
5385

5386
    auto next_cx = new_sub_block_ctxt(cx, "next");
5387 5388 5389 5390 5391 5392
    cond_res.bcx.build.CondBr(cond_res.val,
                              next_cx.llbb,
                              fail_cx.llbb);
    ret res(next_cx, C_nil());
}

5393 5394
fn trans_fail(@block_ctxt cx, option.t[common.span] sp_opt, str fail_str)
        -> result {
5395
    auto V_fail_str = p2i(C_cstr(cx.fcx.lcx.ccx, fail_str));
5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409

    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 已提交
5410 5411
    auto args = vec(V_fail_str, V_filename, C_int(V_line));

5412
    auto sub = trans_upcall(cx, "upcall_fail", args, false);
5413 5414
    sub.bcx.build.Unreachable();
    ret res(sub.bcx, C_nil());
B
Brian Anderson 已提交
5415 5416
}

5417
fn trans_put(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
5418 5419 5420 5421 5422
    auto llcallee = C_nil();
    auto llenv = C_nil();

    alt (cx.fcx.lliterbody) {
        case (some[ValueRef](?lli)) {
5423
            auto slot = alloca(cx, val_ty(lli));
5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435
            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;
5436
    auto dummy_retslot = alloca(bcx, T_nil());
5437 5438 5439 5440
    let vec[ValueRef] llargs = vec(dummy_retslot, cx.fcx.lltaskptr, llenv);
    alt (e) {
        case (none[@ast.expr]) { }
        case (some[@ast.expr](?x)) {
5441
            auto e_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, x);
5442 5443 5444
            auto arg = rec(mode=ast.alias, ty=e_ty);
            auto arg_tys = type_of_explicit_args(cx.fcx.lcx.ccx, vec(arg));
            auto r = trans_arg_expr(bcx, arg, arg_tys.(0), x);
5445
            bcx = r.bcx;
5446
            llargs += vec(r.val);
5447 5448
        }
    }
5449

5450
    ret res(bcx, bcx.build.FastCall(llcallee, llargs));
5451 5452
}

5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472
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) {
                        case (option.some[@block_ctxt](?_cont)) {
                            bcx.build.Br(_cont.llbb);
                        }
                        case (_) {
                            bcx.build.Br(cleanup_cx.llbb);
                        }
                    }
                }
5473
                ret res(bcx, C_nil());
5474 5475 5476 5477 5478 5479 5480 5481
            }
            case (_) {
                alt (cleanup_cx.parent) {
                    case (parent_some(?cx)) { cleanup_cx = cx; }
                }
            }
        }
    }
5482
    fail;
5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493
}

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


5494 5495 5496 5497
fn trans_ret(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
    auto bcx = cx;
    auto val = C_nil();

5498 5499
    alt (e) {
        case (some[@ast.expr](?x)) {
5500
            auto t = ty.expr_ty(cx.fcx.lcx.ccx.tcx, x);
5501 5502 5503
            auto r = trans_expr(cx, x);
            bcx = r.bcx;
            val = r.val;
5504
            bcx = copy_ty(bcx, INIT, cx.fcx.llretptr, val, t).bcx;
5505
        }
5506 5507 5508 5509 5510
        case (_) {
            auto t = llvm.LLVMGetElementType(val_ty(cx.fcx.llretptr));
            auto null = lib.llvm.llvm.LLVMConstNull(t);
            bcx.build.Store(null, cx.fcx.llretptr);
        }
5511 5512
    }

5513 5514
    // Run all cleanups and back out.
    let bool more_cleanups = true;
5515
    auto cleanup_cx = cx;
5516
    while (more_cleanups) {
5517
        bcx = trans_block_cleanups(bcx, cleanup_cx);
5518
        alt (cleanup_cx.parent) {
5519
            case (parent_some(?b)) {
5520
                cleanup_cx = b;
5521 5522 5523 5524 5525 5526 5527
            }
            case (parent_none) {
                more_cleanups = false;
            }
        }
    }

5528 5529
    bcx.build.RetVoid();
    ret res(bcx, C_nil());
5530 5531
}

5532
fn trans_be(@block_ctxt cx, @ast.expr e) -> result {
5533
    // FIXME: This should be a typestate precondition
5534
    check (ast.is_call_expr(e));
5535 5536
    // FIXME: Turn this into a real tail call once
    // calling convention issues are settled
5537 5538 5539
    ret trans_ret(cx, some(e));
}

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

5542
    auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
B
Brian Anderson 已提交
5543
    auto unit_ty;
5544
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
B
Brian Anderson 已提交
5545 5546 5547 5548
        case (ty.ty_port(?t)) {
            unit_ty = t;
        }
        case (_) {
5549
            cx.fcx.lcx.ccx.sess.bug("non-port type in trans_port");
B
Brian Anderson 已提交
5550 5551 5552 5553
            fail;
        }
    }

5554
    auto llunit_ty = type_of(cx.fcx.lcx.ccx, unit_ty);
B
Brian Anderson 已提交
5555 5556 5557 5558

    auto bcx = cx;
    auto unit_sz = size_of(bcx, unit_ty);
    bcx = unit_sz.bcx;
5559
    auto sub = trans_upcall(bcx, "upcall_new_port", vec(unit_sz.val), false);
B
Brian Anderson 已提交
5560
    bcx = sub.bcx;
5561
    auto llty = type_of(cx.fcx.lcx.ccx, t);
B
Brian Anderson 已提交
5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575
    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);
5576
    auto sub = trans_upcall(bcx, "upcall_new_chan", vec(prt_val), false);
B
Brian Anderson 已提交
5577 5578
    bcx = sub.bcx;

5579 5580
    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 已提交
5581 5582 5583 5584 5585 5586 5587 5588 5589
    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 {
5590 5591 5592 5593 5594 5595 5596

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

5597
    auto chan_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
5598
    auto unit_ty;
5599
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, chan_ty)) {
5600 5601 5602 5603
        case (ty.ty_chan(?t)) {
            unit_ty = t;
        }
        case (_) {
5604
            bcx.fcx.lcx.ccx.sess.bug("non-chan type in trans_send");
5605 5606 5607 5608
            fail;
        }
    }

5609 5610 5611 5612
    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;
5613

5614 5615
    find_scope_cx(bcx).cleanups +=
        vec(clean(bind drop_ty(_, data_alloc.val, unit_ty)));
5616

5617 5618
    auto sub = trans_upcall(bcx, "upcall_send",
                            vec(vp2i(bcx, chn.val),
5619
                                vp2i(bcx, data_alloc.val)), false);
5620 5621
    bcx = sub.bcx;

5622
    ret res(bcx, chn.val);
B
Brian Anderson 已提交
5623 5624 5625 5626
}

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

    auto bcx = cx;
B
Brian Anderson 已提交
5629
    auto data = trans_lval(bcx, lhs);
5630
    check (data.is_mem);
B
Brian Anderson 已提交
5631
    bcx = data.res.bcx;
5632
    auto unit_ty = node_ann_type(bcx.fcx.lcx.ccx, ann);
5633 5634 5635

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

fn recv_val(@block_ctxt cx, ValueRef lhs, @ast.expr rhs,
5639
            ty.t unit_ty, copy_action action) -> result {
5640 5641

    auto bcx = cx;
5642 5643
    auto prt = trans_expr(bcx, rhs);
    bcx = prt.bcx;
B
Brian Anderson 已提交
5644

5645
    auto sub = trans_upcall(bcx, "upcall_recv",
5646
                            vec(vp2i(bcx, lhs),
5647
                                vp2i(bcx, prt.val)), false);
5648 5649
    bcx = sub.bcx;

5650
    auto data_load = load_if_immediate(bcx, lhs, unit_ty);
5651
    auto cp = copy_ty(bcx, action, lhs, data_load, unit_ty);
5652
    bcx = cp.bcx;
B
Brian Anderson 已提交
5653

5654
    // TODO: Any cleanup need to be done here?
5655

5656
    ret res(bcx, lhs);
B
Brian Anderson 已提交
5657 5658
}

5659 5660 5661
fn init_local(@block_ctxt cx, @ast.local local) -> result {

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

    find_scope_cx(cx).cleanups +=
5668
        vec(clean(bind drop_slot(_, llptr, ty)));
5669 5670

    alt (local.init) {
5671
        case (some[ast.initializer](?init)) {
5672 5673 5674 5675 5676 5677 5678 5679 5680
            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;
                }
            }
5681 5682
        }
        case (_) {
5683
            bcx = zero_alloca(bcx, llptr, ty).bcx;
5684 5685 5686 5687 5688
        }
    }
    ret res(bcx, llptr);
}

5689
fn zero_alloca(@block_ctxt cx, ValueRef llptr, ty.t t) -> result {
5690
    auto bcx = cx;
5691
    if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
5692 5693 5694
        auto llsz = size_of(bcx, t);
        bcx = call_bzero(llsz.bcx, llptr, llsz.val).bcx;
    } else {
5695
        auto llty = type_of(bcx.fcx.lcx.ccx, t);
5696 5697 5698 5699 5700 5701
        auto null = lib.llvm.llvm.LLVMConstNull(llty);
        bcx.build.Store(null, llptr);
    }
    ret res(bcx, llptr);
 }

5702 5703
fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
    auto bcx = cx;
5704
    alt (s.node) {
5705
        case (ast.stmt_expr(?e,_)) {
5706
            bcx = trans_expr(cx, e).bcx;
5707
        }
5708

5709
        case (ast.stmt_decl(?d,_)) {
5710 5711
            alt (d.node) {
                case (ast.decl_local(?local)) {
5712
                    bcx = init_local(bcx, local).bcx;
5713
                }
G
Graydon Hoare 已提交
5714
                case (ast.decl_item(?i)) {
5715
                    trans_item(cx.fcx.lcx, *i);
G
Graydon Hoare 已提交
5716
                }
5717 5718
            }
        }
5719
        case (_) {
5720
            cx.fcx.lcx.ccx.sess.unimpl("stmt variant");
5721 5722
        }
    }
5723
    ret res(bcx, C_nil());
5724 5725
}

5726
fn new_builder(BasicBlockRef llbb) -> builder {
5727 5728
    let BuilderRef llbuild = llvm.LLVMCreateBuilder();
    llvm.LLVMPositionBuilderAtEnd(llbuild, llbb);
5729
    ret builder(llbuild, @mutable false);
5730 5731
}

5732 5733
// You probably don't want to use this one. See the
// next three functions instead.
5734
fn new_block_ctxt(@fn_ctxt cx, block_parent parent,
5735
                  block_kind kind,
5736
                  str name) -> @block_ctxt {
5737
    let vec[cleanup] cleanups = vec();
5738
    let BasicBlockRef llbb =
5739
        llvm.LLVMAppendBasicBlock(cx.llfn,
5740
                                  _str.buf(cx.lcx.ccx.names.next(name)));
5741

5742
    ret @rec(llbb=llbb,
5743
             build=new_builder(llbb),
5744
             parent=parent,
5745
             kind=kind,
5746
             mutable cleanups=cleanups,
5747 5748 5749
             fcx=cx);
}

5750 5751
// 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 {
5752 5753
    ret new_block_ctxt(fcx, parent_none, SCOPE_BLOCK,
                       "function top level");
5754
}
5755

5756 5757
// 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 {
5758
    ret new_block_ctxt(bcx.fcx, parent_some(bcx), SCOPE_BLOCK, n);
5759 5760
}

5761 5762 5763 5764 5765 5766
fn new_loop_scope_block_ctxt(@block_ctxt bcx, option.t[@block_ctxt] _cont,
                             @block_ctxt _break, str n) -> @block_ctxt {
    ret new_block_ctxt(bcx.fcx, parent_some(bcx),
                       LOOP_SCOPE_BLOCK(_cont, _break), n);
}

5767
// Use this when you're making a general CFG BB within a scope.
5768
fn new_sub_block_ctxt(@block_ctxt bcx, str n) -> @block_ctxt {
5769
    ret new_block_ctxt(bcx.fcx, parent_some(bcx), NON_SCOPE_BLOCK, n);
5770
}
5771

5772

5773 5774
fn trans_block_cleanups(@block_ctxt cx,
                        @block_ctxt cleanup_cx) -> @block_ctxt {
5775
    auto bcx = cx;
5776

5777
    if (cleanup_cx.kind == NON_SCOPE_BLOCK) {
5778
        check (_vec.len[cleanup](cleanup_cx.cleanups) == 0u);
5779 5780
    }

5781 5782 5783 5784
    auto i = _vec.len[cleanup](cleanup_cx.cleanups);
    while (i > 0u) {
        i -= 1u;
        auto c = cleanup_cx.cleanups.(i);
5785
        alt (c) {
5786
            case (clean(?cfn)) {
5787
                bcx = cfn(bcx).bcx;
5788 5789 5790
            }
        }
    }
5791 5792 5793
    ret bcx;
}

5794 5795 5796 5797 5798
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) {
5799
            case (ast.stmt_decl(?d,_)) {
5800 5801 5802 5803
                alt (d.node) {
                    case (ast.decl_local(?local)) {
                        put local;
                    }
5804
                    case (_) { /* fall through */ }
5805 5806
                }
            }
5807
            case (_) { /* fall through */ }
5808 5809 5810 5811
        }
    }
}

5812 5813 5814 5815 5816 5817 5818 5819 5820 5821
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);
}

5822
fn alloc_ty(@block_ctxt cx, ty.t t) -> result {
5823
    auto val = C_int(0);
5824
    if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
5825 5826 5827 5828 5829 5830 5831 5832 5833

        // 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);
5834
    } else {
5835
        val = alloca(cx, type_of(cx.fcx.lcx.ccx, t));
5836
    }
5837 5838 5839 5840 5841 5842 5843
    // 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);
5844 5845
}

5846
fn alloc_local(@block_ctxt cx, @ast.local local) -> result {
5847
    auto t = node_ann_type(cx.fcx.lcx.ccx, local.ann);
5848 5849 5850 5851 5852
    auto r = alloc_ty(cx, t);
    r.bcx.fcx.lllocals.insert(local.id, r.val);
    ret r;
}

5853
fn trans_block(@block_ctxt cx, &ast.block b) -> result {
5854 5855
    auto bcx = cx;

5856
    for each (@ast.local local in block_locals(b)) {
5857
        bcx = alloc_local(bcx, local).bcx;
5858
    }
5859
    auto r = res(bcx, C_nil());
5860

5861
    for (@ast.stmt s in b.node.stmts) {
5862 5863
        r = trans_stmt(bcx, *s);
        bcx = r.bcx;
5864 5865 5866 5867 5868
        // 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;
        }
5869
    }
5870

5871 5872 5873 5874
    alt (b.node.expr) {
        case (some[@ast.expr](?e)) {
            r = trans_expr(bcx, e);
            bcx = r.bcx;
5875

5876 5877
            if (is_terminated(bcx)) {
                ret r;
5878
            } else {
5879 5880
                auto r_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, e);
                if (!ty.type_is_nil(cx.fcx.lcx.ccx.tcx, r_ty)) {
5881
                    // The value resulting from the block gets copied into an
B
Brian Anderson 已提交
5882
                    // alloca created in an outer scope and its refcount
5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894
                    // 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.
5895
                    auto res_alloca = alloc_ty(bcx, r_ty);
5896 5897
                    auto llbcx = llallocas_block_ctxt(bcx.fcx);
                    zero_alloca(llbcx, res_alloca.val, r_ty);
5898 5899

                    // Now we're working in our own block context again
5900 5901 5902 5903 5904 5905
                    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,
5906
                                       ty.t t) -> result {
5907
                        auto reg_val = load_if_immediate(cx,
5908 5909 5910 5911 5912 5913 5914 5915
                                                            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));
                }
5916 5917 5918 5919 5920 5921 5922
            }
        }
        case (none[@ast.expr]) {
            r = res(bcx, C_nil());
        }
    }

5923
    bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
5924
    ret res(bcx, r.val);
5925 5926
}

5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937
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);
}

5938 5939 5940 5941 5942 5943 5944
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args

5945
fn new_fn_ctxt(@local_ctxt cx,
5946
               ValueRef llfndecl) -> @fn_ctxt {
5947

5948 5949 5950
    let ValueRef llretptr = llvm.LLVMGetParam(llfndecl, 0u);
    let ValueRef lltaskptr = llvm.LLVMGetParam(llfndecl, 1u);
    let ValueRef llenv = llvm.LLVMGetParam(llfndecl, 2u);
5951 5952

    let hashmap[ast.def_id, ValueRef] llargs = new_def_hash[ValueRef]();
5953 5954
    let hashmap[ast.def_id, ValueRef] llobjfields = new_def_hash[ValueRef]();
    let hashmap[ast.def_id, ValueRef] lllocals = new_def_hash[ValueRef]();
5955
    let hashmap[ast.def_id, ValueRef] llupvars = new_def_hash[ValueRef]();
5956

5957 5958 5959
    let BasicBlockRef llallocas =
        llvm.LLVMAppendBasicBlock(llfndecl, _str.buf("allocas"));

5960
    ret @rec(llfn=llfndecl,
5961
             lltaskptr=lltaskptr,
5962 5963
             llenv=llenv,
             llretptr=llretptr,
5964
             mutable llallocas = llallocas,
5965
             mutable llself=none[self_vt],
5966
             mutable lliterbody=none[ValueRef],
5967
             llargs=llargs,
5968
             llobjfields=llobjfields,
5969
             lllocals=lllocals,
5970
             llupvars=llupvars,
5971
             mutable lltydescs=_vec.empty[ValueRef](),
5972
             lcx=cx);
5973 5974
}

5975 5976 5977 5978 5979 5980 5981
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args

5982
fn create_llargs_for_fn_args(&@fn_ctxt cx,
5983
                             ast.proto proto,
5984 5985
                             option.t[tup(TypeRef, ty.t)] ty_self,
                             ty.t ret_ty,
5986
                             &vec[ast.arg] args,
5987
                             &vec[ast.ty_param] ty_params) {
5988 5989

    auto arg_n = 3u;
5990

5991
    alt (ty_self) {
5992
        case (some[tup(TypeRef, ty.t)](?tt)) {
5993 5994
            cx.llself = some[self_vt](rec(v = cx.llenv, t = tt._1));
        }
5995
        case (none[tup(TypeRef, ty.t)]) {
5996
            auto i = 0u;
5997 5998
            for (ast.ty_param tp in ty_params) {
                auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n);
5999
                check (llarg as int != 0);
6000
                cx.lltydescs += vec(llarg);
6001
                arg_n += 1u;
6002
                i += 1u;
6003
            }
6004
        }
6005 6006
    }

6007
    if (proto == ast.proto_iter) {
6008
        auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n);
6009
        check (llarg as int != 0);
6010 6011 6012
        cx.lliterbody = some[ValueRef](llarg);
        arg_n += 1u;
    }
6013

6014 6015
    for (ast.arg arg in args) {
        auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n);
6016
        check (llarg as int != 0);
6017 6018 6019 6020 6021
        cx.llargs.insert(arg.id, llarg);
        arg_n += 1u;
    }
}

6022 6023 6024 6025
// 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.

6026
fn copy_any_self_to_alloca(@fn_ctxt fcx,
6027
                           option.t[tup(TypeRef, ty.t)] ty_self) {
6028

6029
    auto bcx = llallocas_block_ctxt(fcx);
6030

6031
    alt (fcx.llself) {
6032
        case (some[self_vt](?s_vt)) {
6033
            alt (ty_self) {
6034
                case (some[tup(TypeRef, ty.t)](?tt)) {
6035 6036 6037
                    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));
6038 6039 6040 6041 6042 6043
                }
            }
        }
        case (_) {
        }
    }
6044 6045 6046 6047 6048 6049 6050 6051 6052 6053
}


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

6055
    for (ast.arg aarg in args) {
6056
        if (aarg.mode != ast.alias) {
6057
            auto arg_t = type_of_arg(fcx.lcx, arg_tys.(arg_n));
6058 6059 6060
            auto a = alloca(bcx, arg_t);
            auto argval = fcx.llargs.get(aarg.id);
            bcx.build.Store(argval, a);
6061
            // Overwrite the llargs entry for this arg with its alloca.
6062
            fcx.llargs.insert(aarg.id, a);
6063 6064
        }

6065 6066
        arg_n += 1u;
    }
6067 6068

    fcx.llallocas = bcx.llbb;
6069 6070
}

6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085
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;
    }
}


6086 6087 6088 6089 6090
fn is_terminated(@block_ctxt cx) -> bool {
    auto inst = llvm.LLVMGetLastInstruction(cx.llbb);
    ret llvm.LLVMIsATerminatorInst(inst) as int != 0;
}

6091
fn arg_tys_of_fn(@crate_ctxt ccx, ast.ann ann) -> vec[ty.arg] {
6092
    alt (ty.struct(ccx.tcx, ty.ann_to_type(ann))) {
6093
        case (ty.ty_fn(_, ?arg_tys, _)) {
6094 6095 6096 6097 6098 6099
            ret arg_tys;
        }
    }
    fail;
}

6100
fn ret_ty_of_fn_ty(@crate_ctxt ccx, ty.t t) -> ty.t {
6101
    alt (ty.struct(ccx.tcx, t)) {
6102
        case (ty.ty_fn(_, _, ?ret_ty)) {
6103 6104 6105 6106 6107 6108
            ret ret_ty;
        }
    }
    fail;
}

6109

6110 6111
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));
6112 6113
}

6114
fn populate_fn_ctxt_from_llself(@fn_ctxt fcx, self_vt llself) {
6115
    auto bcx = llallocas_block_ctxt(fcx);
6116

6117
    let vec[ty.t] field_tys = vec();
6118

6119 6120
    for (ast.obj_field f in bcx.fcx.lcx.obj_fields) {
        field_tys += vec(node_ann_type(bcx.fcx.lcx.ccx, f.ann));
6121 6122
    }

6123 6124
    // Synthesize a tuple type for the fields so that GEP_tup_like() can work
    // its magic.
6125
    auto fields_tup_ty = ty.mk_imm_tup(fcx.lcx.ccx.tcx, field_tys);
6126

6127 6128
    auto n_typarams = _vec.len[ast.ty_param](bcx.fcx.lcx.obj_typarams);
    let TypeRef llobj_box_ty = T_obj_ptr(bcx.fcx.lcx.ccx.tn, n_typarams);
6129 6130

    auto box_cell =
6131
        bcx.build.GEP(llself.v,
6132 6133
                      vec(C_int(0),
                          C_int(abi.obj_field_box)));
6134

6135
    auto box_ptr = bcx.build.Load(box_cell);
6136

6137
    box_ptr = bcx.build.PointerCast(box_ptr, llobj_box_ty);
6138

6139
    auto obj_typarams = bcx.build.GEP(box_ptr,
6140 6141 6142
                                     vec(C_int(0),
                                         C_int(abi.box_rc_field_body),
                                         C_int(abi.obj_body_elt_typarams)));
6143

6144 6145 6146
    // 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),
6147
        llsize_of(llvm.LLVMGetElementType(val_ty(obj_typarams))));
6148 6149 6150 6151

    // 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 *.
6152
    if (!ty.type_has_dynamic_size(fcx.lcx.ccx.tcx, fields_tup_ty)) {
6153
        auto llfields_ty = type_of(fcx.lcx.ccx, fields_tup_ty);
6154 6155 6156 6157 6158
        obj_fields = vi2p(bcx, obj_fields, T_ptr(llfields_ty));
    } else {
        obj_fields = vi2p(bcx, obj_fields, T_ptr(T_i8()));
    }

6159 6160

    let int i = 0;
6161

6162
    for (ast.ty_param p in fcx.lcx.obj_typarams) {
6163 6164 6165 6166
        let ValueRef lltyparam = bcx.build.GEP(obj_typarams,
                                               vec(C_int(0),
                                                   C_int(i)));
        lltyparam = bcx.build.Load(lltyparam);
6167
        fcx.lltydescs += vec(lltyparam);
6168 6169 6170 6171
        i += 1;
    }

    i = 0;
6172
    for (ast.obj_field f in fcx.lcx.obj_fields) {
6173
        auto rslt = GEP_tup_like(bcx, fields_tup_ty, obj_fields, vec(0, i));
6174
        bcx = llallocas_block_ctxt(fcx);
6175
        auto llfield = rslt.val;
6176
        fcx.llobjfields.insert(f.id, llfield);
6177 6178
        i += 1;
    }
6179

6180
    fcx.llallocas = bcx.llbb;
6181 6182
}

6183
fn trans_fn(@local_ctxt cx, &ast._fn f, ast.def_id fid,
6184
            option.t[tup(TypeRef, ty.t)] ty_self,
6185
            &vec[ast.ty_param] ty_params, &ast.ann ann) {
6186
    auto llfndecl = cx.ccx.item_ids.get(fid);
6187

6188
    auto fcx = new_fn_ctxt(cx, llfndecl);
6189
    create_llargs_for_fn_args(fcx, f.proto,
6190
                              ty_self, ret_ty_of_fn(cx.ccx, ann),
6191
                              f.decl.inputs, ty_params);
6192

6193
    copy_any_self_to_alloca(fcx, ty_self);
6194 6195

    alt (fcx.llself) {
6196
        case (some[self_vt](?llself)) {
6197
            populate_fn_ctxt_from_llself(fcx, llself);
6198 6199 6200 6201
        }
        case (_) {
        }
    }
6202

6203 6204
    auto arg_tys = arg_tys_of_fn(fcx.lcx.ccx, ann);
    copy_args_to_allocas(fcx, f.decl.inputs, arg_tys);
6205 6206

    auto bcx = new_top_block_ctxt(fcx);
6207 6208 6209

    add_cleanups_for_args(bcx, f.decl.inputs, arg_tys);

6210 6211
    auto lltop = bcx.llbb;

6212 6213
    auto res = trans_block(bcx, f.body);
    if (!is_terminated(res.bcx)) {
6214 6215
        // FIXME: until LLVM has a unit type, we are moving around
        // C_nil values rather than their void type.
6216
        res.bcx.build.RetVoid();
6217
    }
6218 6219 6220

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

6223
fn trans_vtbl(@local_ctxt cx,
6224
              TypeRef llself_ty,
6225
              ty.t self_ty,
6226 6227
              &ast._obj ob,
              &vec[ast.ty_param] ty_params) -> ValueRef {
6228 6229 6230 6231 6232 6233 6234 6235 6236
    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);
6237 6238 6239 6240 6241 6242 6243 6244 6245

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

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

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

6247
        auto llfnty = T_nil();
6248
        alt (ty.struct(cx.ccx.tcx, node_ann_type(cx.ccx, m.node.ann))) {
6249
            case (ty.ty_fn(?proto, ?inputs, ?output)) {
6250
                llfnty = type_of_fn_full(cx.ccx, proto,
6251
                                         some[TypeRef](llself_ty),
6252 6253
                                         inputs, output,
                                         _vec.len[ast.ty_param](ty_params));
6254 6255 6256
            }
        }

6257
        let @local_ctxt mcx = extend_path(cx, m.node.ident);
6258
        let str s = mangle_name_by_seq(mcx.ccx, mcx.path, "method");
6259 6260 6261 6262
        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);
6263

6264
        trans_fn(mcx, m.node.meth, m.node.id,
6265
                 some[tup(TypeRef, ty.t)](tup(llself_ty, self_ty)),
6266
                 ty_params, m.node.ann);
6267
        methods += vec(llfn);
G
Graydon Hoare 已提交
6268
    }
6269
    auto vtbl = C_struct(methods);
6270
    auto vtbl_name = mangle_name_by_seq(cx.ccx, cx.path, "vtbl");
6271
    auto gvar = llvm.LLVMAddGlobal(cx.ccx.llmod, val_ty(vtbl),
6272
                                   _str.buf(vtbl_name));
6273 6274
    llvm.LLVMSetInitializer(gvar, vtbl);
    llvm.LLVMSetGlobalConstant(gvar, True);
6275
    llvm.LLVMSetLinkage(gvar, lib.llvm.LLVMInternalLinkage
6276
                        as llvm.Linkage);
6277
    ret gvar;
G
Graydon Hoare 已提交
6278 6279
}

6280
fn trans_dtor(@local_ctxt cx,
6281
              TypeRef llself_ty,
6282
              ty.t self_ty,
6283 6284 6285
              &vec[ast.ty_param] ty_params,
              &@ast.method dtor) -> ValueRef {

6286
    auto llfnty = T_dtor(cx.ccx, llself_ty);
6287
    let @local_ctxt dcx = extend_path(cx, "drop");
6288
    let str s = mangle_name_by_seq(dcx.ccx, dcx.path, "drop");
6289 6290 6291
    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);
6292 6293

    trans_fn(dcx, dtor.node.meth, dtor.node.id,
6294
             some[tup(TypeRef, ty.t)](tup(llself_ty, self_ty)),
6295 6296 6297 6298 6299
             ty_params, dtor.node.ann);

    ret llfn;
}

6300
fn trans_obj(@local_ctxt cx, &ast._obj ob, ast.def_id oid,
6301
             &vec[ast.ty_param] ty_params, &ast.ann ann) {
6302 6303
    auto ccx = cx.ccx;
    auto llctor_decl = ccx.item_ids.get(oid);
6304

6305
    // Translate obj ctor args to function arguments.
6306 6307 6308 6309 6310 6311 6312 6313
    let vec[ast.arg] fn_args = vec();
    for (ast.obj_field f in ob.fields) {
        fn_args += vec(rec(mode=ast.alias,
                           ty=f.ty,
                           ident=f.ident,
                           id=f.id));
    }

6314
    auto fcx = new_fn_ctxt(cx, llctor_decl);
6315
    create_llargs_for_fn_args(fcx, ast.proto_fn,
6316
                              none[tup(TypeRef, ty.t)],
6317
                              ret_ty_of_fn(ccx, ann),
6318
                              fn_args, ty_params);
6319

6320
    let vec[ty.arg] arg_tys = arg_tys_of_fn(ccx, ann);
6321 6322 6323 6324
    copy_args_to_allocas(fcx, fn_args, arg_tys);

    auto bcx = new_top_block_ctxt(fcx);
    auto lltop = bcx.llbb;
6325

6326
    auto self_ty = ret_ty_of_fn(ccx, ann);
6327
    auto llself_ty = type_of(ccx, self_ty);
6328
    auto pair = bcx.fcx.llretptr;
6329

6330
    auto vtbl = trans_vtbl(cx, llself_ty, self_ty, ob, ty_params);
6331 6332 6333
    auto pair_vtbl = bcx.build.GEP(pair,
                                   vec(C_int(0),
                                       C_int(abi.obj_field_vtbl)));
6334 6335 6336
    auto pair_box = bcx.build.GEP(pair,
                                  vec(C_int(0),
                                      C_int(abi.obj_field_box)));
6337
    bcx.build.Store(vtbl, pair_vtbl);
6338

6339
    let TypeRef llbox_ty = T_opaque_obj_ptr(ccx.tn);
6340 6341 6342 6343

    if (_vec.len[ast.ty_param](ty_params) == 0u &&
        _vec.len[ty.arg](arg_tys) == 0u) {
        // Store null into pair, if no args or typarams.
6344 6345 6346
        bcx.build.Store(C_null(llbox_ty), pair_box);
    } else {
        // Malloc a box for the body and copy args in.
6347
        let vec[ty.t] obj_fields = vec();
6348
        for (ty.arg a in arg_tys) {
6349
            _vec.push[ty.t](obj_fields, a.ty);
6350
        }
6351 6352

        // Synthesize an obj body type.
6353
        auto tydesc_ty = ty.mk_type(ccx.tcx);
6354
        let vec[ty.t] tps = vec();
6355
        for (ast.ty_param tp in ty_params) {
6356
            _vec.push[ty.t](tps, tydesc_ty);
6357 6358
        }

6359 6360 6361
        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,
6362
                                          vec(tydesc_ty,
6363 6364
                                              typarams_ty,
                                              fields_ty));
6365
        let ty.t boxed_body_ty = ty.mk_imm_box(ccx.tcx, body_ty);
6366

6367
        // Malloc a box for the body.
6368
        auto box = trans_malloc_boxed(bcx, body_ty);
6369 6370 6371 6372 6373 6374 6375 6376
        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);
6377

6378 6379
        // Store body tydesc.
        auto body_tydesc =
6380 6381 6382
            GEP_tup_like(bcx, body_ty, body.val,
                         vec(0, abi.obj_body_elt_tydesc));
        bcx = body_tydesc.bcx;
6383

6384 6385 6386 6387 6388 6389 6390 6391 6392
        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]) {}
        }

6393 6394
        bcx = body_td.bcx;
        bcx.build.Store(body_td.val, body_tydesc.val);
6395

6396 6397 6398 6399 6400 6401 6402
        // 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) {
6403
            auto typaram = bcx.fcx.lltydescs.(i);
6404 6405 6406 6407 6408 6409 6410
            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;
        }

6411 6412
        // Copy args into body fields.
        auto body_fields =
6413 6414 6415
            GEP_tup_like(bcx, body_ty, body.val,
                         vec(0, abi.obj_body_elt_fields));
        bcx = body_fields.bcx;
6416

6417
        i = 0;
6418
        for (ast.obj_field f in ob.fields) {
6419
            auto arg = bcx.fcx.llargs.get(f.id);
6420
            arg = load_if_immediate(bcx, arg, arg_tys.(i).ty);
6421 6422 6423 6424
            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;
6425 6426 6427
            i += 1;
        }
        // Store box ptr in outer pair.
6428
        auto p = bcx.build.PointerCast(box.val, llbox_ty);
6429
        bcx.build.Store(p, pair_box);
6430
    }
6431
    bcx.build.RetVoid();
6432 6433 6434

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

6437
fn trans_tag_variant(@local_ctxt cx, ast.def_id tag_id,
6438 6439
                     &ast.variant variant, int index,
                     &vec[ast.ty_param] ty_params) {
6440
    if (_vec.len[ast.variant_arg](variant.node.args) == 0u) {
6441 6442 6443
        ret;    // nullary constructors are just constants
    }

6444 6445 6446
    // Translate variant arguments to function arguments.
    let vec[ast.arg] fn_args = vec();
    auto i = 0u;
6447
    for (ast.variant_arg varg in variant.node.args) {
6448 6449 6450 6451 6452 6453
        fn_args += vec(rec(mode=ast.alias,
                           ty=varg.ty,
                           ident="arg" + _uint.to_str(i, 10u),
                           id=varg.id));
    }

6454
    check (cx.ccx.item_ids.contains_key(variant.node.id));
6455
    let ValueRef llfndecl = cx.ccx.item_ids.get(variant.node.id);
6456

6457
    auto fcx = new_fn_ctxt(cx, llfndecl);
6458

6459
    create_llargs_for_fn_args(fcx, ast.proto_fn,
6460
                              none[tup(TypeRef, ty.t)],
6461
                              ret_ty_of_fn(cx.ccx, variant.node.ann),
6462
                              fn_args, ty_params);
6463

6464
    let vec[ty.t] ty_param_substs = vec();
6465
    i = 0u;
6466
    for (ast.ty_param tp in ty_params) {
6467
        ty_param_substs += vec(ty.mk_param(cx.ccx.tcx, i));
6468
        i += 1u;
6469 6470
    }

6471
    auto arg_tys = arg_tys_of_fn(cx.ccx, variant.node.ann);
6472 6473 6474 6475
    copy_args_to_allocas(fcx, fn_args, arg_tys);

    auto bcx = new_top_block_ctxt(fcx);
    auto lltop = bcx.llbb;
6476

6477 6478
    // Cast the tag to a type we can GEP into.
    auto lltagptr = bcx.build.PointerCast(fcx.llretptr,
6479
                                          T_opaque_tag_ptr(fcx.lcx.ccx.tn));
6480 6481

    auto lldiscrimptr = bcx.build.GEP(lltagptr,
6482
                                      vec(C_int(0), C_int(0)));
6483 6484
    bcx.build.Store(C_int(index), lldiscrimptr);

6485
    auto llblobptr = bcx.build.GEP(lltagptr,
6486
                                   vec(C_int(0), C_int(1)));
6487 6488

    i = 0u;
6489 6490
    for (ast.variant_arg va in variant.node.args) {
        auto rslt = GEP_tag(bcx, llblobptr, tag_id, variant.node.id,
6491
                            ty_param_substs, i as int);
6492 6493
        bcx = rslt.bcx;
        auto lldestptr = rslt.val;
6494

6495 6496 6497 6498
        // 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),
6499
            val_ty(lldestptr));
6500

6501 6502
        auto arg_ty = arg_tys.(i).ty;
        auto llargval;
6503 6504
        if (ty.type_is_structural(cx.ccx.tcx, arg_ty) ||
                ty.type_has_dynamic_size(cx.ccx.tcx, arg_ty)) {
6505 6506 6507 6508 6509 6510 6511 6512
            llargval = llargptr;
        } else {
            llargval = bcx.build.Load(llargptr);
        }

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

6513 6514 6515 6516
        i += 1u;
    }

    bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
6517
    bcx.build.RetVoid();
6518 6519 6520

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

6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538
// 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);
6539 6540 6541 6542 6543 6544

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

6547
fn trans_item(@local_ctxt cx, &ast.item item) {
6548
    alt (item.node) {
6549
        case (ast.item_fn(?name, ?f, ?tps, ?fid, ?ann)) {
6550
            auto sub_cx = extend_path(cx, name);
6551
            trans_fn(sub_cx, f, fid, none[tup(TypeRef, ty.t)], tps, ann);
6552
        }
6553
        case (ast.item_obj(?name, ?ob, ?tps, ?oid, ?ann)) {
6554 6555 6556
            auto sub_cx = @rec(obj_typarams=tps,
                               obj_fields=ob.fields with
                               *extend_path(cx, name));
6557
            trans_obj(sub_cx, ob, oid.ctor, tps, ann);
6558
        }
6559
        case (ast.item_mod(?name, ?m, _)) {
6560 6561 6562
            auto sub_cx = @rec(path = cx.path + vec(name),
                               module_path = cx.module_path + vec(name)
                               with *cx);
6563
            trans_mod(sub_cx, m);
6564
        }
6565
        case (ast.item_tag(?name, ?variants, ?tps, ?tag_id, _)) {
6566
            auto sub_cx = extend_path(cx, name);
6567
            auto i = 0;
6568
            for (ast.variant variant in variants) {
6569
                trans_tag_variant(sub_cx, tag_id, variant, i, tps);
6570
                i += 1;
6571 6572
            }
        }
6573
        case (ast.item_const(?name, _, ?expr, ?cid, ?ann)) {
6574
            trans_const(cx.ccx, expr, cid, ann);
6575
        }
6576
        case (_) { /* fall through */ }
6577 6578 6579
    }
}

6580
fn trans_mod(@local_ctxt cx, &ast._mod m) {
6581 6582
    for (@ast.item item in m.items) {
        trans_item(cx, *item);
6583 6584 6585
    }
}

6586 6587 6588 6589 6590 6591 6592 6593
fn get_pair_fn_ty(TypeRef llpairty) -> TypeRef {
    // Bit of a kludge: pick the fn typeref out of the pair.
    let vec[TypeRef] pair_tys = vec(T_nil(), T_nil());
    llvm.LLVMGetStructElementTypes(llpairty,
                                   _vec.buf[TypeRef](pair_tys));
    ret llvm.LLVMGetElementType(pair_tys.(0));
}

6594 6595
fn decl_fn_and_pair(@crate_ctxt ccx,
                    vec[str] path,
6596
                    str flav,
6597
                    vec[ast.ty_param] ty_params,
6598 6599 6600
                    &ast.ann ann,
                    ast.def_id id) {

6601 6602
    auto llfty;
    auto llpairty;
6603
    alt (ty.struct(ccx.tcx, node_ann_type(ccx, ann))) {
6604
        case (ty.ty_fn(?proto, ?inputs, ?output)) {
6605
            llfty = type_of_fn(ccx, proto, inputs, output,
6606
                               _vec.len[ast.ty_param](ty_params));
6607
            llpairty = T_fn_pair(ccx.tn, llfty);
6608 6609
        }
        case (_) {
6610
            ccx.sess.bug("decl_fn_and_pair(): fn item doesn't have fn type!");
6611 6612 6613
            fail;
        }
    }
6614 6615

    // Declare the function itself.
6616
    let str s = mangle_name_by_seq(ccx, path, flav);
6617
    let ValueRef llfn = decl_internal_fastcall_fn(ccx.llmod, s, llfty);
6618 6619

    // Declare the global constant pair that points to it.
6620
    let str ps = mangle_name_by_type(ccx, path, node_ann_type(ccx, ann));
6621

6622
    register_fn_pair(ccx, ps, llpairty, llfn, id);
6623 6624 6625 6626
}

fn register_fn_pair(@crate_ctxt cx, str ps, TypeRef llpairty, ValueRef llfn,
                    ast.def_id id) {
6627 6628 6629
    let ValueRef gvar = llvm.LLVMAddGlobal(cx.llmod, llpairty,
                                           _str.buf(ps));
    auto pair = C_struct(vec(llfn,
6630
                             C_null(T_opaque_closure_ptr(cx.tn))));
6631 6632 6633

    llvm.LLVMSetInitializer(gvar, pair);
    llvm.LLVMSetGlobalConstant(gvar, True);
6634 6635 6636
    llvm.LLVMSetVisibility(gvar,
                           lib.llvm.LLVMProtectedVisibility
                           as llvm.Visibility);
6637 6638

    cx.item_ids.insert(id, llfn);
P
Patrick Walton 已提交
6639
    cx.item_symbols.insert(id, ps);
6640 6641 6642
    cx.fn_pairs.insert(id, gvar);
}

6643 6644 6645 6646 6647 6648 6649 6650 6651 6652
// 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;
        }
6653
        case (ast.native_item_fn(_, _, _, ?tps, _, _)) {
6654 6655 6656 6657 6658 6659
            count = _vec.len[ast.ty_param](tps);
        }
    }
    ret count;
}

6660
fn native_fn_wrapper_type(@crate_ctxt cx, uint ty_param_count, ty.t x)
6661
        -> TypeRef {
6662
    alt (ty.struct(cx.tcx, x)) {
6663
        case (ty.ty_native_fn(?abi, ?args, ?out)) {
6664
            ret type_of_fn(cx, ast.proto_fn, args, out, ty_param_count);
6665 6666 6667 6668 6669
        }
    }
    fail;
}

6670 6671
fn decl_native_fn_and_pair(@crate_ctxt ccx,
                           vec[str] path,
6672 6673 6674
                           str name,
                           &ast.ann ann,
                           ast.def_id id) {
6675
    auto num_ty_param = native_fn_ty_param_count(ccx, id);
6676

6677
    // Declare the wrapper.
6678 6679
    auto t = node_ann_type(ccx, ann);
    auto wrapper_type = native_fn_wrapper_type(ccx, num_ty_param, t);
6680
    let str s = mangle_name_by_seq(ccx, path, "wrapper");
6681 6682
    let ValueRef wrapper_fn = decl_internal_fastcall_fn(ccx.llmod, s,
                                                        wrapper_type);
6683

6684
    // Declare the global constant pair that points to it.
6685
    auto wrapper_pair_type = T_fn_pair(ccx.tn, wrapper_type);
6686
    let str ps = mangle_name_by_type(ccx, path, node_ann_type(ccx, ann));
6687

6688
    register_fn_pair(ccx, ps, wrapper_pair_type, wrapper_fn, id);
6689

6690
    // Build the wrapper.
6691
    auto fcx = new_fn_ctxt(new_local_ctxt(ccx), wrapper_fn);
6692
    auto bcx = new_top_block_ctxt(fcx);
6693
    auto lltop = bcx.llbb;
6694

6695
    // Declare the function itself.
6696 6697
    auto item = ccx.native_items.get(id);
    auto fn_type = node_ann_type(ccx, ann);  // NB: has no type params
6698

6699
    auto abi = ty.ty_fn_abi(ccx.tcx, fn_type);
6700
    auto llfnty = type_of_native_fn(ccx, abi,
6701 6702
        ty.ty_fn_args(ccx.tcx, fn_type),
        ty.ty_fn_ret(ccx.tcx, fn_type), num_ty_param);
6703

6704 6705 6706 6707 6708
    // 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));

6709
    let vec[ValueRef] call_args = vec();
6710
    auto arg_n = 3u;
6711 6712
    auto pass_task;

6713
    auto lltaskptr = vp2i(bcx, fcx.lltaskptr);
6714 6715
    alt (abi) {
        case (ast.native_abi_rust) {
6716
            pass_task = true;
6717
            call_args += vec(lltaskptr);
6718 6719
            for each (uint i in _uint.range(0u, num_ty_param)) {
                auto llarg = llvm.LLVMGetParam(fcx.llfn, arg_n);
G
Graydon Hoare 已提交
6720
                fcx.lltydescs += vec(llarg);
6721
                check (llarg as int != 0);
6722
                call_args += vec(vp2i(bcx, llarg));
6723 6724 6725 6726
                arg_n += 1u;
            }
        }
        case (ast.native_abi_cdecl) {
6727
            pass_task = false;
6728
        }
6729 6730 6731 6732
        case (ast.native_abi_llvm) {
            pass_task = false;
            // We handle this case below.
        }
6733
    }
6734

6735 6736 6737
    fn push_arg(@block_ctxt cx,
                &mutable vec[ValueRef] args,
                ValueRef v,
6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754
                ty.t t,
                ast.mode mode) {
        if (mode == ast.val) {
            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)) {
                    args += vec(cx.build.ZExtOrBitCast(v, T_int()));
                } else {
                    args += vec(cx.build.TruncOrBitCast(v, T_int()));
                }
                ret;
            }
            if (ty.type_is_fp(cx.fcx.lcx.ccx.tcx, t)) {
                args += vec(cx.build.FPToSI(v, T_int()));
                ret;
6755 6756
            }
        }
6757 6758

        args += vec(vp2i(cx, v));
6759 6760
    }

6761 6762
    auto r;
    auto rptr;
6763
    auto args = ty.ty_fn_args(ccx.tcx, fn_type);
6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774
    if (abi == ast.native_abi_llvm) {
        let vec[ValueRef] call_args = vec();
        let vec[TypeRef] call_arg_tys = vec();
        auto i = 0u;
        while (i < _vec.len[ty.arg](args)) {
            auto call_arg = llvm.LLVMGetParam(fcx.llfn, i + 3u);
            call_args += vec(call_arg);
            call_arg_tys += vec(val_ty(call_arg));
            i += 1u;
        }
        auto llnativefnty = T_fn(call_arg_tys,
6775
                                 type_of(ccx,
6776
                                         ty.ty_fn_ret(ccx.tcx, fn_type)));
6777
        auto llnativefn = get_extern_fn(ccx.externs, ccx.llmod, name,
6778 6779 6780 6781
                                        lib.llvm.LLVMCCallConv, llnativefnty);
        r = bcx.build.Call(llnativefn, call_args);
        rptr = fcx.llretptr;
    } else {
G
Graydon Hoare 已提交
6782 6783 6784

        let vec[tup(ValueRef, ty.t)] drop_args = vec();

6785 6786
        for (ty.arg arg in args) {
            auto llarg = llvm.LLVMGetParam(fcx.llfn, arg_n);
6787
            check (llarg as int != 0);
6788
            push_arg(bcx, call_args, llarg, arg.ty, arg.mode);
G
Graydon Hoare 已提交
6789 6790 6791
            if (arg.mode == ast.val) {
                drop_args += vec(tup(llarg, arg.ty));
            }
6792 6793 6794
            arg_n += 1u;
        }

6795 6796
        r = trans_native_call(bcx.build, ccx.glues, lltaskptr, ccx.externs,
                              ccx.tn, ccx.llmod, name, pass_task, call_args);
6797
        rptr = bcx.build.BitCast(fcx.llretptr, T_ptr(T_i32()));
G
Graydon Hoare 已提交
6798 6799 6800 6801

        for (tup(ValueRef, ty.t) d in drop_args) {
            bcx = drop_ty(bcx, d._0, d._1).bcx;
        }
6802
    }
6803

6804 6805 6806 6807 6808
    // 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); }

6809
    bcx.build.RetVoid();
6810 6811 6812

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

6815
type walk_ctxt = rec(mutable vec[str] path);
6816 6817 6818 6819
fn new_walk_ctxt() -> @walk_ctxt {
    let vec[str] path = vec();
    ret @rec(mutable path=path);
}
6820 6821 6822 6823 6824

fn enter_item(@walk_ctxt cx, @ast.item item) {
    alt (item.node) {
        case (ast.item_fn(?name, _, _, _, _)) {
            _vec.push[str](cx.path, name);
6825
        }
6826 6827 6828 6829 6830
        case (ast.item_obj(?name, _, _, _, _)) {
            _vec.push[str](cx.path, name);
        }
        case (ast.item_mod(?name, _, _)) {
            _vec.push[str](cx.path, name);
6831
        }
6832
        case (_) { }
6833 6834
    }
}
6835

6836 6837 6838 6839
fn leave_item(@walk_ctxt cx, @ast.item item) {
    alt (item.node) {
        case (ast.item_fn(_, _, _, _, _)) {
            _vec.pop[str](cx.path);
6840
        }
6841 6842
        case (ast.item_obj(_, _, _, _, _)) {
            _vec.pop[str](cx.path);
6843
        }
6844 6845
        case (ast.item_mod(_, _, _)) {
            _vec.pop[str](cx.path);
6846
        }
6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857
        case (_) { }
    }
}

fn collect_native_item(@crate_ctxt ccx, @walk_ctxt wcx, @ast.native_item i) {
    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);
            }
6858
        }
6859 6860
        case (ast.native_item_ty(_, ?tid)) {
            ccx.native_items.insert(tid, i);
6861 6862 6863
        }
    }
}
6864

6865 6866 6867
fn collect_item_1(@crate_ctxt ccx, @walk_ctxt wcx, @ast.item i) {
    enter_item(wcx, i);

6868
    alt (i.node) {
6869
        case (ast.item_const(?name, _, _, ?cid, ?ann)) {
6870 6871 6872
            auto typ = node_ann_type(ccx, ann);
            auto g = llvm.LLVMAddGlobal(ccx.llmod, type_of(ccx, typ),
                                        _str.buf(ccx.names.next(name)));
6873
            llvm.LLVMSetLinkage(g, lib.llvm.LLVMInternalLinkage
6874
                                as llvm.Linkage);
6875 6876
            ccx.items.insert(cid, i);
            ccx.consts.insert(cid, g);
6877 6878
        }
        case (ast.item_mod(?name, ?m, ?mid)) {
6879
            ccx.items.insert(mid, i);
6880
        }
6881
        case (ast.item_ty(_, _, _, ?did, _)) {
6882
            ccx.items.insert(did, i);
6883
        }
6884
        case (ast.item_tag(?name, ?variants, ?tps, ?tag_id, _)) {
6885
            ccx.items.insert(tag_id, i);
6886
        }
6887
        case (_) {}
6888 6889 6890
    }
}

6891 6892 6893
fn collect_item_2(@crate_ctxt ccx, @walk_ctxt wcx, @ast.item i) {
    enter_item(wcx, i);

6894
    alt (i.node) {
6895
        case (ast.item_fn(?name, ?f, ?tps, ?fid, ?ann)) {
6896 6897 6898
            ccx.items.insert(fid, i);
            if (!ccx.obj_methods.contains_key(fid)) {
                decl_fn_and_pair(ccx, wcx.path, "fn", tps, ann, fid);
6899
            }
6900
        }
6901
        case (ast.item_obj(?name, ?ob, ?tps, ?oid, ?ann)) {
6902 6903
            ccx.items.insert(oid.ctor, i);
            decl_fn_and_pair(ccx, wcx.path, "obj_ctor", tps, ann, oid.ctor);
6904
            for (@ast.method m in ob.methods) {
6905
                ccx.obj_methods.insert(m.node.id, ());
6906
            }
6907
        }
6908
        case (_) {}
6909 6910 6911
    }
}

6912
fn collect_items(@crate_ctxt ccx, @ast.crate crate) {
6913
    auto wcx = new_walk_ctxt();
6914
    auto visitor0 = walk.default_visitor();
6915
    auto visitor1 = rec(visit_native_item_pre =
6916 6917 6918 6919 6920 6921 6922 6923 6924
                          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);
6925 6926
}

6927 6928
fn collect_tag_ctor(@crate_ctxt ccx, @walk_ctxt wcx, @ast.item i) {
    enter_item(wcx, i);
6929 6930

    alt (i.node) {
6931
        case (ast.item_tag(_, ?variants, ?tps, _, _)) {
6932
            for (ast.variant variant in variants) {
6933
                if (_vec.len[ast.variant_arg](variant.node.args) != 0u) {
6934
                    decl_fn_and_pair(ccx, wcx.path + vec(variant.node.name),
6935 6936
                                     "tag", tps, variant.node.ann,
                                     variant.node.id);
6937 6938 6939 6940 6941 6942 6943 6944
                }
            }
        }

        case (_) { /* fall through */ }
    }
}

6945 6946 6947 6948 6949 6950
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);
6951 6952
}

6953 6954
// The constant translation pass.

6955 6956
fn trans_constant(@crate_ctxt ccx, @walk_ctxt wcx, @ast.item it) {
    enter_item(wcx, it);
6957

6958
    alt (it.node) {
6959
        case (ast.item_tag(?ident, ?variants, _, ?tag_id, _)) {
6960
            auto i = 0u;
6961 6962 6963
            auto n_variants = _vec.len[ast.variant](variants);
            while (i < n_variants) {
                auto variant = variants.(i);
6964 6965 6966

                auto discrim_val = C_int(i as int);

6967
                auto s = mangle_name_by_seq(ccx, wcx.path,
6968 6969
                                            #fmt("_rust_tag_discrim_%s_%u",
                                                 ident, i));
6970
                auto discrim_gvar = llvm.LLVMAddGlobal(ccx.llmod, T_int(),
P
Patrick Walton 已提交
6971
                                                       _str.buf(s));
6972 6973 6974 6975

                llvm.LLVMSetInitializer(discrim_gvar, discrim_val);
                llvm.LLVMSetGlobalConstant(discrim_gvar, True);

6976 6977
                ccx.discrims.insert(variant.node.id, discrim_gvar);
                ccx.discrim_symbols.insert(variant.node.id, s);
6978 6979 6980 6981

                i += 1u;
            }
        }
6982 6983 6984 6985 6986

        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);
6987 6988 6989 6990
            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);
6991 6992
        }

6993
        case (_) {}
6994 6995 6996
    }
}

6997 6998 6999 7000 7001 7002
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);
7003 7004
}

7005 7006 7007 7008 7009 7010 7011 7012 7013 7014

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

7015 7016 7017 7018
fn p2i(ValueRef v) -> ValueRef {
    ret llvm.LLVMConstPtrToInt(v, T_int());
}

7019 7020 7021 7022
fn i2p(ValueRef v, TypeRef t) -> ValueRef {
    ret llvm.LLVMConstIntToPtr(v, t);
}

7023
fn trans_exit_task_glue(@glue_fns glues,
7024
                        &hashmap[str, ValueRef] externs,
7025
                        type_names tn, ModuleRef llmod) {
7026 7027 7028
    let vec[TypeRef] T_args = vec();
    let vec[ValueRef] V_args = vec();

7029
    auto llfn = glues.exit_task_glue;
7030
    let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 4u);
7031

7032 7033
    auto entrybb = llvm.LLVMAppendBasicBlock(llfn, _str.buf("entry"));
    auto build = new_builder(entrybb);
7034
    auto tptr = build.PtrToInt(lltaskptr, T_int());
7035
    auto V_args2 = vec(tptr) + V_args;
7036 7037
    trans_native_call(build, glues, lltaskptr,
                      externs, tn, llmod, "upcall_exit", true, V_args2);
7038
    build.RetVoid();
7039 7040
}

7041
fn create_typedefs(@crate_ctxt cx) {
7042 7043 7044
    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));
7045 7046
}

7047
fn create_crate_constant(ValueRef crate_ptr, @glue_fns glues) {
7048

7049
    let ValueRef crate_addr = p2i(crate_ptr);
7050 7051

    let ValueRef activate_glue_off =
7052
        llvm.LLVMConstSub(p2i(glues.activate_glue), crate_addr);
7053 7054

    let ValueRef yield_glue_off =
7055
        llvm.LLVMConstSub(p2i(glues.yield_glue), crate_addr);
7056

7057
    let ValueRef exit_task_glue_off =
7058
        llvm.LLVMConstSub(p2i(glues.exit_task_glue), crate_addr);
7059 7060 7061

    let ValueRef crate_val =
        C_struct(vec(C_null(T_int()),     // ptrdiff_t image_base_off
7062
                     p2i(crate_ptr),      // uintptr_t self_addr
7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073
                     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
7074
                     C_null(T_int()),     // int n_libs
7075
                     C_int(abi.abi_x86_rustc_fastcall) // uintptr_t abi_tag
7076 7077
                     ));

7078
    llvm.LLVMSetInitializer(crate_ptr, crate_val);
7079 7080
}

7081 7082 7083 7084
fn find_main_fn(@crate_ctxt cx) -> ValueRef {
    auto e = sep() + "main";
    let ValueRef v = C_nil();
    let uint n = 0u;
7085 7086
    for each (@tup(ast.def_id, str) i in cx.item_symbols.items()) {
        if (_str.ends_with(i._1, e)) {
7087
            n += 1u;
7088
            v = cx.item_ids.get(i._0);
7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104
        }
    }
    alt (n) {
        case (0u) {
            cx.sess.err("main fn not found");
        }
        case (1u) {
            ret v;
        }
        case (_) {
            cx.sess.err("multiple main fns found");
        }
    }
    fail;
}

7105
fn trans_main_fn(@local_ctxt cx, ValueRef llcrate, ValueRef crate_map) {
7106
    auto T_main_args = vec(T_int(), T_int());
7107
    auto T_rust_start_args = vec(T_int(), T_int(), T_int(), T_int(), T_int());
7108

7109 7110 7111 7112 7113 7114 7115
    auto main_name;
    if (_str.eq(std.os.target_os(), "win32")) {
        main_name = "WinMain@16";
    } else {
        main_name = "main";
    }

7116
    auto llmain =
7117
        decl_cdecl_fn(cx.ccx.llmod, main_name, T_fn(T_main_args, T_int()));
7118

7119
    auto llrust_start = decl_cdecl_fn(cx.ccx.llmod, "rust_start",
7120
                                      T_fn(T_rust_start_args, T_int()));
7121 7122 7123

    auto llargc = llvm.LLVMGetParam(llmain, 0u);
    auto llargv = llvm.LLVMGetParam(llmain, 1u);
7124
    auto llrust_main = find_main_fn(cx.ccx);
7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135

    //
    // Emit the moral equivalent of:
    //
    // main(int argc, char **argv) {
    //     rust_start(&_rust.main, &crate, argc, argv);
    // }
    //

    let BasicBlockRef llbb =
        llvm.LLVMAppendBasicBlock(llmain, _str.buf(""));
7136
    auto b = new_builder(llbb);
7137

7138 7139
    auto start_args = vec(p2i(llrust_main), p2i(llcrate), llargc, llargv,
                          p2i(crate_map));
7140 7141 7142 7143

    b.Ret(b.Call(llrust_start, start_args));
}

7144 7145
fn declare_intrinsics(ModuleRef llmod) -> hashmap[str,ValueRef] {

7146
    let vec[TypeRef] T_trap_args = vec();
7147 7148 7149 7150 7151 7152
    auto trap = decl_cdecl_fn(llmod, "llvm.trap",
                              T_fn(T_trap_args, T_void()));

    auto intrinsics = new_str_hash[ValueRef]();
    intrinsics.insert("llvm.trap", trap);
    ret intrinsics;
7153 7154
}

7155 7156

fn trace_str(@block_ctxt cx, str s) {
7157 7158
    trans_upcall(cx, "upcall_trace_str", vec(p2i(C_cstr(cx.fcx.lcx.ccx, s))),
                 false);
7159 7160 7161
}

fn trace_word(@block_ctxt cx, ValueRef v) {
7162
    trans_upcall(cx, "upcall_trace_word", vec(v), false);
7163 7164 7165 7166 7167 7168 7169 7170
}

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();
7171
    bcx.build.Call(bcx.fcx.lcx.ccx.intrinsics.get("llvm.trap"), v);
7172
}
7173 7174 7175 7176
tag output_type {
    output_type_none;
    output_type_bitcode;
    output_type_assembly;
R
Rafael Ávila de Espíndola 已提交
7177 7178 7179
    output_type_object;
}

7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192
// Decides what to call an intermediate file, given the name of the output and
// the extension to use.
fn mk_intermediate_name(str output_path, str extension) -> str {
    auto dot_pos = _str.index(output_path, '.' as u8);
    auto stem;
    if (dot_pos < 0) {
        stem = output_path;
    } else {
        stem = _str.substr(output_path, 0u, dot_pos as uint);
    }
    ret stem + "." + extension;
}

R
Rafael Ávila de Espíndola 已提交
7193 7194 7195 7196 7197 7198 7199 7200
fn is_object_or_assembly(output_type ot) -> bool {
    if (ot == output_type_assembly) {
        ret true;
    }
    if (ot == output_type_object) {
        ret true;
    }
    ret false;
7201
}
7202

7203 7204
fn run_passes(ModuleRef llmod, bool opt, bool verify, bool save_temps,
              str output, output_type ot) {
7205 7206 7207
    auto pm = mk_pass_manager();

    // TODO: run the linter here also, once there are llvm-c bindings for it.
R
Rafael Ávila de Espíndola 已提交
7208

7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225
    // Generate a pre-optimization intermediate file if -save-temps was
    // specified.
    if (save_temps) {
        alt (ot) {
            case (output_type_bitcode) {
                if (opt) {
                    auto filename = mk_intermediate_name(output, "no-opt.bc");
                    llvm.LLVMWriteBitcodeToFile(llmod, _str.buf(filename));
                }
            }
            case (_) {
                auto filename = mk_intermediate_name(output, "bc");
                llvm.LLVMWriteBitcodeToFile(llmod, _str.buf(filename));
            }
        }
    }

R
Rafael Ávila de Espíndola 已提交
7226 7227 7228 7229 7230 7231 7232 7233
    // FIXME: This is mostly a copy of the bits of opt's -O2 that are
    // available in the C api.
    // FIXME2: We might want to add optmization levels like -O1, -O2, -Os, etc
    // FIXME3: Should we expose and use the pass lists used by the opt tool?
    if (opt) {
        auto fpm = mk_pass_manager();

        // createStandardFunctionPasses
7234 7235
        llvm.LLVMAddTypeBasedAliasAnalysisPass(fpm.llpm);
        llvm.LLVMAddBasicAliasAnalysisPass(fpm.llpm);
R
Rafael Ávila de Espíndola 已提交
7236 7237
        llvm.LLVMAddCFGSimplificationPass(fpm.llpm);
        llvm.LLVMAddScalarReplAggregatesPass(fpm.llpm);
7238
        llvm.LLVMAddEarlyCSEPass(fpm.llpm);
R
Rafael Ávila de Espíndola 已提交
7239 7240 7241 7242

        llvm.LLVMRunPassManager(fpm.llpm, llmod);

        // createStandardModulePasses
7243 7244
        llvm.LLVMAddTypeBasedAliasAnalysisPass(pm.llpm);
        llvm.LLVMAddBasicAliasAnalysisPass(pm.llpm);
R
Rafael Ávila de Espíndola 已提交
7245 7246 7247 7248 7249 7250 7251
        llvm.LLVMAddGlobalOptimizerPass(pm.llpm);
        llvm.LLVMAddIPSCCPPass(pm.llpm);
        llvm.LLVMAddDeadArgEliminationPass(pm.llpm);
        llvm.LLVMAddInstructionCombiningPass(pm.llpm);
        llvm.LLVMAddCFGSimplificationPass(pm.llpm);
        llvm.LLVMAddPruneEHPass(pm.llpm);
        llvm.LLVMAddFunctionInliningPass(pm.llpm);
7252
        llvm.LLVMAddFunctionAttrsPass(pm.llpm);
7253 7254
        llvm.LLVMAddScalarReplAggregatesPassSSA(pm.llpm);
        llvm.LLVMAddEarlyCSEPass(pm.llpm);
R
Rafael Ávila de Espíndola 已提交
7255 7256
        llvm.LLVMAddSimplifyLibCallsPass(pm.llpm);
        llvm.LLVMAddJumpThreadingPass(pm.llpm);
7257
        llvm.LLVMAddCorrelatedValuePropagationPass(pm.llpm);
R
Rafael Ávila de Espíndola 已提交
7258 7259 7260 7261 7262 7263 7264 7265 7266 7267
        llvm.LLVMAddCFGSimplificationPass(pm.llpm);
        llvm.LLVMAddInstructionCombiningPass(pm.llpm);
        llvm.LLVMAddTailCallEliminationPass(pm.llpm);
        llvm.LLVMAddCFGSimplificationPass(pm.llpm);
        llvm.LLVMAddReassociatePass(pm.llpm);
        llvm.LLVMAddLoopRotatePass(pm.llpm);
        llvm.LLVMAddLICMPass(pm.llpm);
        llvm.LLVMAddLoopUnswitchPass(pm.llpm);
        llvm.LLVMAddInstructionCombiningPass(pm.llpm);
        llvm.LLVMAddIndVarSimplifyPass(pm.llpm);
7268
        llvm.LLVMAddLoopIdiomPass(pm.llpm);
R
Rafael Ávila de Espíndola 已提交
7269 7270 7271 7272 7273 7274 7275 7276
        llvm.LLVMAddLoopDeletionPass(pm.llpm);
        llvm.LLVMAddLoopUnrollPass(pm.llpm);
        llvm.LLVMAddInstructionCombiningPass(pm.llpm);
        llvm.LLVMAddGVNPass(pm.llpm);
        llvm.LLVMAddMemCpyOptPass(pm.llpm);
        llvm.LLVMAddSCCPPass(pm.llpm);
        llvm.LLVMAddInstructionCombiningPass(pm.llpm);
        llvm.LLVMAddJumpThreadingPass(pm.llpm);
7277
        llvm.LLVMAddCorrelatedValuePropagationPass(pm.llpm);
R
Rafael Ávila de Espíndola 已提交
7278 7279 7280 7281 7282 7283 7284
        llvm.LLVMAddDeadStoreEliminationPass(pm.llpm);
        llvm.LLVMAddAggressiveDCEPass(pm.llpm);
        llvm.LLVMAddCFGSimplificationPass(pm.llpm);
        llvm.LLVMAddStripDeadPrototypesPass(pm.llpm);
        llvm.LLVMAddDeadTypeEliminationPass(pm.llpm);
        llvm.LLVMAddConstantMergePass(pm.llpm);
    }
P
Patrick Walton 已提交
7285 7286 7287 7288

    if (verify) {
        llvm.LLVMAddVerifierPass(pm.llpm);
    }
7289

7290
    // TODO: Write .s if -c was specified and -save-temps was on.
R
Rafael Ávila de Espíndola 已提交
7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301
    if (is_object_or_assembly(ot)) {
        let int LLVMAssemblyFile = 0;
        let int LLVMObjectFile = 1;
        let int LLVMNullFile = 2;
        auto FileType;
        if (ot == output_type_object) {
            FileType = LLVMObjectFile;
        } else {
            FileType = LLVMAssemblyFile;
        }

7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314
        // Write optimized bitcode if --save-temps was on.
        if (save_temps) {
            alt (ot) {
                case (output_type_bitcode) { /* nothing to do */ }
                case (_) {
                    auto filename = mk_intermediate_name(output, "opt.bc");
                    llvm.LLVMRunPassManager(pm.llpm, llmod);
                    llvm.LLVMWriteBitcodeToFile(llmod, _str.buf(filename));
                    pm = mk_pass_manager();
                }
            }
        }

R
Rafael Ávila de Espíndola 已提交
7315 7316 7317 7318
        llvm.LLVMRustWriteOutputFile(pm.llpm, llmod,
                                     _str.buf(x86.get_target_triple()),
                                     _str.buf(output),
                                     FileType);
7319
        llvm.LLVMDisposeModule(llmod);
7320 7321 7322
        ret;
    }

R
Rafael Ávila de Espíndola 已提交
7323
    llvm.LLVMRunPassManager(pm.llpm, llmod);
7324 7325 7326

    llvm.LLVMWriteBitcodeToFile(llmod, _str.buf(output));
    llvm.LLVMDisposeModule(llmod);
7327 7328
}

7329
fn decl_no_op_type_glue(ModuleRef llmod, type_names tn) -> ValueRef {
7330
    auto ty = T_fn(vec(T_taskptr(tn), T_ptr(T_i8())), T_void());
7331 7332 7333 7334
    ret decl_fastcall_fn(llmod, abi.no_op_type_glue_name(), ty);
}

fn make_no_op_type_glue(ValueRef fun) {
7335 7336
    auto bb_name = _str.buf("_rust_no_op_type_glue_bb");
    auto llbb = llvm.LLVMAppendBasicBlock(fun, bb_name);
7337
    new_builder(llbb).RetVoid();
7338 7339
}

7340
fn decl_memcpy_glue(ModuleRef llmod) -> ValueRef {
7341 7342 7343
    auto p8 = T_ptr(T_i8());

    auto ty = T_fn(vec(p8, p8, T_int()), T_void());
7344 7345
    ret decl_fastcall_fn(llmod, abi.memcpy_glue_name(), ty);
}
7346

7347 7348 7349 7350
fn make_memcpy_glue(ValueRef fun) {
    // We're not using the LLVM memcpy intrinsic. It appears to call through
    // to the platform memcpy in some cases, which is not terribly safe to run
    // on a rust stack.
7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383
    auto initbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("init"));
    auto hdrbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("hdr"));
    auto loopbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("loop"));
    auto endbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("end"));

    auto dst = llvm.LLVMGetParam(fun, 0u);
    auto src = llvm.LLVMGetParam(fun, 1u);
    auto count = llvm.LLVMGetParam(fun, 2u);

    // Init block.
    auto ib = new_builder(initbb);
    auto ip = ib.Alloca(T_int());
    ib.Store(C_int(0), ip);
    ib.Br(hdrbb);

    // Loop-header block
    auto hb = new_builder(hdrbb);
    auto i = hb.Load(ip);
    hb.CondBr(hb.ICmp(lib.llvm.LLVMIntEQ, count, i), endbb, loopbb);

    // Loop-body block
    auto lb = new_builder(loopbb);
    i = lb.Load(ip);
    lb.Store(lb.Load(lb.GEP(src, vec(i))),
             lb.GEP(dst, vec(i)));
    lb.Store(lb.Add(i, C_int(1)), ip);
    lb.Br(hdrbb);

    // End block
    auto eb = new_builder(endbb);
    eb.RetVoid();
}

7384
fn decl_bzero_glue(ModuleRef llmod) -> ValueRef {
7385 7386 7387
    auto p8 = T_ptr(T_i8());

    auto ty = T_fn(vec(p8, T_int()), T_void());
7388 7389
    ret decl_fastcall_fn(llmod, abi.bzero_glue_name(), ty);
}
7390

7391
fn make_bzero_glue(ValueRef fun) -> ValueRef {
7392
    // We're not using the LLVM memset intrinsic. Same as with memcpy.
7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420 7421 7422 7423 7424
    auto initbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("init"));
    auto hdrbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("hdr"));
    auto loopbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("loop"));
    auto endbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("end"));

    auto dst = llvm.LLVMGetParam(fun, 0u);
    auto count = llvm.LLVMGetParam(fun, 1u);

    // Init block.
    auto ib = new_builder(initbb);
    auto ip = ib.Alloca(T_int());
    ib.Store(C_int(0), ip);
    ib.Br(hdrbb);

    // Loop-header block
    auto hb = new_builder(hdrbb);
    auto i = hb.Load(ip);
    hb.CondBr(hb.ICmp(lib.llvm.LLVMIntEQ, count, i), endbb, loopbb);

    // Loop-body block
    auto lb = new_builder(loopbb);
    i = lb.Load(ip);
    lb.Store(C_integral(0, T_i8()), lb.GEP(dst, vec(i)));
    lb.Store(lb.Add(i, C_int(1)), ip);
    lb.Br(hdrbb);

    // End block
    auto eb = new_builder(endbb);
    eb.RetVoid();
    ret fun;
}

7425
fn make_vec_append_glue(ModuleRef llmod, type_names tn) -> ValueRef {
7426
    /*
7427
     * Args to vec_append_glue:
7428 7429 7430 7431 7432 7433 7434 7435 7436 7437
     *
     *   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.
     *
7438
     *   3. Dst vec ptr (i.e. ptr to ptr to rust_vec).
7439 7440
     *
     *   4. Src vec (i.e. ptr to rust_vec).
7441
     *
7442
     *   5. Flag indicating whether to skip trailing null on dst.
7443 7444 7445 7446 7447 7448
     *
     */

    auto ty = T_fn(vec(T_taskptr(tn),
                       T_ptr(T_tydesc(tn)),
                       T_ptr(T_tydesc(tn)),
7449 7450 7451
                       T_ptr(T_opaque_vec_ptr()),
                       T_opaque_vec_ptr(), T_bool()),
                   T_void());
7452

7453
    auto llfn = decl_fastcall_fn(llmod, abi.vec_append_glue_name(), ty);
7454 7455 7456
    ret llfn;
}

7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495

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

7496
fn trans_vec_append_glue(@local_ctxt cx) {
7497

7498
    auto llfn = cx.ccx.glues.vec_append_glue;
7499 7500 7501 7502

    let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 0u);
    let ValueRef llvec_tydesc = llvm.LLVMGetParam(llfn, 1u);
    let ValueRef llelt_tydesc = llvm.LLVMGetParam(llfn, 2u);
7503 7504 7505
    let ValueRef lldst_vec_ptr = llvm.LLVMGetParam(llfn, 3u);
    let ValueRef llsrc_vec = llvm.LLVMGetParam(llfn, 4u);
    let ValueRef llskipnull = llvm.LLVMGetParam(llfn, 5u);
7506

7507 7508 7509
    let BasicBlockRef llallocas =
        llvm.LLVMAppendBasicBlock(llfn, _str.buf("allocas"));

7510 7511 7512 7513
    auto fcx = @rec(llfn=llfn,
                    lltaskptr=lltaskptr,
                    llenv=C_null(T_ptr(T_nil())),
                    llretptr=C_null(T_ptr(T_nil())),
7514
                    mutable llallocas = llallocas,
7515
                    mutable llself=none[self_vt],
7516 7517 7518 7519
                    mutable lliterbody=none[ValueRef],
                    llargs=new_def_hash[ValueRef](),
                    llobjfields=new_def_hash[ValueRef](),
                    lllocals=new_def_hash[ValueRef](),
7520
                    llupvars=new_def_hash[ValueRef](),
7521
                    mutable lltydescs=_vec.empty[ValueRef](),
7522
                    lcx=cx);
7523 7524

    auto bcx = new_top_block_ctxt(fcx);
7525
    auto lltop = bcx.llbb;
7526

7527 7528
    auto lldst_vec = bcx.build.Load(lldst_vec_ptr);

7529 7530
    // 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.
7531

7532
    auto llcopy_dst_ptr = alloca(bcx, T_int());
7533 7534
    auto llnew_vec_res =
        trans_upcall(bcx, "upcall_vec_grow",
7535 7536 7537
                     vec(vp2i(bcx, lldst_vec),
                         vec_fill_adjusted(bcx, llsrc_vec, llskipnull),
                         vp2i(bcx, llcopy_dst_ptr),
7538 7539
                         vp2i(bcx, llvec_tydesc)),
                     false);
7540 7541

    bcx = llnew_vec_res.bcx;
7542 7543
    auto llnew_vec = vi2p(bcx, llnew_vec_res.val,
                          T_opaque_vec_ptr());
7544
    llvm.LLVMSetValueName(llnew_vec, _str.buf("llnew_vec"));
7545

7546 7547
    auto copy_dst_cx = new_sub_block_ctxt(bcx, "copy new <- dst");
    auto copy_src_cx = new_sub_block_ctxt(bcx, "copy new <- src");
7548

7549
    auto pp0 = alloca(bcx, T_ptr(T_i8()));
7550
    bcx.build.Store(vec_p1_adjusted(bcx, llnew_vec, llskipnull), pp0);
7551
    llvm.LLVMSetValueName(pp0, _str.buf("pp0"));
7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566

    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));
7567
        llvm.LLVMSetValueName(src_lim, _str.buf("src_lim"));
7568 7569 7570 7571 7572

        auto elt_llsz =
            cx.build.Load(cx.build.GEP(elt_tydesc,
                                       vec(C_int(0),
                                           C_int(abi.tydesc_field_size))));
7573
        llvm.LLVMSetValueName(elt_llsz, _str.buf("elt_llsz"));
7574 7575

        fn take_one(ValueRef elt_tydesc,
7576 7577 7578
                    @block_ctxt cx,
                    ValueRef dst, ValueRef src) -> result {
            call_tydesc_glue_full(cx, src,
7579
                                  elt_tydesc,
7580
                                  abi.tydesc_field_take_glue);
7581
            ret res(cx, src);
7582 7583
        }

7584
        auto bcx = iter_sequence_raw(cx, dst, src, src_lim,
7585
                                     elt_llsz, bind take_one(elt_tydesc,
7586
                                                             _, _, _)).bcx;
7587 7588 7589 7590 7591

        ret call_memcpy(bcx, dst, src, n_bytes);
    }

    // Copy any dst elements in, omitting null if doing str.
7592

7593
    auto n_bytes = vec_fill_adjusted(copy_dst_cx, lldst_vec, llskipnull);
7594 7595
    llvm.LLVMSetValueName(n_bytes, _str.buf("n_bytes"));

7596 7597
    copy_dst_cx = copy_elts(copy_dst_cx,
                            llelt_tydesc,
7598
                            vec_p0(copy_dst_cx, llnew_vec),
7599 7600 7601
                            vec_p0(copy_dst_cx, lldst_vec),
                            n_bytes).bcx;

7602 7603 7604 7605
    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);
7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617
    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,
7618 7619 7620
                 copy_src_cx.build.Add(vec_fill_adjusted(copy_src_cx,
                                                         llnew_vec,
                                                         llskipnull),
7621
                                        n_bytes));
7622 7623 7624 7625

    // 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();
7626 7627 7628

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


7632 7633 7634
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()),
7635 7636
             /*
              * Note: the signature passed to decl_cdecl_fn here looks unusual
7637
              * because it is. It corresponds neither to a native signature
7638 7639 7640 7641 7642 7643 7644 7645
              * nor a normal rust-ABI signature. In fact it is a fake
              * signature, that exists solely to acquire the task pointer as
              * an argument to the upcall. It so happens that the runtime sets
              * up the task pointer as the sole incoming argument to the frame
              * that we return into when returning to the exit task glue. So
              * this is the signature required to retrieve it.
              */
             exit_task_glue = decl_cdecl_fn(llmod, abi.exit_task_glue_name(),
7646
                                            T_fn(vec(T_int(),
7647
                                                     T_int(),
7648 7649 7650
                                                     T_int(),
                                                     T_int(),
                                                     T_taskptr(tn)),
7651
                                                 T_void())),
7652

7653
             native_glues_rust =
7654 7655 7656 7657 7658
                 _vec.init_fn[ValueRef](bind decl_native_glue(llmod, tn,
                    abi.ngt_rust, _), abi.n_native_glues + 1 as uint),
             native_glues_pure_rust =
                 _vec.init_fn[ValueRef](bind decl_native_glue(llmod, tn,
                    abi.ngt_pure_rust, _), abi.n_native_glues + 1 as uint),
7659
             native_glues_cdecl =
7660 7661
                 _vec.init_fn[ValueRef](bind decl_native_glue(llmod, tn,
                    abi.ngt_cdecl, _), abi.n_native_glues + 1 as uint),
7662 7663 7664
             no_op_type_glue = decl_no_op_type_glue(llmod, tn),
             memcpy_glue = decl_memcpy_glue(llmod),
             bzero_glue = decl_bzero_glue(llmod),
7665
             vec_append_glue = make_vec_append_glue(llmod, tn));
7666 7667
}

7668
fn make_common_glue(str output, bool optimize, bool verify, bool save_temps,
7669
                    output_type ot) {
7670 7671 7672
    // 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.
7673 7674 7675 7676
    auto llmod =
        llvm.LLVMModuleCreateWithNameInContext(_str.buf("rust_out"),
                                               llvm.LLVMGetGlobalContext());

7677 7678
    llvm.LLVMSetDataLayout(llmod, _str.buf(x86.get_data_layout()));
    llvm.LLVMSetTarget(llmod, _str.buf(x86.get_target_triple()));
7679
    auto td = mk_target_data(x86.get_data_layout());
7680
    auto tn = mk_type_names();
7681 7682
    let ValueRef crate_ptr =
        llvm.LLVMAddGlobal(llmod, T_crate(tn), _str.buf("rust_crate"));
7683

7684 7685
    auto intrinsics = declare_intrinsics(llmod);

7686
    llvm.LLVMSetModuleInlineAsm(llmod, _str.buf(x86.get_module_asm()));
7687

7688
    auto glues = make_glues(llmod, tn);
7689
    create_crate_constant(crate_ptr, glues);
7690
    make_memcpy_glue(glues.memcpy_glue);
7691
    make_bzero_glue(glues.bzero_glue);
7692 7693 7694

    trans_exit_task_glue(glues, new_str_hash[ValueRef](), tn, llmod);

7695
    run_passes(llmod, optimize, verify, save_temps, output, ot);
7696 7697
}

7698 7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743 7744 7745
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,
                                  _str.buf("_rust_mod_map"));
    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)));
        _vec.push[ValueRef](elts, elt);
    }
    auto term = C_struct(vec(C_int(0), C_int(0)));
    _vec.push[ValueRef](elts, term);
    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()) {
        if (_str.eq(item.node.name, "name")) {
            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(),
                                     _str.buf("_rust_crate_map_" + name));
        _vec.push[ValueRef](subcrates, p2i(cr));
        i += 1;
    }
    _vec.push[ValueRef](subcrates, C_int(0));
    auto sym_name = "_rust_crate_map_" + crate_name(ccx, "__none__");
    auto arrtype = T_array(T_int(), _vec.len[ValueRef](subcrates));
    auto maptype = T_struct(vec(T_int(), arrtype));
    auto map = llvm.LLVMAddGlobal(ccx.llmod, maptype, _str.buf(sym_name));
    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;
}

7746
fn trans_crate(session.session sess, @ast.crate crate, ty.ctxt tcx,
7747
               ty.type_cache type_cache, str output, bool shared,
7748
               bool optimize, bool verify, bool save_temps, output_type ot) {
7749 7750 7751 7752 7753 7754 7755 7756 7757 7758 7759
    auto llmod =
        llvm.LLVMModuleCreateWithNameInContext(_str.buf("rust_out"),
                                               llvm.LLVMGetGlobalContext());

    llvm.LLVMSetDataLayout(llmod, _str.buf(x86.get_data_layout()));
    llvm.LLVMSetTarget(llmod, _str.buf(x86.get_target_triple()));
    auto td = mk_target_data(x86.get_data_layout());
    auto tn = mk_type_names();
    let ValueRef crate_ptr =
        llvm.LLVMAddGlobal(llmod, T_crate(tn), _str.buf("rust_crate"));

7760
    auto intrinsics = declare_intrinsics(llmod);
7761

7762
    auto glues = make_glues(llmod, tn);
7763 7764
    auto hasher = ty.hash_ty;
    auto eqer = ty.eq_ty;
7765 7766 7767
    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);
7768
    auto sha1s = map.mk_hashmap[ty.t,str](hasher, eqer);
7769
    auto abbrevs = map.mk_hashmap[ty.t,metadata.ty_abbrev](hasher, eqer);
7770

7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 7788 7789
    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,
7790
                    module_data = new_str_hash[ValueRef](),
7791
                    lltypes = lltypes,
7792 7793
                    glues = glues,
                    names = namegen(0),
7794
                    sha = std.sha1.mk_sha1(),
7795
                    type_sha1s = sha1s,
7796
                    type_abbrevs = abbrevs,
7797
                    tcx = tcx);
7798
    auto cx = new_local_ctxt(ccx);
7799

7800
    create_typedefs(ccx);
7801

7802
    collect_items(ccx, crate);
7803 7804
    collect_tag_ctors(ccx, crate);
    trans_constants(ccx, crate);
7805
    trans_mod(cx, crate.node.module);
7806
    trans_vec_append_glue(cx);
7807
    auto crate_map = create_crate_map(ccx);
7808
    if (!shared) {
7809
        trans_main_fn(cx, crate_ptr, crate_map);
7810
    }
7811

7812
    // Translate the metadata.
7813
    middle.metadata.write_metadata(cx.ccx, shared, crate);
7814

7815
    run_passes(llmod, optimize, verify, save_temps, output, ot);
7816 7817 7818 7819 7820 7821 7822 7823 7824
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
7825
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
7826 7827
// End:
//