trans.rs 263.1 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 60
                    vec[ValueRef] native_glues_rust,
                    vec[ValueRef] native_glues_cdecl,
61
                    ValueRef no_op_type_glue,
62
                    ValueRef memcpy_glue,
63
                    ValueRef bzero_glue,
64
                    ValueRef vec_append_glue);
65

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

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

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

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

126

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

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

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

147 148 149

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

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

161 162 163 164 165 166 167 168
// 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);
}

169

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

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

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

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


186
fn mangle_name_by_type(@crate_ctxt ccx, vec[str] path, ty.t t) -> str {
187 188 189 190 191 192
    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;
193 194 195 196
            // 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);
197 198 199 200 201 202
            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);
203 204
}

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

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

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

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

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


// LLVM type constructors.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

308 309 310 311 312 313 314 315 316 317 318 319 320 321
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();
}

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

341 342 343 344 345 346 347 348 349 350
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;
}

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

357 358 359 360 361 362 363 364 365 366 367 368
    auto t = T_tydesc_field(tn, abi.tydesc_field_drop_glue);
    tn.associate(s, t);
    ret t;
}

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);
369 370
    tn.associate(s, t);
    ret t;
371 372
}

373 374 375 376 377 378
fn T_tydesc(type_names tn) -> TypeRef {

    auto s = "tydesc";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }
379 380 381

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

    llvm.LLVMRefineType(abs_tydesc, tydesc);
409 410 411
    auto t = llvm.LLVMResolveTypeHandle(th.llth);
    tn.associate(s, t);
    ret t;
412 413
}

414 415 416 417
fn T_array(TypeRef t, uint n) -> TypeRef {
    ret llvm.LLVMArrayType(t, n);
}

418 419 420 421
fn T_vec(TypeRef t) -> TypeRef {
    ret T_struct(vec(T_int(),       // Refcount
                     T_int(),       // Alloc
                     T_int(),       // Fill
422
                     T_int(),       // Pad
423
                     T_array(t, 0u) // Body elements
424 425 426
                     ));
}

427 428 429 430
fn T_opaque_vec_ptr() -> TypeRef {
    ret T_ptr(T_vec(T_int()));
}

431 432
fn T_str() -> TypeRef {
    ret T_vec(T_i8());
433 434
}

435 436 437 438
fn T_box(TypeRef t) -> TypeRef {
    ret T_struct(vec(T_int(), t));
}

B
Brian Anderson 已提交
439 440 441 442 443 444 445 446
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
}

447 448 449 450 451 452 453 454 455 456 457 458
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
459 460 461 462 463
                          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
464 465
                          T_int(),      // int n_rust_syms
                          T_int(),      // int n_c_syms
466
                          T_int(),      // int n_libs
467
                          T_int()       // uintptr_t abi_tag
468 469 470
                          ));
    tn.associate(s, t);
    ret t;
471 472
}

473 474
fn T_taskptr(type_names tn) -> TypeRef {
    ret T_ptr(T_task(tn));
475 476
}

477 478
// This type must never be used directly; it must always be cast away.
fn T_typaram(type_names tn) -> TypeRef {
479 480 481 482 483
    auto s = "typaram";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }

484
    auto t = T_i8();
485 486
    tn.associate(s, t);
    ret t;
487 488
}

489 490 491 492
fn T_typaram_ptr(type_names tn) -> TypeRef {
    ret T_ptr(T_typaram(tn));
}

493 494
fn T_closure_ptr(type_names tn,
                 TypeRef lltarget_ty,
495 496
                 TypeRef llbindings_ty,
                 uint n_ty_params) -> TypeRef {
497 498 499 500

    // 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.
501
    ret T_ptr(T_box(T_struct(vec(T_ptr(T_tydesc(tn)),
502
                                 lltarget_ty,
503 504
                                 llbindings_ty,
                                 T_captured_tydescs(tn, n_ty_params))
505 506 507
                             )));
}

508 509 510 511 512 513 514
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()))),
515 516
                           T_nil(),
                           0u);
517 518
    tn.associate(s, t);
    ret t;
519 520
}

521 522 523 524 525 526 527 528 529 530 531
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 {
532
    auto s = "opaque_tag";
533 534 535
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }
536
    auto t = T_struct(vec(T_int(), T_i8()));
537 538 539 540
    tn.associate(s, t);
    ret t;
}

541 542 543 544
fn T_opaque_tag_ptr(type_names tn) -> TypeRef {
    ret T_ptr(T_opaque_tag(tn));
}

545 546
fn T_captured_tydescs(type_names tn, uint n) -> TypeRef {
    ret T_struct(_vec.init_elt[TypeRef](T_ptr(T_tydesc(tn)), n));
547 548
}

549 550 551 552 553 554 555
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)));
    }
556

557
    ret T_ptr(T_box(T_obj(tn, n_captured_tydescs)));
558 559
}

560
fn T_opaque_obj_ptr(type_names tn) -> TypeRef {
561
    ret T_obj_ptr(tn, 0u);
562 563
}

564

565 566 567 568
// 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.
569
fn type_of(@crate_ctxt cx, ty.t t) -> TypeRef {
570
    if (ty.type_has_dynamic_size(cx.tcx, t)) {
571
        log_err "type_of() called on a type with dynamic size: " +
572
            ty.ty_to_str(cx.tcx, t);
573 574 575
        fail;
    }

576
    ret type_of_inner(cx, t);
577 578
}

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

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

608
fn type_of_fn_full(@crate_ctxt cx,
609
                   ast.proto proto,
610 611
                   option.t[TypeRef] obj_self,
                   vec[ty.arg] inputs,
612
                   ty.t output,
613
                   uint ty_param_count) -> TypeRef {
614
    let vec[TypeRef] atys = vec();
615

616
    // Arg 0: Output pointer.
617
    if (ty.type_has_dynamic_size(cx.tcx, output)) {
618
        atys += vec(T_typaram_ptr(cx.tn));
619
    } else {
620
        atys += vec(T_ptr(type_of_inner(cx, output)));
621 622
    }

623
    // Arg 1: Task pointer.
624
    atys += vec(T_taskptr(cx.tn));
625 626

    // Arg 2: Env (closure-bindings / self-obj)
627 628 629
    alt (obj_self) {
        case (some[TypeRef](?t)) {
            check (t as int != 0);
630
            atys += vec(t);
631
        }
632
        case (_) {
633
            atys += vec(T_opaque_closure_ptr(cx.tn));
634
        }
635 636
    }

637 638 639 640
    // Args >3: ty params, if not acquired via capture...
    if (obj_self == none[TypeRef]) {
        auto i = 0u;
        while (i < ty_param_count) {
641
            atys += vec(T_ptr(T_tydesc(cx.tn)));
642 643
            i += 1u;
        }
644 645
    }

646
    if (proto == ast.proto_iter) {
647 648 649
        // 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.
650 651
        atys +=
            vec(T_fn_pair(cx.tn,
652
                          type_of_fn_full(cx, ast.proto_fn, none[TypeRef],
653
                                          vec(rec(mode=ast.alias, ty=output)),
654
                                          ty.mk_nil(cx.tcx), 0u)));
655 656
    }

657
    // ... then explicit args.
658
    atys += type_of_explicit_args(cx, inputs);
659

660
    ret T_fn(atys, llvm.LLVMVoidType());
661 662
}

663
fn type_of_fn(@crate_ctxt cx,
664
              ast.proto proto,
665
              vec[ty.arg] inputs,
666
              ty.t output,
667 668 669
              uint ty_param_count) -> TypeRef {
    ret type_of_fn_full(cx, proto, none[TypeRef], inputs, output,
                        ty_param_count);
670 671
}

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

690
fn type_of_inner(@crate_ctxt cx, ty.t t) -> TypeRef {
691 692 693 694 695
    // Check the cache.
    if (cx.lltypes.contains_key(t)) {
        ret cx.lltypes.get(t);
    }

696 697
    let TypeRef llty = 0 as TypeRef;

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

766
            let vec[TypeRef] mtys = vec();
767
            for (ty.method m in meths) {
768
                let TypeRef mty =
769
                    type_of_fn_full(cx, m.proto,
770
                                    some[TypeRef](self_ty),
771
                                    m.inputs, m.output, 0u);
772
                mtys += vec(T_ptr(mty));
773
            }
774
            let TypeRef vtbl = T_struct(mtys);
775
            let TypeRef pair = T_struct(vec(T_ptr(vtbl),
776
                                            T_opaque_obj_ptr(cx.tn)));
777

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

    check (llty as int != 0);
798 799 800
    llvm.LLVMAddTypeName(cx.llmod,
                         _str.buf(ty.ty_to_short_str(cx.tcx,
                                                     cx.type_abbrevs, t)),
801
                         llty);
802
    cx.lltypes.insert(t, llty);
803
    ret llty;
804 805
}

806
fn type_of_arg(@local_ctxt cx, &ty.arg arg) -> TypeRef {
807
    alt (ty.struct(cx.ccx.tcx, arg.ty)) {
808 809
        case (ty.ty_param(_)) {
            if (arg.mode == ast.alias) {
810
                ret T_typaram_ptr(cx.ccx.tn);
811 812 813 814 815 816 817
            }
        }
        case (_) {
            // fall through
        }
    }

818
    auto typ;
819
    if (arg.mode == ast.alias) {
820
        typ = T_ptr(type_of_inner(cx.ccx, arg.ty));
821
    } else {
822
        typ = type_of_inner(cx.ccx, arg.ty);
823
    }
824
    ret typ;
825 826
}

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


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

870 871 872 873 874 875
// LLVM constant constructors.

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

876
fn C_integral(int i, TypeRef t) -> ValueRef {
877 878 879 880 881 882
    // 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);
    //
883 884 885
    ret llvm.LLVMConstIntOfString(t, _str.buf(istr(i)), 10);
}

886 887 888 889
fn C_float(str s) -> ValueRef {
    ret llvm.LLVMConstRealOfString(T_float(), _str.buf(s));
}

890 891 892 893
fn C_floating(str s, TypeRef t) -> ValueRef {
    ret llvm.LLVMConstRealOfString(t, _str.buf(s));
}

894 895 896 897 898
fn C_nil() -> ValueRef {
    // NB: See comment above in T_void().
    ret C_integral(0, T_i1());
}

899 900
fn C_bool(bool b) -> ValueRef {
    if (b) {
901
        ret C_integral(1, T_bool());
902
    } else {
903
        ret C_integral(0, T_bool());
904 905 906
    }
}

907 908
fn C_int(int i) -> ValueRef {
    ret C_integral(i, T_int());
909 910
}

911 912 913 914
fn C_i8(uint i) -> ValueRef {
    ret C_integral(i as int, T_i8());
}

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

928 929 930 931 932 933
// 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'
934
                            C_int(0),               // 'pad'
935 936 937 938 939 940
                            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);
941
    llvm.LLVMSetLinkage(g, lib.llvm.LLVMInternalLinkage
942 943 944 945
                        as llvm.Linkage);
    ret llvm.LLVMConstPointerCast(g, T_ptr(T_str()));
}

946 947 948 949 950 951 952 953 954 955 956
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));
}

957 958 959 960 961 962
fn C_struct(vec[ValueRef] elts) -> ValueRef {
    ret llvm.LLVMConstStruct(_vec.buf[ValueRef](elts),
                             _vec.len[ValueRef](elts),
                             False);
}

963 964 965 966 967
fn C_array(TypeRef ty, vec[ValueRef] elts) -> ValueRef {
    ret llvm.LLVMConstArray(ty, _vec.buf[ValueRef](elts),
                            _vec.len[ValueRef](elts));
}

968
fn decl_fn(ModuleRef llmod, str name, uint cc, TypeRef llty) -> ValueRef {
969 970
    let ValueRef llfn =
        llvm.LLVMAddFunction(llmod, _str.buf(name), llty);
971
    llvm.LLVMSetFunctionCallConv(llfn, cc);
972 973 974
    ret llfn;
}

975 976
fn decl_cdecl_fn(ModuleRef llmod, str name, TypeRef llty) -> ValueRef {
    ret decl_fn(llmod, name, lib.llvm.LLVMCCallConv, llty);
977 978
}

979 980
fn decl_fastcall_fn(ModuleRef llmod, str name, TypeRef llty) -> ValueRef {
    ret decl_fn(llmod, name, lib.llvm.LLVMFastCallConv, llty);
981 982
}

983
fn decl_internal_fastcall_fn(ModuleRef llmod,
984
                            str name, TypeRef llty) -> ValueRef {
985
    auto llfn = decl_fn(llmod, name, lib.llvm.LLVMFastCallConv, llty);
986
    llvm.LLVMSetLinkage(llfn, lib.llvm.LLVMInternalLinkage as llvm.Linkage);
987 988 989
    ret llfn;
}

990 991
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()));
992 993
}

994
fn decl_native_glue(ModuleRef llmod, type_names tn,
995
                    bool pass_task, uint _n) -> ValueRef {
996
    // It doesn't actually matter what type we come up with here, at the
997 998
    // moment, as we cast the native function pointers to int before passing
    // them to the indirect native-invocation glue.  But eventually we'd like
999
    // to call them directly, once we have a calling convention worked out.
1000
    let int n = _n as int;
1001
    let str s = abi.native_glue_name(n, pass_task);
1002
    let vec[TypeRef] args = vec(T_int()); // callee
1003 1004
    if (!pass_task) {
        args += vec(T_int()); // taskptr, will not be passed
1005 1006
    }
    args += _vec.init_elt[TypeRef](T_int(), n as uint);
1007

1008
    ret decl_fastcall_fn(llmod, s, T_fn(args, T_int()));
1009 1010
}

1011 1012 1013
fn get_extern_fn(&hashmap[str, ValueRef] externs,
                 ModuleRef llmod, str name,
                 uint cc, TypeRef ty) -> ValueRef {
1014 1015
    if (externs.contains_key(name)) {
        ret externs.get(name);
1016
    }
1017
    auto f = decl_fn(llmod, name, cc, ty);
1018
    externs.insert(name, f);
1019 1020 1021
    ret f;
}

1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032
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,
1033
                     ModuleRef llmod, str name, int n_args) -> ValueRef {
1034 1035 1036 1037 1038 1039
    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);
}

1040
fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args) -> result {
1041
    auto cxx = cx.fcx.lcx.ccx;
1042 1043
    auto lltaskptr = cx.build.PtrToInt(cx.fcx.lltaskptr, T_int());
    auto args2 = vec(lltaskptr) + args;
1044 1045 1046
    auto t = trans_native_call(cx.build, cxx.glues, lltaskptr,
                               cxx.externs, cxx.tn, cxx.llmod, name,
                               true, args2);
1047 1048 1049
    ret res(cx, t);
}

1050 1051 1052 1053
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 {
1054
    let int n = (_vec.len[ValueRef](args) as int);
1055
    let ValueRef llnative = get_simple_extern_fn(externs, llmod, name, n);
1056
    llnative = llvm.LLVMConstPointerCast(llnative, T_int());
1057

1058 1059
    let ValueRef llglue;
    if (pass_task) {
1060
        llglue = glues.native_glues_rust.(n);
1061
    } else {
1062
        llglue = glues.native_glues_cdecl.(n);
1063
    }
1064
    let vec[ValueRef] call_args = vec(llnative);
1065

1066 1067 1068
    if (!pass_task) {
        call_args += vec(lltaskptr);
    }
1069

1070
    for (ValueRef a in args) {
1071
        call_args += vec(b.ZExtOrBitCast(a, T_int()));
1072
    }
1073

1074
    ret b.FastCall(llglue, call_args);
1075 1076
}

1077
fn trans_non_gc_free(@block_ctxt cx, ValueRef v) -> result {
1078
    ret trans_upcall(cx, "upcall_free", vec(vp2i(cx, v),
1079
                                            C_int(0)));
1080 1081
}

1082
fn find_scope_cx(@block_ctxt cx) -> @block_ctxt {
1083
    if (cx.kind != NON_SCOPE_BLOCK) {
1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
        ret cx;
    }
    alt (cx.parent) {
        case (parent_some(?b)) {
            be find_scope_cx(b);
        }
        case (parent_none) {
            fail;
        }
    }
}

1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
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;
        }
    }
}

1108 1109 1110 1111 1112
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);
}

1113 1114 1115 1116 1117
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);
}

1118 1119 1120 1121 1122 1123
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));
}

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

1129
fn llsize_of(TypeRef t) -> ValueRef {
1130 1131 1132
    ret llvm.LLVMConstIntCast(lib.llvm.llvm.LLVMSizeOf(t), T_int(), False);
}

1133
fn llalign_of(TypeRef t) -> ValueRef {
1134 1135 1136
    ret llvm.LLVMConstIntCast(lib.llvm.llvm.LLVMAlignOf(t), T_int(), False);
}

1137
fn size_of(@block_ctxt cx, ty.t t) -> result {
1138
    if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
1139
        ret res(cx, llsize_of(type_of(cx.fcx.lcx.ccx, t)));
1140 1141 1142 1143
    }
    ret dynamic_size_of(cx, t);
}

1144
fn align_of(@block_ctxt cx, ty.t t) -> result {
1145
    if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
1146
        ret res(cx, llalign_of(type_of(cx.fcx.lcx.ccx, t)));
1147 1148 1149 1150
    }
    ret dynamic_align_of(cx, t);
}

1151 1152 1153 1154 1155 1156 1157 1158 1159
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);
}


1160 1161 1162 1163
// 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.
1164 1165
fn simplify_type(@crate_ctxt ccx, ty.t typ) -> ty.t {
    fn simplifier(@crate_ctxt ccx, ty.t typ) -> ty.t {
1166
        alt (ty.struct(ccx.tcx, typ)) {
1167
            case (ty.ty_box(_)) {
1168
                ret ty.mk_imm_box(ccx.tcx, ty.mk_nil(ccx.tcx));
1169 1170 1171 1172
            }
            case (_) { ret typ; }
        }
    }
1173
    auto f = bind simplifier(ccx, _);
1174
    ret ty.fold_ty(ccx.tcx, f, typ);
1175 1176
}

1177
// Computes the size of the data part of a non-dynamically-sized tag.
1178
fn static_size_of_tag(@crate_ctxt cx, ty.t t) -> uint {
1179
    if (ty.type_has_dynamic_size(cx.tcx, t)) {
1180
        log_err "dynamically sized type passed to static_size_of_tag()";
1181 1182 1183 1184 1185 1186 1187
        fail;
    }

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

B
Brian Anderson 已提交
1188
    auto tid;
1189
    let vec[ty.t] subtys;
1190
    alt (ty.struct(cx.tcx, t)) {
1191 1192 1193 1194 1195
        case (ty.ty_tag(?tid_, ?subtys_)) {
            tid = tid_;
            subtys = subtys_;
        }
        case (_) {
1196
            log_err "non-tag passed to static_size_of_tag()";
1197 1198 1199 1200 1201 1202 1203
            fail;
        }
    }

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

1207
        // Perform any type parameter substitutions.
1208 1209
        tup_ty = ty.bind_params_in_type(cx.tcx, tup_ty);
        tup_ty = ty.substitute_type_params(cx.tcx, subtys, tup_ty);
1210

1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222
        // 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;
}

1223 1224
fn dynamic_size_of(@block_ctxt cx, ty.t t) -> result {
    fn align_elements(@block_ctxt cx, vec[ty.t] elts) -> result {
1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235
        //
        // 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;
1236
        for (ty.t e in elts) {
1237 1238 1239 1240 1241
            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);
1242
            off = bcx.build.Add(aligned_off, elt_size.val);
1243 1244 1245 1246 1247 1248
            max_align = umax(bcx, max_align, elt_align.val);
        }
        off = align_to(bcx, off, max_align);
        ret res(bcx, off);
    }

1249
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
1250 1251
        case (ty.ty_param(?p)) {
            auto szptr = field_of_tydesc(cx, t, abi.tydesc_field_size);
1252
            ret res(szptr.bcx, szptr.bcx.build.Load(szptr.val));
1253 1254
        }
        case (ty.ty_tup(?elts)) {
1255
            let vec[ty.t] tys = vec();
1256 1257 1258 1259
            for (ty.mt mt in elts) {
                tys += vec(mt.ty);
            }
            ret align_elements(cx, tys);
1260 1261
        }
        case (ty.ty_rec(?flds)) {
1262
            let vec[ty.t] tys = vec();
1263
            for (ty.field f in flds) {
1264
                tys += vec(f.mt.ty);
1265
            }
1266
            ret align_elements(cx, tys);
1267
        }
1268 1269 1270 1271
        case (ty.ty_tag(?tid, ?tps)) {
            auto bcx = cx;

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

1275
            auto variants = tag_variants(bcx.fcx.lcx.ccx, tid);
1276 1277
            for (variant_info variant in variants) {
                // Perform type substitution on the raw argument types.
1278 1279 1280
                let vec[ty.t] raw_tys = variant.args;
                let vec[ty.t] tys = vec();
                for (ty.t raw_ty in raw_tys) {
1281
                    auto t = ty.bind_params_in_type(cx.fcx.lcx.ccx.tcx,
1282
                                                    raw_ty);
1283
                    t = ty.substitute_type_params(cx.fcx.lcx.ccx.tcx, tps, t);
1284 1285 1286
                    tys += vec(t);
                }

1287 1288 1289 1290 1291 1292 1293 1294
                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);
            }

1295 1296 1297
            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);
1298
        }
1299 1300 1301
    }
}

1302
fn dynamic_align_of(@block_ctxt cx, ty.t t) -> result {
1303
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
1304 1305
        case (ty.ty_param(?p)) {
            auto aptr = field_of_tydesc(cx, t, abi.tydesc_field_align);
1306
            ret res(aptr.bcx, aptr.bcx.build.Load(aptr.val));
1307 1308 1309
        }
        case (ty.ty_tup(?elts)) {
            auto a = C_int(1);
1310
            auto bcx = cx;
1311 1312
            for (ty.mt e in elts) {
                auto align = align_of(bcx, e.ty);
1313 1314
                bcx = align.bcx;
                a = umax(bcx, a, align.val);
1315
            }
1316
            ret res(bcx, a);
1317 1318 1319
        }
        case (ty.ty_rec(?flds)) {
            auto a = C_int(1);
1320
            auto bcx = cx;
1321
            for (ty.field f in flds) {
1322
                auto align = align_of(bcx, f.mt.ty);
1323 1324
                bcx = align.bcx;
                a = umax(bcx, a, align.val);
1325
            }
1326
            ret res(bcx, a);
1327
        }
1328 1329 1330
        case (ty.ty_tag(_, _)) {
            ret res(cx, C_int(1)); // FIXME: stub
        }
1331 1332 1333
    }
}

1334
// Replacement for the LLVM 'GEP' instruction when field-indexing into a
1335 1336 1337 1338
// 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.
1339

1340
fn GEP_tup_like(@block_ctxt cx, ty.t t,
1341
                ValueRef base, vec[int] ixs) -> result {
1342

1343
    check (ty.type_is_tup_like(cx.fcx.lcx.ccx.tcx, t));
1344 1345 1346

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

1347
    if (! ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
1348 1349
        let vec[ValueRef] v = vec();
        for (int i in ixs) {
1350
            v += vec(C_int(i));
1351
        }
1352
        ret res(cx, cx.build.GEP(base, v));
1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371
    }

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

1372
    fn split_type(@crate_ctxt ccx, ty.t t, vec[int] ixs, uint n)
1373
        -> rec(vec[ty.t] prefix, ty.t target) {
1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387

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

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

        check (len > 1u);

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

        check (n < len);

        let int ix = ixs.(n);
1394
        let vec[ty.t] prefix = vec();
1395 1396
        let int i = 0;
        while (i < ix) {
1397
            _vec.push[ty.t](prefix,
1398
                            ty.get_element_type(ccx.tcx, t, i as uint));
1399
            i += 1 ;
1400 1401
        }

1402
        auto selected = ty.get_element_type(ccx.tcx, t, i as uint);
1403 1404 1405 1406 1407 1408 1409 1410 1411

        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.
1412
            auto inner = split_type(ccx, selected, ixs, n+1u);
1413 1414 1415 1416 1417 1418 1419 1420 1421
            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.

1422
    auto s = split_type(cx.fcx.lcx.ccx, t, ixs, 0u);
1423
    auto prefix_ty = ty.mk_imm_tup(cx.fcx.lcx.ccx.tcx, s.prefix);
1424 1425 1426 1427 1428
    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));
1429

1430
    if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, s.target)) {
1431
        ret res(bcx, bumped);
1432
    }
1433

1434
    auto typ = T_ptr(type_of(bcx.fcx.lcx.ccx, s.target));
1435
    ret res(bcx, bcx.build.PointerCast(bumped, typ));
1436 1437
}

1438 1439 1440 1441
// 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.
1442 1443 1444 1445
fn GEP_tag(@block_ctxt cx,
           ValueRef llblobptr,
           &ast.def_id tag_id,
           &ast.def_id variant_id,
1446
           vec[ty.t] ty_substs,
1447
           int ix)
1448
        -> result {
1449
    auto variant = tag_variant_with_id(cx.fcx.lcx.ccx, tag_id, variant_id);
1450

1451 1452
    // Synthesize a tuple type so that GEP_tup_like() can work its magic.
    // Separately, store the type of the element we're interested in.
1453
    auto arg_tys = variant.args;
1454
    auto elem_ty = ty.mk_nil(cx.fcx.lcx.ccx.tcx); // typestate infelicity
1455
    auto i = 0;
1456 1457
    let vec[ty.t] true_arg_tys = vec();
    for (ty.t aty in arg_tys) {
1458 1459
        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,
1460
                                           arg_ty);
1461
        true_arg_tys += vec(arg_ty);
1462
        if (i == ix) {
1463
            elem_ty = arg_ty;
1464 1465 1466 1467
        }

        i += 1;
    }
1468

1469
    auto tup_ty = ty.mk_imm_tup(cx.fcx.lcx.ccx.tcx, true_arg_tys);
1470 1471 1472 1473

    // 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;
1474
    if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, tup_ty)) {
1475
        auto llty = type_of(cx.fcx.lcx.ccx, tup_ty);
1476 1477 1478 1479 1480 1481 1482 1483 1484 1485
        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;
1486
    if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, elem_ty)) {
1487
        auto llelemty = type_of(rslt.bcx.fcx.lcx.ccx, elem_ty);
1488 1489 1490 1491 1492 1493 1494 1495
        val = rslt.bcx.build.PointerCast(rslt.val, T_ptr(llelemty));
    } else {
        val = rslt.val;
    }

    ret res(rslt.bcx, val);
}

1496

1497
fn trans_raw_malloc(@block_ctxt cx, TypeRef llptr_ty, ValueRef llsize)
1498
        -> result {
1499 1500
    // FIXME: need a table to collect tydesc globals.
    auto tydesc = C_int(0);
1501
    auto rslt = trans_upcall(cx, "upcall_malloc", vec(llsize, tydesc));
1502
    rslt = res(rslt.bcx, vi2p(rslt.bcx, rslt.val, llptr_ty));
1503 1504 1505
    ret rslt;
}

1506
fn trans_malloc_boxed(@block_ctxt cx, ty.t t) -> result {
1507 1508
    // Synthesize a fake box type structurally so we have something
    // to measure the size of.
1509 1510 1511
    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);
1512
    auto sz = size_of(cx, boxed_body);
1513
    auto llty = type_of(cx.fcx.lcx.ccx, box_ptr);
1514
    ret trans_raw_malloc(sz.bcx, llty, sz.val);
1515 1516 1517
}


1518 1519 1520 1521 1522
// 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.
1523
fn field_of_tydesc(@block_ctxt cx, ty.t t, int field) -> result {
1524
    auto tydesc = get_tydesc(cx, t);
1525 1526
    ret res(tydesc.bcx,
            tydesc.bcx.build.GEP(tydesc.val, vec(C_int(0), C_int(field))));
1527
}
1528

1529
// Given a type containing ty params, build a vector containing a ValueRef for
1530 1531
// 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
1532
// constructing derived tydescs.
1533
fn linearize_ty_params(@block_ctxt cx, ty.t t) ->
1534
        tup(vec[uint], vec[ValueRef]) {
1535
    let vec[ValueRef] param_vals = vec();
1536
    let vec[uint] param_defs = vec();
1537
    type rr = rec(@block_ctxt cx,
1538
                  mutable vec[ValueRef] vals,
1539
                  mutable vec[uint] defs);
1540

1541
    fn linearizer(@rr r, ty.t t) {
1542
        alt(ty.struct(r.cx.fcx.lcx.ccx.tcx, t)) {
1543 1544 1545 1546 1547
            case (ty.ty_param(?pid)) {
                let bool seen = false;
                for (uint d in r.defs) {
                    if (d == pid) {
                        seen = true;
1548 1549
                    }
                }
1550
                if (!seen) {
1551
                    r.vals += vec(r.cx.fcx.lltydescs.(pid));
1552 1553
                    r.defs += vec(pid);
                }
1554
            }
1555
            case (_) { }
1556 1557 1558 1559 1560 1561 1562 1563
        }
    }


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

1564
    auto f = bind linearizer(x, _);
1565
    ty.walk_ty(cx.fcx.lcx.ccx.tcx, f, t);
1566 1567 1568 1569

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

1570
fn get_tydesc(&@block_ctxt cx, ty.t t) -> result {
1571
    // Is the supplied type a type param? If so, return the passed-in tydesc.
1572
    alt (ty.type_param(cx.fcx.lcx.ccx.tcx, t)) {
1573
        case (some[uint](?id)) { ret res(cx, cx.fcx.lltydescs.(id)); }
1574
        case (none[uint])      { /* fall through */ }
1575
    }
1576 1577

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

1579 1580 1581
    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);
1582
        auto tys = linearize_ty_params(cx, t);
1583

1584
        check (n_params == _vec.len[uint](tys._0));
1585 1586
        check (n_params == _vec.len[ValueRef](tys._1));

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

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

1592
        auto i = 0;
1593 1594 1595
        auto tdp = cx.build.GEP(tydescs, vec(C_int(0), C_int(i)));
        cx.build.Store(root, tdp);
        i += 1;
1596 1597
        for (ValueRef td in tys._1) {
            auto tdp = cx.build.GEP(tydescs, vec(C_int(0), C_int(i)));
1598
            cx.build.Store(td, tdp);
1599
            i += 1;
1600 1601 1602 1603 1604 1605 1606 1607 1608
        }

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

        auto v = trans_upcall(bcx, "upcall_get_type_desc",
1609
                              vec(p2i(bcx.fcx.lcx.ccx.crate_ptr),
1610 1611
                                  sz.val,
                                  align.val,
1612
                                  C_int((1u + n_params) as int),
1613
                                  vp2i(bcx, tydescs)));
1614

1615
        ret res(v.bcx, vi2p(v.bcx, v.val,
1616
                            T_ptr(T_tydesc(cx.fcx.lcx.ccx.tn))));
1617 1618 1619
    }

    // Otherwise, generate a tydesc if necessary, and return it.
1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630
    let vec[uint] tps = vec();
    ret res(cx, get_static_tydesc(cx, t, tps).tydesc);
}

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]) {
1631 1632 1633 1634 1635 1636 1637

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

            /*
1638 1639 1640 1641 1642 1643 1644
            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);
1645 1646 1647 1648
            */

            auto info = declare_tydesc(cx.fcx.lcx, t);
            cx.fcx.lcx.ccx.tydescs.insert(t, info);
1649 1650 1651
            define_tydesc(cx.fcx.lcx, t, ty_params);
            ret info;
        }
1652
    }
1653 1654
}

1655 1656 1657
// 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.
1658
fn declare_tydesc(@local_ctxt cx, ty.t t) -> @tydesc_info {
1659 1660 1661 1662 1663 1664
    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");
1665
    auto ccx = cx.ccx;
1666

1667 1668
    auto llsize;
    auto llalign;
1669
    if (!ty.type_has_dynamic_size(ccx.tcx, t)) {
1670
        auto llty = type_of(ccx, t);
1671 1672 1673 1674 1675 1676 1677 1678 1679
        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);
    }

1680
    auto glue_fn_ty = T_ptr(T_glue_fn(ccx.tn));
1681

1682
    auto name = mangle_name_by_seq(ccx, cx.path, "tydesc");
1683
    auto gvar = llvm.LLVMAddGlobal(ccx.llmod, T_tydesc(ccx.tn),
1684
                                   _str.buf(name));
1685
    auto tydesc = C_struct(vec(C_null(T_ptr(T_ptr(T_tydesc(ccx.tn)))),
1686 1687
                               llsize,
                               llalign,
1688 1689 1690 1691 1692 1693
                               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
1694 1695
                               C_null(glue_fn_ty),    // is_stateful
                               cmp_glue));            // cmp_glue
1696 1697 1698

    llvm.LLVMSetInitializer(gvar, tydesc);
    llvm.LLVMSetGlobalConstant(gvar, True);
1699
    llvm.LLVMSetLinkage(gvar, lib.llvm.LLVMInternalLinkage
1700
                        as llvm.Linkage);
1701

1702
    auto info = @rec(
1703 1704
        tydesc=gvar,
        take_glue=take_glue,
1705 1706
        drop_glue=drop_glue,
        cmp_glue=cmp_glue
1707
    );
1708

1709
    ret info;
1710 1711
}

1712
tag make_generic_glue_helper_fn {
1713
    mgghf_single(fn(@block_ctxt cx, ValueRef v, ty.t t));
1714
    mgghf_cmp;
1715 1716
}

1717
// declare_tydesc() above must have been called first.
1718
fn define_tydesc(@local_ctxt cx, ty.t t, vec[uint] ty_params) {
1719
    auto info = cx.ccx.tydescs.get(t);
1720 1721 1722
    auto gvar = info.tydesc;

    auto tg = make_take_glue;
1723
    make_generic_glue(cx, t, info.take_glue, mgghf_single(tg), ty_params);
1724
    auto dg = make_drop_glue;
1725
    make_generic_glue(cx, t, info.drop_glue, mgghf_single(dg), ty_params);
1726
    make_generic_glue(cx, t, info.cmp_glue, mgghf_cmp, ty_params);
1727 1728
}

1729
fn declare_generic_glue(@local_ctxt cx,
1730
                        ty.t t,
1731 1732
                        TypeRef llfnty,
                        str name) -> ValueRef {
1733
    auto gcx = @rec(path=vec("glue", name) with *cx);
1734
    auto fn_nm = mangle_name_by_seq(cx.ccx, cx.path, "glue");
1735 1736
    fn_nm = sanitize(fn_nm);
    auto llfn = decl_internal_fastcall_fn(cx.ccx.llmod, fn_nm, llfnty);
1737
    ret llfn;
1738
}
1739

1740
fn make_generic_glue(@local_ctxt cx,
1741
                     ty.t t,
1742 1743 1744
                     ValueRef llfn,
                     make_generic_glue_helper_fn helper,
                     vec[uint] ty_params) -> ValueRef {
1745
    auto fcx = new_fn_ctxt(cx, llfn);
1746
    auto bcx = new_top_block_ctxt(fcx);
1747
    auto lltop = bcx.llbb;
1748

1749 1750 1751 1752
    // 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.
1753

1754
    auto llty;
1755
    if (ty.type_has_dynamic_size(cx.ccx.tcx, t)) {
1756 1757 1758 1759
        llty = T_ptr(T_i8());
    } else {
        llty = T_ptr(type_of(cx.ccx, t));
    }
1760

1761
    auto ty_param_count = _vec.len[uint](ty_params);
1762

1763
    auto lltyparams = llvm.LLVMGetParam(llfn, 3u);
1764

1765 1766 1767 1768 1769 1770 1771 1772 1773 1774
    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);
1775

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

1779 1780 1781 1782 1783 1784
    alt (helper) {
        case (mgghf_single(?single_fn)) {
            single_fn(bcx, llval0, t);
        }
        case (mgghf_cmp) {
            auto llrawptr1 = llvm.LLVMGetParam(llfn, 5u);
1785
            auto llval1 = bcx.build.BitCast(llrawptr1, llty);
1786

1787
            auto llcmpval = llvm.LLVMGetParam(llfn, 6u);
1788

1789
            make_cmp_glue(bcx, llval0, llval1, t, llcmpval);
1790
        }
1791
    }
1792

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

1796 1797 1798
    ret llfn;
}

1799
fn make_take_glue(@block_ctxt cx, ValueRef v, ty.t t) {
1800
    // NB: v is an *alias* of type t here, not a direct value.
1801
    auto bcx;
1802
    if (ty.type_is_boxed(cx.fcx.lcx.ccx.tcx, t)) {
1803
        bcx = incr_refcnt_of_boxed(cx, cx.build.Load(v)).bcx;
1804

1805
    } else if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, t)) {
1806 1807 1808 1809
        bcx = iter_structural_ty(cx, v, t,
                                 bind take_ty(_, _, _)).bcx;
    } else {
        bcx = cx;
1810
    }
1811
    bcx.build.RetVoid();
1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832
}

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

1833
fn make_drop_glue(@block_ctxt cx, ValueRef v0, ty.t t) {
1834
    // NB: v0 is an *alias* of type t here, not a direct value.
1835
    auto rslt;
1836
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
1837
        case (ty.ty_str) {
1838
            auto v = cx.build.Load(v0);
1839
            rslt = decr_refcnt_and_if_zero
G
Graydon Hoare 已提交
1840 1841 1842
                (cx, v, bind trans_non_gc_free(_, v),
                 "free string",
                 T_int(), C_int(0));
1843 1844
        }

1845
        case (ty.ty_vec(_)) {
G
Graydon Hoare 已提交
1846
            fn hit_zero(@block_ctxt cx, ValueRef v,
1847
                        ty.t t) -> result {
G
Graydon Hoare 已提交
1848 1849
                auto res = iter_sequence(cx, v, t,
                                         bind drop_ty(_,_,_));
1850 1851 1852
                // FIXME: switch gc/non-gc on layer of the type.
                ret trans_non_gc_free(res.bcx, v);
            }
1853
            auto v = cx.build.Load(v0);
1854 1855 1856 1857
            rslt = decr_refcnt_and_if_zero(cx, v,
                                          bind hit_zero(_, v, t),
                                          "free vector",
                                          T_int(), C_int(0));
1858 1859
        }

1860
        case (ty.ty_box(?body_mt)) {
G
Graydon Hoare 已提交
1861
            fn hit_zero(@block_ctxt cx, ValueRef v,
1862
                        ty.t body_ty) -> result {
1863 1864 1865 1866
                auto body = cx.build.GEP(v,
                                         vec(C_int(0),
                                             C_int(abi.box_rc_field_body)));

1867
                auto body_val = load_if_immediate(cx, body, body_ty);
1868 1869 1870 1871
                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);
            }
1872
            auto v = cx.build.Load(v0);
1873 1874 1875 1876
            rslt = decr_refcnt_and_if_zero(cx, v,
                                           bind hit_zero(_, v, body_mt.ty),
                                           "free box",
                                           T_int(), C_int(0));
1877 1878
        }

B
Brian Anderson 已提交
1879 1880 1881 1882 1883
        case (ty.ty_port(_)) {
            fn hit_zero(@block_ctxt cx, ValueRef v) -> result {
                ret trans_upcall(cx, "upcall_del_port",
                                 vec(vp2i(cx, v)));
            }
1884
            auto v = cx.build.Load(v0);
1885 1886 1887 1888
            rslt = decr_refcnt_and_if_zero(cx, v,
                                           bind hit_zero(_, v),
                                           "free port",
                                           T_int(), C_int(0));
B
Brian Anderson 已提交
1889 1890 1891 1892 1893 1894 1895
        }

        case (ty.ty_chan(_)) {
            fn hit_zero(@block_ctxt cx, ValueRef v) -> result {
                ret trans_upcall(cx, "upcall_del_chan",
                                 vec(vp2i(cx, v)));
            }
1896
            auto v = cx.build.Load(v0);
1897 1898 1899 1900
            rslt = decr_refcnt_and_if_zero(cx, v,
                                           bind hit_zero(_, v),
                                           "free chan",
                                           T_int(), C_int(0));
B
Brian Anderson 已提交
1901 1902
        }

1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915
        case (ty.ty_obj(_)) {
            fn hit_zero(@block_ctxt cx, ValueRef v) -> result {

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

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

1917
                call_tydesc_glue_full(cx, body, cx.build.Load(tydescptr),
1918
                                      abi.tydesc_field_drop_glue);
1919 1920 1921 1922 1923 1924

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

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

1931 1932 1933 1934
            rslt = decr_refcnt_and_if_zero(cx, boxptr,
                                           bind hit_zero(_, boxptr),
                                           "free obj",
                                           T_int(), C_int(0));
1935 1936
        }

1937
        case (ty.ty_fn(_,_,_)) {
1938 1939 1940 1941 1942 1943 1944
            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)));
1945 1946 1947 1948
                auto bindings =
                    cx.build.GEP(body,
                                 vec(C_int(0),
                                     C_int(abi.closure_elt_bindings)));
1949 1950 1951 1952 1953

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

1955
                call_tydesc_glue_full(cx, bindings, cx.build.Load(tydescptr),
1956
                                      abi.tydesc_field_drop_glue);
1957

1958 1959 1960 1961 1962 1963

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

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

1970 1971 1972 1973
            rslt = decr_refcnt_and_if_zero(cx, boxptr,
                                           bind hit_zero(_, boxptr),
                                           "free fn",
                                           T_int(), C_int(0));
1974 1975
        }

1976
        case (_) {
1977
            if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, t)) {
1978 1979
                rslt = iter_structural_ty(cx, v0, t,
                                          bind drop_ty(_, _, _));
1980

1981 1982 1983
            } 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)) {
1984
                rslt = res(cx, C_nil());
1985 1986
            } else {
                rslt = res(cx, C_nil());
1987 1988 1989
            }
        }
    }
1990 1991

    rslt.bcx.build.RetVoid();
1992 1993
}

1994 1995
fn decr_refcnt_and_if_zero(@block_ctxt cx,
                           ValueRef box_ptr,
1996
                           fn(@block_ctxt cx) -> result inner,
1997
                           str inner_name,
1998
                           TypeRef t_else, ValueRef v_else) -> result {
1999

2000
    auto load_rc_cx = new_sub_block_ctxt(cx, "load rc");
2001 2002 2003 2004
    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");

2005 2006
    auto null_test = cx.build.IsNull(box_ptr);
    cx.build.CondBr(null_test, next_cx.llbb, load_rc_cx.llbb);
2007

2008 2009 2010 2011 2012 2013 2014 2015 2016 2017

    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);
2018 2019 2020 2021

    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);
2022 2023 2024 2025
    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);
2026

2027
    auto phi = next_cx.build.Phi(t_else,
2028
                                 vec(v_else, v_else, v_else, inner_res.val),
2029
                                 vec(cx.llbb,
2030
                                     load_rc_cx.llbb,
2031
                                     rc_adj_cx.llbb,
2032 2033
                                     inner_res.bcx.llbb));

2034
    ret res(next_cx, phi);
2035 2036
}

2037 2038 2039 2040 2041
// Structural comparison: a rather involved form of glue.

fn make_cmp_glue(@block_ctxt cx,
                 ValueRef lhs0,
                 ValueRef rhs0,
2042
                 ty.t t,
2043 2044 2045 2046
                 ValueRef llop) {
    auto lhs = load_if_immediate(cx, lhs0, t);
    auto rhs = load_if_immediate(cx, rhs0, t);

2047
    if (ty.type_is_scalar(cx.fcx.lcx.ccx.tcx, t)) {
2048 2049
        make_scalar_cmp_glue(cx, lhs, rhs, t, llop);

2050
    } else if (ty.type_is_box(cx.fcx.lcx.ccx.tcx, t)) {
2051 2052 2053 2054 2055 2056 2057
        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();

2058 2059
    } else if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, t)
               || ty.type_is_sequence(cx.fcx.lcx.ccx.tcx, t)) {
2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092

        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;
2093
        if (ty.type_is_sequence(cx.fcx.lcx.ccx.tcx, t)) {
2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119

            // 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,
2120
                 ty.t t) -> result {
2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131

            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.

2132
                if (!ty.type_has_dynamic_size(last_cx.fcx.lcx.ccx.tcx, t)) {
2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153
                    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());
        }

2154
        if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, t)) {
2155 2156 2157 2158 2159 2160 2161 2162 2163
            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));
2164
            auto elt_ty = ty.sequence_element_type(cx.fcx.lcx.ccx.tcx, t);
2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180
            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],
2181
                   "attempt to compare values of type " +
2182
                   ty.ty_to_str(cx.fcx.lcx.ccx.tcx, t));
2183 2184 2185 2186
    }
}

// A helper function to create scalar comparison glue.
2187
fn make_scalar_cmp_glue(@block_ctxt cx, ValueRef lhs, ValueRef rhs, ty.t t,
2188
                        ValueRef llop) {
2189
    if (ty.type_is_fp(cx.fcx.lcx.ccx.tcx, t)) {
2190 2191 2192 2193
        make_fp_cmp_glue(cx, lhs, rhs, t, llop);
        ret;
    }

2194 2195
    if (ty.type_is_integral(cx.fcx.lcx.ccx.tcx, t) ||
            ty.type_is_bool(cx.fcx.lcx.ccx.tcx, t)) {
2196 2197 2198 2199
        make_integral_cmp_glue(cx, lhs, rhs, t, llop);
        ret;
    }

2200
    if (ty.type_is_nil(cx.fcx.lcx.ccx.tcx, t)) {
2201 2202 2203 2204 2205 2206
        cx.build.Store(C_bool(true), cx.fcx.llretptr);
        cx.build.RetVoid();
        ret;
    }

    trans_fail(cx, none[common.span],
2207
               "attempt to compare values of type " +
2208
               ty.ty_to_str(cx.fcx.lcx.ccx.tcx, t));
2209 2210 2211
}

// A helper function to create floating point comparison glue.
2212
fn make_fp_cmp_glue(@block_ctxt cx, ValueRef lhs, ValueRef rhs, ty.t fptype,
2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 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
                    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,
2286
                          ty.t intype, ValueRef llop) {
2287
    auto r = compare_integral_values(cx, lhs, rhs,
2288
        ty.type_is_signed(cx.fcx.lcx.ccx.tcx, intype), llop);
2289 2290
    r.bcx.build.Store(r.val, r.bcx.fcx.llretptr);
    r.bcx.build.RetVoid();
2291 2292 2293
}


2294 2295
// Tag information

2296
type variant_info = rec(vec[ty.t] args, ty.t ctor_ty, ast.def_id id);
2297 2298 2299

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

2304 2305
    check (cx.items.contains_key(id));
    alt (cx.items.get(id).node) {
2306 2307 2308 2309
        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);
2310
                let vec[ty.t] arg_tys = vec();
2311
                if (_vec.len[ast.variant_arg](variant.node.args) > 0u) {
2312
                    for (ty.arg a in ty.ty_fn_args(cx.tcx, ctor_ty)) {
2313 2314 2315 2316 2317 2318 2319 2320
                        arg_tys += vec(a.ty);
                    }
                }
                auto did = variant.node.id;
                result += vec(rec(args=arg_tys, ctor_ty=ctor_ty, id=did));
            }
            ret result;
        }
2321 2322 2323 2324
    }
    fail;   // not reached
}

2325
// Returns information about the tag variant with the given ID.
2326 2327
fn tag_variant_with_id(@crate_ctxt cx,
                       &ast.def_id tag_id,
2328
                       &ast.def_id variant_id) -> variant_info {
2329 2330 2331
    auto variants = tag_variants(cx, tag_id);

    auto i = 0u;
2332
    while (i < _vec.len[variant_info](variants)) {
2333
        auto variant = variants.(i);
2334
        if (common.def_eq(variant.id, variant_id)) {
2335 2336 2337 2338 2339
            ret variant;
        }
        i += 1u;
    }

2340
    log_err "tag_variant_with_id(): no variant exists with that ID";
2341 2342 2343
    fail;
}

2344

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

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

2349
type val_pair_and_ty_fn =
2350
    fn(@block_ctxt cx, ValueRef av, ValueRef bv, ty.t t) -> result;
2351

2352
// Iterates through the elements of a structural type.
2353 2354
fn iter_structural_ty(@block_ctxt cx,
                      ValueRef v,
2355
                      ty.t t,
2356 2357
                      val_and_ty_fn f)
    -> result {
2358 2359 2360 2361
    fn adaptor_fn(val_and_ty_fn f,
                  @block_ctxt cx,
                  ValueRef av,
                  ValueRef bv,
2362
                  ty.t t) -> result {
2363 2364 2365 2366 2367 2368 2369 2370 2371 2372
        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,
2373
                           ty.t t,
2374 2375
                           val_pair_and_ty_fn f)
    -> result {
2376
    let result r = res(cx, C_nil());
2377

2378
    fn iter_boxpp(@block_ctxt cx,
2379 2380 2381 2382 2383
                  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);
2384 2385
        auto tnil = ty.mk_nil(cx.fcx.lcx.ccx.tcx);
        auto tbox = ty.mk_imm_box(cx.fcx.lcx.ccx.tcx, tnil);
2386 2387 2388

        auto inner_cx = new_sub_block_ctxt(cx, "iter box");
        auto next_cx = new_sub_block_ctxt(cx, "next");
2389
        auto null_test = cx.build.IsNull(box_a_ptr);
2390 2391
        cx.build.CondBr(null_test, next_cx.llbb, inner_cx.llbb);

2392
        auto r = f(inner_cx, box_a_ptr, box_b_ptr, tbox);
2393
        r.bcx.build.Br(next_cx.llbb);
2394
        ret res(next_cx, C_nil());
2395 2396
    }

2397
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
2398
        case (ty.ty_tup(?args)) {
2399
            let int i = 0;
2400
            for (ty.mt arg in args) {
2401 2402 2403 2404
                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;
2405
                r = f(r.bcx,
2406 2407
                      load_if_immediate(r.bcx, elt_a, arg.ty),
                      load_if_immediate(r.bcx, elt_b, arg.ty),
2408
                      arg.ty);
2409 2410 2411
                i += 1;
            }
        }
2412
        case (ty.ty_rec(?fields)) {
2413
            let int i = 0;
2414
            for (ty.field fld in fields) {
2415 2416 2417 2418
                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;
2419
                r = f(r.bcx,
2420 2421
                      load_if_immediate(r.bcx, llfld_a, fld.mt.ty),
                      load_if_immediate(r.bcx, llfld_b, fld.mt.ty),
2422
                      fld.mt.ty);
2423 2424 2425
                i += 1;
            }
        }
2426
        case (ty.ty_tag(?tid, ?tps)) {
2427
            auto variants = tag_variants(cx.fcx.lcx.ccx, tid);
2428
            auto n_variants = _vec.len[variant_info](variants);
2429

2430
            // Cast the tags to types we can GEP into.
2431
            auto lltagty = T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn);
2432 2433 2434 2435 2436 2437 2438
            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)));
2439 2440
            auto lldiscrim_a = cx.build.Load(lldiscrim_a_ptr);

2441 2442 2443 2444
            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)));
2445
            auto lldiscrim_b = cx.build.Load(lldiscrim_b_ptr);
G
Graydon Hoare 已提交
2446

2447 2448 2449
            // NB: we must hit the discriminant first so that structural
            // comparison know not to proceed when the discriminants differ.
            auto bcx = cx;
2450
            bcx = f(bcx, lldiscrim_a, lldiscrim_b,
2451
                    ty.mk_int(cx.fcx.lcx.ccx.tcx)).bcx;
2452 2453

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

2456
            auto llswitch = bcx.build.Switch(lldiscrim_a, unr_cx.llbb,
2457
                                             n_variants);
G
Graydon Hoare 已提交
2458

2459
            auto next_cx = new_sub_block_ctxt(bcx, "tag-iter-next");
2460 2461

            auto i = 0u;
2462
            for (variant_info variant in variants) {
2463
                auto variant_cx = new_sub_block_ctxt(bcx,
2464
                                                     "tag-iter-variant-" +
2465 2466 2467
                                                     _uint.to_str(i, 10u));
                llvm.LLVMAddCase(llswitch, C_int(i as int), variant_cx.llbb);

2468
                if (_vec.len[ty.t](variant.args) > 0u) {
2469
                    // N-ary variant.
2470
                    auto fn_ty = variant.ctor_ty;
2471
                    alt (ty.struct(bcx.fcx.lcx.ccx.tcx, fn_ty)) {
2472
                        case (ty.ty_fn(_, ?args, _)) {
2473
                            auto j = 0;
2474 2475
                            for (ty.arg a in args) {
                                auto v = vec(C_int(0), C_int(j as int));
2476

2477
                                auto rslt = GEP_tag(variant_cx, llunion_a_ptr,
2478
                                    tid, variant.id, tps, j);
2479 2480
                                auto llfldp_a = rslt.val;
                                variant_cx = rslt.bcx;
2481

2482
                                rslt = GEP_tag(variant_cx, llunion_b_ptr, tid,
2483
                                    variant.id, tps, j);
2484 2485
                                auto llfldp_b = rslt.val;
                                variant_cx = rslt.bcx;
2486

2487
                                auto ty_subst = ty.bind_params_in_type(
2488
                                    cx.fcx.lcx.ccx.tcx, a.ty);
2489
                                ty_subst = ty.substitute_type_params(
2490
                                    cx.fcx.lcx.ccx.tcx, tps, ty_subst);
2491

2492
                                auto llfld_a =
2493
                                    load_if_immediate(variant_cx,
2494
                                                         llfldp_a,
2495 2496
                                                         ty_subst);

2497
                                auto llfld_b =
2498
                                    load_if_immediate(variant_cx,
2499 2500 2501 2502 2503
                                                         llfldp_b,
                                                         ty_subst);

                                auto res = f(variant_cx,
                                             llfld_a, llfld_b, ty_subst);
2504
                                variant_cx = res.bcx;
2505
                                j += 1;
2506 2507
                            }
                        }
2508
                        case (_) { fail; }
2509
                    }
2510 2511 2512 2513 2514

                    variant_cx.build.Br(next_cx.llbb);
                } else {
                    // Nullary variant; nothing to do.
                    variant_cx.build.Br(next_cx.llbb);
2515 2516 2517 2518 2519 2520 2521
                }

                i += 1u;
            }

            ret res(next_cx, C_nil());
        }
2522
        case (ty.ty_fn(_,_,_)) {
2523 2524 2525 2526 2527 2528
            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,
2529 2530
                             vec(C_int(0),
                                 C_int(abi.fn_field_box)));
2531
            ret iter_boxpp(cx, box_cell_a, box_cell_b, f);
2532
        }
2533
        case (ty.ty_obj(_)) {
2534 2535 2536 2537 2538 2539
            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,
2540 2541
                             vec(C_int(0),
                                 C_int(abi.obj_field_box)));
2542
            ret iter_boxpp(cx, box_cell_a, box_cell_b, f);
2543
        }
2544
        case (_) {
2545
            cx.fcx.lcx.ccx.sess.unimpl("type in iter_structural_ty_full");
2546
        }
2547
    }
2548
    ret r;
2549 2550
}

2551 2552
// Iterates through a pointer range, until the src* hits the src_lim*.
fn iter_sequence_raw(@block_ctxt cx,
2553
                     ValueRef dst,     // elt*
2554 2555 2556
                     ValueRef src,     // elt*
                     ValueRef src_lim, // elt*
                     ValueRef elt_sz,
2557
                     val_pair_fn f) -> result {
2558 2559 2560

    auto bcx = cx;

2561
    let ValueRef dst_int = vp2i(bcx, dst);
2562 2563 2564 2565 2566 2567 2568 2569 2570
    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);

2571 2572
    let ValueRef dst_curr = cond_cx.build.Phi(T_int(),
                                              vec(dst_int), vec(bcx.llbb));
2573 2574 2575
    let ValueRef src_curr = cond_cx.build.Phi(T_int(),
                                              vec(src_int), vec(bcx.llbb));

2576
    auto end_test = cond_cx.build.ICmp(lib.llvm.LLVMIntULT,
2577 2578 2579 2580
                                       src_curr, src_lim_int);

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

2581
    auto dst_curr_ptr = vi2p(body_cx, dst_curr, T_ptr(T_i8()));
2582
    auto src_curr_ptr = vi2p(body_cx, src_curr, T_ptr(T_i8()));
2583

2584
    auto body_res = f(body_cx, dst_curr_ptr, src_curr_ptr);
2585 2586
    body_cx = body_res.bcx;

2587
    auto dst_next = body_cx.build.Add(dst_curr, elt_sz);
2588
    auto src_next = body_cx.build.Add(src_curr, elt_sz);
2589 2590
    body_cx.build.Br(cond_cx.llbb);

2591 2592
    cond_cx.build.AddIncomingToPhi(dst_curr, vec(dst_next),
                                   vec(body_cx.llbb));
2593 2594 2595 2596 2597 2598 2599 2600 2601 2602
    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*
2603
                       ty.t elt_ty,
2604 2605
                       val_and_ty_fn f) -> result {
    fn adaptor_fn(val_and_ty_fn f,
2606
                  ty.t elt_ty,
2607
                  @block_ctxt cx,
2608 2609
                  ValueRef dst,
                  ValueRef src) -> result {
2610
        auto llptrty;
2611
        if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, elt_ty)) {
2612
            auto llty = type_of(cx.fcx.lcx.ccx, elt_ty);
2613 2614 2615 2616 2617 2618
            llptrty = T_ptr(llty);
        } else {
            llptrty = T_ptr(T_ptr(T_i8()));
        }

        auto p = cx.build.PointerCast(src, llptrty);
2619
        ret f(cx, load_if_immediate(cx, p, elt_ty), elt_ty);
2620 2621
    }

2622
    auto elt_sz = size_of(cx, elt_ty);
2623 2624
    be iter_sequence_raw(elt_sz.bcx, src, src, src_lim, elt_sz.val,
                         bind adaptor_fn(f, elt_ty, _, _, _));
2625 2626 2627
}


2628 2629 2630
// Iterates through the elements of a vec or str.
fn iter_sequence(@block_ctxt cx,
                 ValueRef v,
2631
                 ty.t t,
2632 2633 2634 2635
                 val_and_ty_fn f) -> result {

    fn iter_sequence_body(@block_ctxt cx,
                          ValueRef v,
2636
                          ty.t elt_ty,
2637 2638 2639 2640 2641 2642 2643
                          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)));
2644

2645
        auto llunit_ty;
2646
        if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, elt_ty)) {
2647 2648
            llunit_ty = T_i8();
        } else {
2649
            llunit_ty = type_of(cx.fcx.lcx.ccx, elt_ty);
2650 2651
        }

2652
        auto bcx = cx;
2653

2654
        auto len = bcx.build.Load(lenptr);
2655
        if (trailing_null) {
2656 2657
            auto unit_sz = size_of(bcx, elt_ty);
            bcx = unit_sz.bcx;
2658
            len = bcx.build.Sub(len, unit_sz.val);
2659 2660
        }

2661 2662
        auto p1 = vi2p(bcx, bcx.build.Add(vp2i(bcx, p0), len),
                       T_ptr(llunit_ty));
2663

2664
        ret iter_sequence_inner(bcx, p0, p1, elt_ty, f);
2665 2666
    }

2667
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
2668 2669
        case (ty.ty_vec(?elt)) {
            ret iter_sequence_body(cx, v, elt.ty, f, false);
2670
        }
2671
        case (ty.ty_str) {
2672
            auto et = ty.mk_mach(cx.fcx.lcx.ccx.tcx, common.ty_u8);
2673
            ret iter_sequence_body(cx, v, et, f, true);
2674
        }
2675
        case (_) { fail; }
2676
    }
2677
    cx.fcx.lcx.ccx.sess.bug("bad type in trans.iter_sequence");
2678 2679 2680
    fail;
}

2681 2682 2683 2684 2685 2686 2687 2688 2689
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);
2690

2691 2692 2693 2694 2695
    cx.build.FastCall(llfn, vec(C_null(T_ptr(T_nil())),
                                cx.fcx.lltaskptr,
                                C_null(T_ptr(T_nil())),
                                lltydescs,
                                llrawptr));
2696 2697
}

2698 2699
fn call_tydesc_glue(@block_ctxt cx, ValueRef v,
                    ty.t t, int field) -> result {
2700
    auto td = get_tydesc(cx, t);
2701 2702 2703
    call_tydesc_glue_full(td.bcx,
                          spill_if_immediate(td.bcx, v, t),
                          td.val, field);
2704
    ret res(td.bcx, C_nil());
2705 2706
}

2707
fn call_cmp_glue(@block_ctxt cx, ValueRef lhs, ValueRef rhs, ty.t t,
2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742
                 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()));

    auto r = get_tydesc(cx, t);
    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));
}

2743
fn take_ty(@block_ctxt cx, ValueRef v, ty.t t) -> result {
2744
    if (!ty.type_is_scalar(cx.fcx.lcx.ccx.tcx, t)) {
2745
        ret call_tydesc_glue(cx, v, t, abi.tydesc_field_take_glue);
2746
    }
2747
    ret res(cx, C_nil());
2748 2749
}

2750 2751
fn drop_slot(@block_ctxt cx,
             ValueRef slot,
2752
             ty.t t) -> result {
2753
    auto llptr = load_if_immediate(cx, slot, t);
2754 2755 2756 2757 2758 2759
    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;
2760 2761
}

2762 2763
fn drop_ty(@block_ctxt cx,
           ValueRef v,
2764
           ty.t t) -> result {
2765

2766
    if (!ty.type_is_scalar(cx.fcx.lcx.ccx.tcx, t)) {
2767
        ret call_tydesc_glue(cx, v, t, abi.tydesc_field_drop_glue);
2768
    }
2769
    ret res(cx, C_nil());
2770 2771
}

2772 2773 2774 2775
fn call_memcpy(@block_ctxt cx,
               ValueRef dst,
               ValueRef src,
               ValueRef n_bytes) -> result {
2776 2777
    auto src_ptr = cx.build.PointerCast(src, T_ptr(T_i8()));
    auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
2778
    auto size = cx.build.IntCast(n_bytes, T_int());
2779
    ret res(cx, cx.build.FastCall(cx.fcx.lcx.ccx.glues.memcpy_glue,
2780
                                  vec(dst_ptr, src_ptr, size)));
2781 2782
}

2783 2784 2785 2786 2787
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());
2788
    ret res(cx, cx.build.FastCall(cx.fcx.lcx.ccx.glues.bzero_glue,
2789 2790 2791
                                  vec(dst_ptr, size)));
}

2792 2793 2794
fn memcpy_ty(@block_ctxt cx,
             ValueRef dst,
             ValueRef src,
2795
             ty.t t) -> result {
2796
    if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
2797
        auto llszptr = field_of_tydesc(cx, t, abi.tydesc_field_size);
2798 2799
        auto llsz = llszptr.bcx.build.Load(llszptr.val);
        ret call_memcpy(llszptr.bcx, dst, src, llsz);
2800 2801 2802 2803 2804 2805

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

2806 2807 2808 2809 2810
tag copy_action {
    INIT;
    DROP_EXISTING;
}

2811
fn copy_ty(@block_ctxt cx,
2812
           copy_action action,
2813 2814
           ValueRef dst,
           ValueRef src,
2815
           ty.t t) -> result {
2816 2817
    if (ty.type_is_scalar(cx.fcx.lcx.ccx.tcx, t) ||
            ty.type_is_native(cx.fcx.lcx.ccx.tcx, t)) {
2818 2819
        ret res(cx, cx.build.Store(src, dst));

2820
    } else if (ty.type_is_nil(cx.fcx.lcx.ccx.tcx, t)) {
2821 2822
        ret res(cx, C_nil());

2823
    } else if (ty.type_is_boxed(cx.fcx.lcx.ccx.tcx, t)) {
2824
        auto r = take_ty(cx, src, t);
2825
        if (action == DROP_EXISTING) {
2826
            r = drop_ty(r.bcx, r.bcx.build.Load(dst), t);
2827 2828 2829
        }
        ret res(r.bcx, r.bcx.build.Store(src, dst));

2830 2831
    } else if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, t) ||
               ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
2832
        auto r = take_ty(cx, src, t);
2833
        if (action == DROP_EXISTING) {
2834 2835
            r = drop_ty(r.bcx, dst, t);
        }
2836
        ret memcpy_ty(r.bcx, dst, src, t);
2837 2838
    }

2839
    cx.fcx.lcx.ccx.sess.bug("unexpected type in trans.copy_ty: " +
2840
                        ty.ty_to_str(cx.fcx.lcx.ccx.tcx, t));
2841 2842 2843
    fail;
}

2844
fn trans_lit(@crate_ctxt cx, &ast.lit lit, &ast.ann ann) -> ValueRef {
2845
    alt (lit.node) {
2846
        case (ast.lit_int(?i)) {
2847
            ret C_int(i);
2848 2849
        }
        case (ast.lit_uint(?u)) {
2850
            ret C_int(u as int);
2851
        }
2852 2853 2854 2855 2856 2857
        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 已提交
2858 2859 2860 2861 2862 2863 2864 2865 2866
                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(); }
2867
            }
2868
            ret C_integral(i, t);
2869
        }
2870 2871 2872
        case(ast.lit_float(?fs)) {
            ret C_float(fs);
        }
2873 2874 2875 2876 2877 2878 2879 2880
        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);
        }
2881
        case (ast.lit_char(?c)) {
2882
            ret C_integral(c as int, T_char());
2883 2884
        }
        case (ast.lit_bool(?b)) {
2885
            ret C_bool(b);
2886 2887
        }
        case (ast.lit_nil) {
2888
            ret C_nil();
2889 2890
        }
        case (ast.lit_str(?s)) {
2891
            ret C_str(cx, s);
2892 2893 2894 2895
        }
    }
}

2896
fn target_type(@crate_ctxt cx, ty.t t) -> ty.t {
2897
    alt (ty.struct(cx.tcx, t)) {
2898
        case (ty.ty_int) {
2899
            auto struct_ty = ty.mk_mach(cx.tcx,
2900
                                        cx.sess.get_targ_cfg().int_type);
2901
            ret ty.copy_cname(cx.tcx, struct_ty, t);
2902
        }
2903
        case (ty.ty_uint) {
2904
            auto struct_ty = ty.mk_mach(cx.tcx,
2905
                                        cx.sess.get_targ_cfg().uint_type);
2906
            ret ty.copy_cname(cx.tcx, struct_ty, t);
2907
        }
2908
        case (_) { /* fall through */ }
2909 2910 2911 2912
    }
    ret t;
}

2913 2914

// Converts an annotation to a type
2915
fn node_ann_type(@crate_ctxt cx, &ast.ann a) -> ty.t {
2916
    ret target_type(cx, ty.ann_to_monotype(cx.tcx, a));
2917 2918
}

2919
fn node_ann_ty_params(&ast.ann a) -> vec[ty.t] {
2920 2921
    alt (a) {
        case (ast.ann_none) {
2922
            log_err "missing type annotation";
2923 2924
            fail;
        }
2925
        case (ast.ann_type(_, ?tps_opt, _)) {
2926
            alt (tps_opt) {
2927
                case (none[vec[ty.t]]) {
2928
                    log_err "type annotation has no ty params";
2929 2930
                    fail;
                }
2931
                case (some[vec[ty.t]](?tps)) { ret tps; }
2932 2933 2934 2935 2936
            }
        }
    }
}

2937 2938 2939 2940
fn node_type(@crate_ctxt cx, &ast.ann a) -> TypeRef {
    ret type_of(cx, node_ann_type(cx, a));
}

2941 2942
fn trans_unary(@block_ctxt cx, ast.unop op,
               @ast.expr e, &ast.ann a) -> result {
2943 2944

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

2947 2948
    alt (op) {
        case (ast.bitnot) {
2949
            sub = autoderef(sub.bcx, sub.val,
2950
                            ty.expr_ty(cx.fcx.lcx.ccx.tcx, e));
2951
            ret res(sub.bcx, sub.bcx.build.Not(sub.val));
2952 2953
        }
        case (ast.not) {
2954
            sub = autoderef(sub.bcx, sub.val,
2955
                            ty.expr_ty(cx.fcx.lcx.ccx.tcx, e));
2956
            ret res(sub.bcx, sub.bcx.build.Not(sub.val));
2957 2958
        }
        case (ast.neg) {
2959
            sub = autoderef(sub.bcx, sub.val,
2960 2961
                            ty.expr_ty(cx.fcx.lcx.ccx.tcx, e));
            if(ty.struct(cx.fcx.lcx.ccx.tcx, e_ty) == ty.ty_float) {
2962 2963 2964 2965 2966
                ret res(sub.bcx, sub.bcx.build.FNeg(sub.val));
            }
            else {
                ret res(sub.bcx, sub.bcx.build.Neg(sub.val));
            }
2967
        }
2968
        case (ast.box(_)) {
2969
            auto e_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, e);
2970
            auto e_val = sub.val;
2971
            auto box_ty = node_ann_type(sub.bcx.fcx.lcx.ccx, a);
2972 2973
            sub = trans_malloc_boxed(sub.bcx, e_ty);
            find_scope_cx(cx).cleanups +=
2974
                vec(clean(bind drop_ty(_, sub.val, box_ty)));
2975

2976 2977
            auto box = sub.val;
            auto rc = sub.bcx.build.GEP(box,
2978 2979
                                        vec(C_int(0),
                                            C_int(abi.box_rc_field_refcnt)));
2980 2981 2982 2983
            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);
2984 2985 2986 2987

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

2993
            sub = copy_ty(sub.bcx, INIT, body, e_val, e_ty);
2994
            ret res(sub.bcx, box);
2995
        }
2996
        case (ast.deref) {
2997
            log_err "deref expressions should have been translated using " +
2998 2999
                "trans_lval(), not trans_unary()";
            fail;
3000
        }
3001 3002 3003 3004
    }
    fail;
}

3005
fn trans_compare(@block_ctxt cx0, ast.binop op, ty.t t0,
3006
                 ValueRef lhs0, ValueRef rhs0) -> result {
3007
    // Autoderef both sides.
3008 3009 3010 3011 3012 3013 3014 3015 3016 3017
    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;

3018
    auto t = autoderefed_ty(cx.fcx.lcx.ccx, t0);
3019

3020 3021 3022
    // Determine the operation we need.
    // FIXME: Use or-patterns when we have them.
    auto llop;
3023
    alt (op) {
3024 3025 3026 3027 3028 3029
        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); }
3030 3031
    }

3032
    auto rslt = call_cmp_glue(cx, lhs, rhs, t, llop);
3033

3034 3035
    // Invert the result if necessary.
    // FIXME: Use or-patterns when we have them.
3036
    alt (op) {
3037 3038 3039 3040 3041 3042
        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)); }
3043 3044 3045
    }
}

3046
fn trans_vec_append(@block_ctxt cx, ty.t t,
3047 3048
                    ValueRef lhs, ValueRef rhs) -> result {

3049
    auto elt_ty = ty.sequence_element_type(cx.fcx.lcx.ccx.tcx, t);
3050 3051

    auto skip_null = C_bool(false);
3052
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064
        case (ty.ty_str) { skip_null = C_bool(true); }
        case (_) { }
    }

    auto bcx = cx;

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

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

3065 3066 3067
    auto dst = bcx.build.PointerCast(lhs, T_ptr(T_opaque_vec_ptr()));
    auto src = bcx.build.PointerCast(rhs, T_opaque_vec_ptr());

3068
    ret res(bcx, bcx.build.FastCall(cx.fcx.lcx.ccx.glues.vec_append_glue,
3069 3070 3071 3072
                                    vec(cx.fcx.lltaskptr,
                                        llvec_tydesc.val,
                                        llelt_tydesc.val,
                                        dst, src, skip_null)));
3073 3074
}

3075
fn trans_vec_add(@block_ctxt cx, ty.t t,
3076
                 ValueRef lhs, ValueRef rhs) -> result {
3077
    auto r = alloc_ty(cx, t);
3078 3079
    auto tmp = r.val;
    r = copy_ty(r.bcx, INIT, tmp, lhs, t);
3080
    auto bcx = trans_vec_append(r.bcx, t, tmp, rhs).bcx;
3081
    tmp = load_if_immediate(bcx, tmp, t);
3082 3083
    find_scope_cx(cx).cleanups +=
        vec(clean(bind drop_ty(_, tmp, t)));
3084
    ret res(bcx, tmp);
3085 3086 3087
}


3088
fn trans_eager_binop(@block_ctxt cx, ast.binop op, ty.t intype,
3089
                     ValueRef lhs, ValueRef rhs) -> result {
3090

3091
    auto is_float = false;
3092
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, intype)) {
3093 3094 3095 3096 3097 3098 3099
        case (ty.ty_float) {
            is_float = true;
        }
        case (_) {
            is_float = false;
        }
    }
3100

3101
    alt (op) {
3102
        case (ast.add) {
3103
            if (ty.type_is_sequence(cx.fcx.lcx.ccx.tcx, intype)) {
3104
                ret trans_vec_add(cx, intype, lhs, rhs);
3105
            }
3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121
            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));
            }
        }

3122
        case (ast.mul) {
3123 3124 3125 3126 3127 3128
            if (is_float) {
                ret res(cx, cx.build.FMul(lhs, rhs));
            }
            else {
                ret res(cx, cx.build.Mul(lhs, rhs));
            }
3129
        }
3130

3131
        case (ast.div) {
3132 3133 3134
            if (is_float) {
                ret res(cx, cx.build.FDiv(lhs, rhs));
            }
3135
            if (ty.type_is_signed(cx.fcx.lcx.ccx.tcx, intype)) {
3136
                ret res(cx, cx.build.SDiv(lhs, rhs));
3137
            } else {
3138
                ret res(cx, cx.build.UDiv(lhs, rhs));
3139 3140 3141
            }
        }
        case (ast.rem) {
3142 3143 3144
            if (is_float) {
                ret res(cx, cx.build.FRem(lhs, rhs));
            }
3145
            if (ty.type_is_signed(cx.fcx.lcx.ccx.tcx, intype)) {
3146
                ret res(cx, cx.build.SRem(lhs, rhs));
3147
            } else {
3148
                ret res(cx, cx.build.URem(lhs, rhs));
3149 3150
            }
        }
3151

3152 3153 3154 3155 3156 3157
        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)); }
3158
        case (_) {
3159
            ret trans_compare(cx, op, intype, lhs, rhs);
3160 3161 3162 3163 3164
        }
    }
    fail;
}

3165
fn autoderef(@block_ctxt cx, ValueRef v, ty.t t) -> result {
3166
    let ValueRef v1 = v;
3167
    let ty.t t1 = t;
3168 3169

    while (true) {
3170
        alt (ty.struct(cx.fcx.lcx.ccx.tcx, t1)) {
3171
            case (ty.ty_box(?mt)) {
3172 3173 3174
                auto body = cx.build.GEP(v1,
                                         vec(C_int(0),
                                             C_int(abi.box_rc_field_body)));
3175
                t1 = mt.ty;
3176 3177 3178 3179 3180

                // 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.
3181
                if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, mt.ty)) {
3182
                    auto llty = type_of(cx.fcx.lcx.ccx, mt.ty);
3183 3184 3185 3186 3187
                    v1 = cx.build.PointerCast(body, T_ptr(llty));
                } else {
                    v1 = body;
                }

3188
                v1 = load_if_immediate(cx, v1, t1);
3189 3190 3191 3192 3193 3194 3195 3196
            }
            case (_) {
                ret res(cx, v1);
            }
        }
    }
}

3197
fn autoderefed_ty(@crate_ctxt ccx, ty.t t) -> ty.t {
3198
    let ty.t t1 = t;
3199 3200

    while (true) {
3201
        alt (ty.struct(ccx.tcx, t1)) {
3202 3203
            case (ty.ty_box(?mt)) {
                t1 = mt.ty;
3204 3205 3206 3207 3208 3209 3210 3211
            }
            case (_) {
                ret t1;
            }
        }
    }
}

3212 3213
fn trans_binary(@block_ctxt cx, ast.binop op,
                @ast.expr a, @ast.expr b) -> result {
3214

3215 3216 3217 3218 3219 3220
    // First couple cases are lazy:

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

3224
            auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
3225
            auto rhs_res = trans_expr(rhs_cx, b);
3226
            rhs_res = autoderef(rhs_res.bcx, rhs_res.val,
3227
                                ty.expr_ty(cx.fcx.lcx.ccx.tcx, b));
3228

3229
            auto lhs_false_cx = new_scope_block_ctxt(cx, "lhs false");
3230
            auto lhs_false_res = res(lhs_false_cx, C_bool(false));
3231 3232 3233

            lhs_res.bcx.build.CondBr(lhs_res.val,
                                     rhs_cx.llbb,
3234 3235 3236 3237
                                     lhs_false_cx.llbb);

            ret join_results(cx, T_bool(),
                             vec(lhs_false_res, rhs_res));
3238 3239 3240 3241 3242
        }

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

3246
            auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
3247
            auto rhs_res = trans_expr(rhs_cx, b);
3248
            rhs_res = autoderef(rhs_res.bcx, rhs_res.val,
3249
                                ty.expr_ty(cx.fcx.lcx.ccx.tcx, b));
3250

3251
            auto lhs_true_cx = new_scope_block_ctxt(cx, "lhs true");
3252
            auto lhs_true_res = res(lhs_true_cx, C_bool(true));
3253 3254

            lhs_res.bcx.build.CondBr(lhs_res.val,
3255
                                     lhs_true_cx.llbb,
3256
                                     rhs_cx.llbb);
3257 3258 3259

            ret join_results(cx, T_bool(),
                             vec(lhs_true_res, rhs_res));
3260
        }
3261 3262

        case (_) {
3263 3264
            // Remaining cases are eager:
            auto lhs = trans_expr(cx, a);
3265
            auto lhty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, a);
3266
            lhs = autoderef(lhs.bcx, lhs.val, lhty);
3267
            auto rhs = trans_expr(lhs.bcx, b);
3268
            auto rhty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, b);
3269
            rhs = autoderef(rhs.bcx, rhs.val, rhty);
3270
            ret trans_eager_binop(rhs.bcx, op,
3271
                autoderefed_ty(cx.fcx.lcx.ccx, lhty), lhs.val, rhs.val);
3272
        }
3273 3274 3275 3276
    }
    fail;
}

3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287
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)) {
3288 3289 3290
            live += vec(r);
            vals += vec(r.val);
            bbs += vec(r.bcx.llbb);
3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302
        }
    }

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

3303
        case (_) { /* fall through */ }
3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314
    }

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

3315
fn trans_if(@block_ctxt cx, @ast.expr cond,
3316
            &ast.block thn, &option.t[@ast.expr] els) -> result {
3317 3318 3319

    auto cond_res = trans_expr(cx, cond);

3320
    auto then_cx = new_scope_block_ctxt(cx, "then");
3321 3322
    auto then_res = trans_block(then_cx, thn);

3323
    auto else_cx = new_scope_block_ctxt(cx, "else");
3324

3325 3326
    auto else_res;
    auto expr_llty;
3327
    alt (els) {
3328
        case (some[@ast.expr](?elexpr)) {
3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340
            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);
                }
            }
3341 3342 3343

            // If we have an else expression, then the entire
            // if expression can have a non-nil type.
3344
            // FIXME: This isn't quite right, particularly re: dynamic types
3345 3346
            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)) {
3347
                expr_llty = T_typaram_ptr(cx.fcx.lcx.ccx.tn);
3348
            } else {
3349
                expr_llty = type_of(else_res.bcx.fcx.lcx.ccx, expr_ty);
3350
                if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, expr_ty)) {
3351 3352
                    expr_llty = T_ptr(expr_llty);
                }
3353
            }
3354 3355 3356 3357
        }
        case (_) {
            else_res = res(else_cx, C_nil());
            expr_llty = T_nil();
3358 3359 3360
        }
    }

3361
    cond_res.bcx.build.CondBr(cond_res.val,
3362 3363
                              then_cx.llbb,
                              else_cx.llbb);
3364

3365
    ret join_results(cx, expr_llty,
3366
                     vec(then_res, else_res));
3367 3368
}

G
Graydon Hoare 已提交
3369 3370 3371 3372 3373 3374
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,
3375
             ty.t t, ast.block body,
3376
             @block_ctxt outer_next_cx) -> result {
G
Graydon Hoare 已提交
3377 3378

        auto next_cx = new_sub_block_ctxt(cx, "next");
3379 3380 3381
        auto scope_cx =
            new_loop_scope_block_ctxt(cx, option.some[@block_ctxt](next_cx),
                                      outer_next_cx, "for loop scope");
G
Graydon Hoare 已提交
3382 3383 3384

        cx.build.Br(scope_cx.llbb);
        auto local_res = alloc_local(scope_cx, local);
3385
        auto bcx = copy_ty(local_res.bcx, INIT, local_res.val, curr, t).bcx;
3386 3387
        scope_cx.cleanups +=
            vec(clean(bind drop_slot(_, local_res.val, t)));
3388
        bcx = trans_block(bcx, body).bcx;
G
Graydon Hoare 已提交
3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400
        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;
        }
    }

3401
    auto next_cx = new_sub_block_ctxt(cx, "next");
3402
    auto seq_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, seq);
G
Graydon Hoare 已提交
3403
    auto seq_res = trans_expr(cx, seq);
3404 3405 3406 3407
    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 已提交
3408 3409
}

3410 3411 3412 3413 3414 3415

// 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)
3416
        -> vec[ast.def_id] {
3417
    type env = @rec(
3418 3419 3420
        mutable vec[ast.def_id] refs,
        hashmap[ast.def_id,()] decls
    );
3421

M
Marijn Haverbeke 已提交
3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438
    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 (_) {}
3439 3440 3441
        }
    }

M
Marijn Haverbeke 已提交
3442 3443 3444 3445 3446 3447 3448
    fn walk_decl(env e, @ast.decl decl) {
        alt (decl.node) {
            case (ast.decl_local(?local)) {
                e.decls.insert(local.id, ());
            }
            case (_) {}
        }
3449 3450 3451 3452 3453 3454 3455
    }

    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 已提交
3456 3457 3458 3459
    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);
3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471

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

3472 3473 3474 3475
fn trans_for_each(@block_ctxt cx,
                  @ast.decl decl,
                  @ast.expr seq,
                  &ast.block body) -> result {
3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501
    /*
     * 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.

3502
    auto lcx = cx.fcx.lcx;
3503
    // FIXME: possibly support alias-mode here?
3504
    auto decl_ty = ty.mk_nil(lcx.ccx.tcx);
3505
    auto decl_id;
3506 3507
    alt (decl.node) {
        case (ast.decl_local(?local)) {
3508
            decl_ty = node_ann_type(lcx.ccx, local.ann);
3509
            decl_id = local.id;
3510 3511 3512
        }
    }

3513
    auto upvars = collect_upvars(cx, body, decl_id);
3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524
    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]) {
3525 3526 3527 3528 3529 3530
                    alt (cx.fcx.llupvars.find(did)) {
                        case (none[ValueRef]) {
                            llbinding = cx.fcx.llargs.get(did);
                        }
                        case (some[ValueRef](?llval)) { llbinding = llval; }
                    }
3531 3532 3533 3534 3535 3536 3537 3538
                }
                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.
3539
        llbindingsptr = alloca(cx, T_struct(llbindingtys));
3540 3541 3542 3543 3544 3545 3546 3547 3548 3549
        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()));
3550 3551
    }

3552
    // Create an environment and populate it with the bindings.
3553
    auto tydesc_count = _vec.len[ValueRef](cx.fcx.lltydescs);
3554
    auto llenvptrty = T_closure_ptr(lcx.ccx.tn, T_ptr(T_nil()),
3555
                                    val_ty(llbindingsptr), tydesc_count);
3556
    auto llenvptr = alloca(cx, llvm.LLVMGetElementType(llenvptrty));
3557 3558 3559 3560 3561 3562

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

3564 3565 3566 3567 3568
    // 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),
3569
                                         C_int(abi.closure_elt_ty_params)));
3570 3571 3572 3573 3574 3575 3576 3577
    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;
    }

3578 3579
    // Step 2: Declare foreach body function.

3580
    let str s = mangle_name_by_seq(lcx.ccx, lcx.path, "foreach");
3581 3582 3583 3584 3585 3586 3587

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

3588 3589 3590 3591
    auto iter_body_llty =
        type_of_fn_full(lcx.ccx, ast.proto_fn,
                        none[TypeRef],
                        vec(rec(mode=ast.alias, ty=decl_ty)),
3592
                        ty.mk_nil(lcx.ccx.tcx), 0u);
3593

3594
    let ValueRef lliterbody = decl_internal_fastcall_fn(lcx.ccx.llmod,
3595
                                                       s, iter_body_llty);
3596

3597
    auto fcx = new_fn_ctxt(lcx, lliterbody);
3598
    auto bcx = new_top_block_ctxt(fcx);
3599
    auto lltop = bcx.llbb;
3600

3601 3602
    // Populate the upvars from the environment.
    auto llremoteenvptr = bcx.build.PointerCast(fcx.llenv, llenvptrty);
3603 3604 3605 3606
    auto llremotebindingsptrptr =
        bcx.build.GEP(llremoteenvptr, vec(C_int(0),
                                          C_int(abi.box_rc_field_body),
                                          C_int(abi.closure_elt_bindings)));
3607 3608
    auto llremotebindingsptr = bcx.build.Load(llremotebindingsptrptr);

3609
    i = 0u;
3610 3611 3612 3613 3614 3615 3616 3617 3618 3619
    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;
    }

3620
    // Populate the type parameters from the environment.
3621 3622 3623 3624 3625
    auto llremotetydescsptr =
        bcx.build.GEP(llremoteenvptr,
                      vec(C_int(0),
                          C_int(abi.box_rc_field_body),
                          C_int(abi.closure_elt_ty_params)));
3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636

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

3637 3638
    // Add an upvar for the loop variable alias.
    fcx.llupvars.insert(decl_id, llvm.LLVMGetParam(fcx.llfn, 3u));
3639

3640
    auto r = trans_block(bcx, body);
3641 3642 3643 3644

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

3645
    r.bcx.build.RetVoid();
3646 3647


3648
    // Step 3: Call iter passing [lliterbody, llenv], plus other args.
3649 3650

    alt (seq.node) {
3651

3652
        case (ast.expr_call(?f, ?args, ?ann)) {
3653

3654
            auto pair = alloca(cx, T_fn_pair(lcx.ccx.tn,
3655
                                             iter_body_llty));
3656 3657 3658 3659 3660
            auto code_cell = cx.build.GEP(pair,
                                          vec(C_int(0),
                                              C_int(abi.fn_field_code)));
            cx.build.Store(lliterbody, code_cell);

3661 3662 3663
            auto env_cell = cx.build.GEP(pair, vec(C_int(0),
                                                   C_int(abi.fn_field_box)));
            auto llenvblobptr = cx.build.PointerCast(llenvptr,
3664
                T_opaque_closure_ptr(lcx.ccx.tn));
3665 3666
            cx.build.Store(llenvblobptr, env_cell);

3667
            // log "lliterbody: " + val_str(lcx.ccx.tn, lliterbody);
3668
            r = trans_call(cx, f,
3669
                           some[ValueRef](cx.build.Load(pair)),
3670 3671
                           args,
                           ann);
3672
            ret res(r.bcx, C_nil());
3673 3674
        }
    }
3675 3676 3677 3678
    fail;
}


3679 3680
fn trans_while(@block_ctxt cx, @ast.expr cond,
               &ast.block body) -> result {
3681

3682
    auto cond_cx = new_scope_block_ctxt(cx, "while cond");
3683
    auto next_cx = new_sub_block_ctxt(cx, "next");
3684 3685
    auto body_cx = new_loop_scope_block_ctxt(cx, option.none[@block_ctxt],
                                             next_cx, "while loop body");
3686 3687

    auto body_res = trans_block(body_cx, body);
3688 3689 3690
    auto cond_res = trans_expr(cond_cx, cond);

    body_res.bcx.build.Br(cond_cx.llbb);
3691 3692 3693

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

    cx.build.Br(cond_cx.llbb);
3696 3697 3698
    ret res(next_cx, C_nil());
}

3699 3700
fn trans_do_while(@block_ctxt cx, &ast.block body,
                  @ast.expr cond) -> result {
3701

3702
    auto next_cx = new_sub_block_ctxt(cx, "next");
3703 3704
    auto body_cx = new_loop_scope_block_ctxt(cx, option.none[@block_ctxt],
                                             next_cx, "do-while loop body");
3705 3706

    auto body_res = trans_block(body_cx, body);
3707 3708 3709 3710 3711 3712
    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);
3713 3714 3715
    ret res(next_cx, body_res.val);
}

P
Patrick Walton 已提交
3716 3717
// Pattern matching translation

3718 3719
fn trans_pat_match(@block_ctxt cx, @ast.pat pat, ValueRef llval,
                   @block_ctxt next_cx) -> result {
P
Patrick Walton 已提交
3720 3721 3722
    alt (pat.node) {
        case (ast.pat_wild(_)) { ret res(cx, llval); }
        case (ast.pat_bind(_, _, _)) { ret res(cx, llval); }
3723 3724

        case (ast.pat_lit(?lt, ?ann)) {
3725
            auto lllit = trans_lit(cx.fcx.lcx.ccx, *lt, ann);
3726 3727
            auto lltype = ty.ann_to_type(ann);
            auto lleq = trans_compare(cx, ast.eq, lltype, llval, lllit);
3728

3729 3730
            auto matched_cx = new_sub_block_ctxt(lleq.bcx, "matched_cx");
            lleq.bcx.build.CondBr(lleq.val, matched_cx.llbb, next_cx.llbb);
3731 3732 3733
            ret res(matched_cx, llval);
        }

P
Patrick Walton 已提交
3734
        case (ast.pat_tag(?id, ?subpats, ?vdef_opt, ?ann)) {
3735
            auto lltagptr = cx.build.PointerCast(llval,
3736
                T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn));
3737 3738 3739

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

P
Patrick Walton 已提交
3742 3743 3744
            auto vdef = option.get[ast.variant_def](vdef_opt);
            auto variant_id = vdef._1;
            auto variant_tag = 0;
3745

3746
            auto variants = tag_variants(cx.fcx.lcx.ccx, vdef._0);
P
Patrick Walton 已提交
3747
            auto i = 0;
3748 3749
            for (variant_info v in variants) {
                auto this_variant_id = v.id;
P
Patrick Walton 已提交
3750
                if (variant_id._0 == this_variant_id._0 &&
G
Graydon Hoare 已提交
3751
                    variant_id._1 == this_variant_id._1) {
P
Patrick Walton 已提交
3752 3753 3754 3755 3756 3757 3758
                    variant_tag = i;
                }
                i += 1;
            }

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

3759
            auto lleq = cx.build.ICmp(lib.llvm.LLVMIntEQ, lldiscrim,
P
Patrick Walton 已提交
3760 3761 3762
                                      C_int(variant_tag));
            cx.build.CondBr(lleq, matched_cx.llbb, next_cx.llbb);

3763 3764
            auto ty_params = node_ann_ty_params(ann);

P
Patrick Walton 已提交
3765
            if (_vec.len[@ast.pat](subpats) > 0u) {
3766
                auto llblobptr = matched_cx.build.GEP(lltagptr,
3767
                    vec(C_int(0), C_int(1)));
P
Patrick Walton 已提交
3768 3769
                auto i = 0;
                for (@ast.pat subpat in subpats) {
3770 3771
                    auto rslt = GEP_tag(matched_cx, llblobptr, vdef._0,
                                        vdef._1, ty_params, i);
3772 3773 3774
                    auto llsubvalptr = rslt.val;
                    matched_cx = rslt.bcx;

3775
                    auto llsubval = load_if_immediate(matched_cx,
3776
                        llsubvalptr, pat_ty(cx.fcx.lcx.ccx.tcx, subpat));
P
Patrick Walton 已提交
3777 3778 3779
                    auto subpat_res = trans_pat_match(matched_cx, subpat,
                                                      llsubval, next_cx);
                    matched_cx = subpat_res.bcx;
3780 3781

                    i += 1;
P
Patrick Walton 已提交
3782 3783 3784 3785 3786 3787 3788 3789 3790 3791
                }
            }

            ret res(matched_cx, llval);
        }
    }

    fail;
}

3792 3793
fn trans_pat_binding(@block_ctxt cx, @ast.pat pat,
                     ValueRef llval, bool bind_alias)
3794
    -> result {
P
Patrick Walton 已提交
3795 3796
    alt (pat.node) {
        case (ast.pat_wild(_)) { ret res(cx, llval); }
3797
        case (ast.pat_lit(_, _)) { ret res(cx, llval); }
P
Patrick Walton 已提交
3798
        case (ast.pat_bind(?id, ?def_id, ?ann)) {
3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812
            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 已提交
3813
        }
3814
        case (ast.pat_tag(_, ?subpats, ?vdef_opt, ?ann)) {
P
Patrick Walton 已提交
3815 3816
            if (_vec.len[@ast.pat](subpats) == 0u) { ret res(cx, llval); }

3817 3818 3819 3820
            // Get the appropriate variant for this tag.
            auto vdef = option.get[ast.variant_def](vdef_opt);

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

3824 3825
            auto ty_param_substs = node_ann_ty_params(ann);

P
Patrick Walton 已提交
3826 3827 3828
            auto this_cx = cx;
            auto i = 0;
            for (@ast.pat subpat in subpats) {
3829 3830
                auto rslt = GEP_tag(this_cx, llblobptr, vdef._0, vdef._1,
                                    ty_param_substs, i);
3831
                this_cx = rslt.bcx;
P
Patrick Walton 已提交
3832
                auto subpat_res = trans_pat_binding(this_cx, subpat,
3833
                                                    rslt.val, true);
P
Patrick Walton 已提交
3834
                this_cx = subpat_res.bcx;
3835
                i += 1;
P
Patrick Walton 已提交
3836 3837 3838 3839 3840 3841 3842
            }

            ret res(this_cx, llval);
        }
    }
}

3843 3844
fn trans_alt(@block_ctxt cx, @ast.expr expr,
             vec[ast.arm] arms, ast.ann ann) -> result {
P
Patrick Walton 已提交
3845 3846 3847
    auto expr_res = trans_expr(cx, expr);

    auto this_cx = expr_res.bcx;
3848
    let vec[result] arm_results = vec();
P
Patrick Walton 已提交
3849 3850 3851 3852 3853 3854 3855 3856 3857
    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,
3858
                                             expr_res.val, false);
P
Patrick Walton 已提交
3859 3860

        auto block_res = trans_block(binding_res.bcx, arm.block);
3861
        arm_results += vec(block_res);
P
Patrick Walton 已提交
3862 3863 3864 3865

        this_cx = next_cx;
    }

3866
    auto default_cx = this_cx;
3867
    auto default_res = trans_fail(default_cx, some[common.span](expr.span),
3868
                                  "non-exhaustive match failure");
P
Patrick Walton 已提交
3869

3870
    // FIXME: This isn't quite right, particularly re: dynamic types
3871 3872
    auto expr_ty = ty.ann_to_type(ann);
    auto expr_llty;
3873
    if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, expr_ty)) {
3874
        expr_llty = T_typaram_ptr(cx.fcx.lcx.ccx.tn);
3875
    } else {
3876
        expr_llty = type_of(cx.fcx.lcx.ccx, expr_ty);
3877
        if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, expr_ty)) {
3878 3879 3880 3881 3882
            expr_llty = T_ptr(expr_llty);
        }
    }

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

3885
type generic_info = rec(ty.t item_type,
3886 3887
                        vec[ValueRef] tydescs);

3888 3889
type lval_result = rec(result res,
                       bool is_mem,
3890
                       option.t[generic_info] generic,
3891
                       option.t[ValueRef] llobj,
3892
                       option.t[ty.t] method_ty);
3893 3894 3895 3896

fn lval_mem(@block_ctxt cx, ValueRef val) -> lval_result {
    ret rec(res=res(cx, val),
            is_mem=true,
3897
            generic=none[generic_info],
3898
            llobj=none[ValueRef],
3899
            method_ty=none[ty.t]);
3900 3901 3902 3903 3904
}

fn lval_val(@block_ctxt cx, ValueRef val) -> lval_result {
    ret rec(res=res(cx, val),
            is_mem=false,
3905
            generic=none[generic_info],
3906
            llobj=none[ValueRef],
3907
            method_ty=none[ty.t]);
3908
}
3909

3910
fn trans_external_path(@block_ctxt cx, ast.def_id did,
3911
                       ty.ty_param_count_and_ty tpt) -> lval_result {
3912 3913 3914 3915
    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));
3916 3917 3918
    ret lval_val(cx, v);
}

3919
fn lval_generic_fn(@block_ctxt cx,
3920
                   ty.ty_param_count_and_ty tpt,
3921 3922
                   ast.def_id fn_id,
                   &ast.ann ann)
3923
        -> lval_result {
3924
    auto lv;
3925
    if (cx.fcx.lcx.ccx.sess.get_targ_crate_num() == fn_id._0) {
3926
        // Internal reference.
3927 3928
        check (cx.fcx.lcx.ccx.fn_pairs.contains_key(fn_id));
        lv = lval_val(cx, cx.fcx.lcx.ccx.fn_pairs.get(fn_id));
3929 3930
    } else {
        // External reference.
3931
        lv = trans_external_path(cx, fn_id, tpt);
3932
    }
3933 3934

    auto monoty;
3935
    let vec[ty.t] tys;
3936 3937
    alt (ann) {
        case (ast.ann_none) {
3938
            cx.fcx.lcx.ccx.sess.bug("no type annotation for path!");
3939 3940
            fail;
        }
3941
        case (ast.ann_type(?monoty_, ?tps, _)) {
3942
            monoty = monoty_;
3943
            tys = option.get[vec[ty.t]](tps);
3944 3945
        }
    }
3946

3947
    if (_vec.len[ty.t](tys) != 0u) {
3948
        auto bcx = lv.res.bcx;
3949
        let vec[ValueRef] tydescs = vec();
3950
        for (ty.t t in tys) {
3951 3952
            auto td = get_tydesc(bcx, t);
            bcx = td.bcx;
3953
            _vec.push[ValueRef](tydescs, td.val);
3954 3955 3956 3957 3958 3959 3960 3961 3962 3963
        }
        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;
}

3964
fn lookup_discriminant(@local_ctxt lcx, ast.def_id tid, ast.def_id vid)
3965
        -> ValueRef {
3966
    alt (lcx.ccx.discrims.find(vid)) {
3967 3968
        case (none[ValueRef]) {
            // It's an external discriminant that we haven't seen yet.
3969 3970 3971 3972
            check (lcx.ccx.sess.get_targ_crate_num() != vid._0);
            auto sym = creader.get_symbol(lcx.ccx.sess, vid);
            auto gvar = llvm.LLVMAddGlobal(lcx.ccx.llmod, T_int(),
                                           _str.buf(sym));
3973 3974 3975
            llvm.LLVMSetLinkage(gvar,
                                lib.llvm.LLVMExternalLinkage as llvm.Linkage);
            llvm.LLVMSetGlobalConstant(gvar, True);
3976
            lcx.ccx.discrims.insert(vid, gvar);
3977 3978 3979 3980 3981 3982
            ret gvar;
        }
        case (some[ValueRef](?llval)) { ret llval; }
    }
}

3983
fn trans_path(@block_ctxt cx, &ast.path p, &option.t[ast.def] dopt,
G
Graydon Hoare 已提交
3984
              &ast.ann ann) -> lval_result {
3985 3986 3987 3988
    alt (dopt) {
        case (some[ast.def](?def)) {
            alt (def) {
                case (ast.def_arg(?did)) {
3989 3990 3991 3992 3993 3994 3995 3996 3997
                    alt (cx.fcx.llargs.find(did)) {
                        case (none[ValueRef]) {
                            check (cx.fcx.llupvars.contains_key(did));
                            ret lval_mem(cx, cx.fcx.llupvars.get(did));
                        }
                        case (some[ValueRef](?llval)) {
                            ret lval_mem(cx, llval);
                        }
                    }
3998 3999
                }
                case (ast.def_local(?did)) {
4000 4001 4002 4003 4004 4005 4006 4007 4008
                    alt (cx.fcx.lllocals.find(did)) {
                        case (none[ValueRef]) {
                            check (cx.fcx.llupvars.contains_key(did));
                            ret lval_mem(cx, cx.fcx.llupvars.get(did));
                        }
                        case (some[ValueRef](?llval)) {
                            ret lval_mem(cx, llval);
                        }
                    }
G
Graydon Hoare 已提交
4009
                }
P
Patrick Walton 已提交
4010 4011
                case (ast.def_binding(?did)) {
                    check (cx.fcx.lllocals.contains_key(did));
4012
                    ret lval_mem(cx, cx.fcx.lllocals.get(did));
P
Patrick Walton 已提交
4013
                }
4014 4015 4016 4017
                case (ast.def_obj_field(?did)) {
                    check (cx.fcx.llobjfields.contains_key(did));
                    ret lval_mem(cx, cx.fcx.llobjfields.get(did));
                }
4018
                case (ast.def_fn(?did)) {
4019
                    auto tyt = ty.lookup_item_type(cx.fcx.lcx.ccx.sess,
4020
                        cx.fcx.lcx.ccx.tcx, cx.fcx.lcx.ccx.type_cache, did);
4021
                    ret lval_generic_fn(cx, tyt, did, ann);
4022
                }
4023
                case (ast.def_obj(?did)) {
4024
                    auto tyt = ty.lookup_item_type(cx.fcx.lcx.ccx.sess,
4025
                        cx.fcx.lcx.ccx.tcx, cx.fcx.lcx.ccx.type_cache, did);
4026
                    ret lval_generic_fn(cx, tyt, did, ann);
4027
                }
4028
                case (ast.def_variant(?tid, ?vid)) {
4029
                    auto v_tyt = ty.lookup_item_type(cx.fcx.lcx.ccx.sess,
4030 4031
                        cx.fcx.lcx.ccx.tcx, cx.fcx.lcx.ccx.type_cache, vid);
                    alt (ty.struct(cx.fcx.lcx.ccx.tcx, v_tyt._1)) {
4032 4033 4034
                        case (ty.ty_fn(_, _, _)) {
                            // N-ary variant.
                            ret lval_generic_fn(cx, v_tyt, vid, ann);
4035
                        }
4036 4037
                        case (_) {
                            // Nullary variant.
4038
                            auto tag_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
4039
                            auto lldiscrim_gv =
4040
                                lookup_discriminant(cx.fcx.lcx, tid, vid);
4041 4042 4043 4044 4045 4046
                            auto lldiscrim = cx.build.Load(lldiscrim_gv);

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

                            auto lltagty;
4047 4048
                            if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx,
                                                         tag_ty)) {
4049
                                lltagty = T_opaque_tag(cx.fcx.lcx.ccx.tn);
4050
                            } else {
4051
                                lltagty = type_of(cx.fcx.lcx.ccx, tag_ty);
4052
                            }
4053 4054
                            auto lltagptr = alloc_result.bcx.build.
                                PointerCast(lltagblob, T_ptr(lltagty));
4055

4056 4057 4058 4059
                            auto lldiscrimptr = alloc_result.bcx.build.GEP(
                                lltagptr, vec(C_int(0), C_int(0)));
                            alloc_result.bcx.build.Store(lldiscrim,
                                                         lldiscrimptr);
4060

4061 4062
                            ret lval_val(alloc_result.bcx, lltagptr);
                        }
4063
                    }
4064
                }
4065
                case (ast.def_const(?did)) {
4066
                    // TODO: externals
4067 4068
                    check (cx.fcx.lcx.ccx.consts.contains_key(did));
                    ret lval_mem(cx, cx.fcx.lcx.ccx.consts.get(did));
4069
                }
4070
                case (ast.def_native_fn(?did)) {
4071
                    auto tyt = ty.lookup_item_type(cx.fcx.lcx.ccx.sess,
4072
                        cx.fcx.lcx.ccx.tcx,
4073
                        cx.fcx.lcx.ccx.type_cache, did);
4074
                    ret lval_generic_fn(cx, tyt, did, ann);
4075
                }
4076
                case (_) {
4077
                    cx.fcx.lcx.ccx.sess.unimpl("def variant in trans");
G
Graydon Hoare 已提交
4078 4079 4080
                }
            }
        }
4081
        case (none[ast.def]) {
4082
            cx.fcx.lcx.ccx.sess.err("unresolved expr_path in trans");
4083 4084 4085 4086 4087
        }
    }
    fail;
}

4088
fn trans_field(@block_ctxt cx, &ast.span sp, ValueRef v, ty.t t0,
4089
               &ast.ident field, &ast.ann ann) -> lval_result {
4090 4091

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

4094
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
4095
        case (ty.ty_tup(_)) {
4096
            let uint ix = ty.field_num(cx.fcx.lcx.ccx.sess, sp, field);
4097
            auto v = GEP_tup_like(r.bcx, t, r.val, vec(0, ix as int));
4098
            ret lval_mem(v.bcx, v.val);
4099
        }
4100
        case (ty.ty_rec(?fields)) {
4101 4102
            let uint ix = ty.field_idx(cx.fcx.lcx.ccx.sess, sp, field,
                                       fields);
4103
            auto v = GEP_tup_like(r.bcx, t, r.val, vec(0, ix as int));
4104
            ret lval_mem(v.bcx, v.val);
4105
        }
4106
        case (ty.ty_obj(?methods)) {
4107 4108
            let uint ix = ty.method_idx(cx.fcx.lcx.ccx.sess, sp, field,
                                        methods);
4109 4110 4111 4112 4113 4114
            auto vtbl = r.bcx.build.GEP(r.val,
                                        vec(C_int(0),
                                            C_int(abi.obj_field_vtbl)));
            vtbl = r.bcx.build.Load(vtbl);
            auto v =  r.bcx.build.GEP(vtbl, vec(C_int(0),
                                                C_int(ix as int)));
4115 4116

            auto lvo = lval_mem(r.bcx, v);
4117
            let ty.t fn_ty = ty.method_ty_to_fn_ty(cx.fcx.lcx.ccx.tcx,
4118
                                                    methods.(ix));
4119
            ret rec(llobj = some[ValueRef](r.val),
4120
                    method_ty = some[ty.t](fn_ty)
4121
                    with lvo);
4122
        }
4123
        case (_) {cx.fcx.lcx.ccx.sess.unimpl("field variant in trans_field");}
4124 4125 4126 4127
    }
    fail;
}

4128 4129
fn trans_index(@block_ctxt cx, &ast.span sp, @ast.expr base,
               @ast.expr idx, &ast.ann ann) -> lval_result {
4130

G
Graydon Hoare 已提交
4131
    auto lv = trans_expr(cx, base);
4132
    lv = autoderef(lv.bcx, lv.val, ty.expr_ty(cx.fcx.lcx.ccx.tcx, base));
G
Graydon Hoare 已提交
4133 4134
    auto ix = trans_expr(lv.bcx, idx);
    auto v = lv.val;
4135
    auto bcx = ix.bcx;
4136

4137 4138
    // Cast to an LLVM integer. Rust is less strict than LLVM in this regard.
    auto ix_val;
4139 4140
    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());
4141 4142 4143 4144 4145 4146 4147 4148
    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;
    }

4149
    auto unit_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
4150
    auto unit_sz = size_of(bcx, unit_ty);
4151
    bcx = unit_sz.bcx;
4152
    llvm.LLVMSetValueName(unit_sz.val, _str.buf("unit_sz"));
4153 4154

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

4157 4158
    auto lim = bcx.build.GEP(v, vec(C_int(0), C_int(abi.vec_elt_fill)));
    lim = bcx.build.Load(lim);
4159

4160 4161
    auto bounds_check = bcx.build.ICmp(lib.llvm.LLVMIntULT,
                                       scaled_ix, lim);
4162

4163 4164 4165
    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);
4166 4167

    // fail: bad bounds check.
4168 4169
    auto fail_res = trans_fail(fail_cx, some[common.span](sp),
                               "bounds check");
4170 4171

    auto body = next_cx.build.GEP(v, vec(C_int(0), C_int(abi.vec_elt_data)));
4172
    auto elt;
4173
    if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, unit_ty)) {
4174 4175 4176 4177
        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));
4178 4179

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

4184
    ret lval_mem(next_cx, elt);
4185 4186
}

4187 4188 4189 4190
// 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).

4191
fn trans_lval(@block_ctxt cx, @ast.expr e) -> lval_result {
4192
    alt (e.node) {
4193 4194
        case (ast.expr_path(?p, ?dopt, ?ann)) {
            ret trans_path(cx, p, dopt, ann);
4195 4196
        }
        case (ast.expr_field(?base, ?ident, ?ann)) {
4197
            auto r = trans_expr(cx, base);
4198
            auto t = ty.expr_ty(cx.fcx.lcx.ccx.tcx, base);
4199
            ret trans_field(r.bcx, e.span, r.val, t, ident, ann);
4200
        }
4201 4202 4203
        case (ast.expr_index(?base, ?idx, ?ann)) {
            ret trans_index(cx, e.span, base, idx, ann);
        }
4204 4205 4206 4207 4208 4209 4210 4211 4212
        case (ast.expr_unary(?unop, ?base, ?ann)) {
            check (unop == ast.deref);

            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);
        }
4213
        case (ast.expr_self_method(?ident, ?ann)) {
4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226
            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;
                }

            }
        }
4227
        case (_) {
4228 4229
            cx.fcx.lcx.ccx.sess.span_unimpl(e.span,
                                            "expr variant in trans_lval");
4230
        }
G
Graydon Hoare 已提交
4231 4232 4233 4234
    }
    fail;
}

4235
fn trans_cast(@block_ctxt cx, @ast.expr e, &ast.ann ann) -> result {
4236 4237
    auto e_res = trans_expr(cx, e);
    auto llsrctype = val_ty(e_res.val);
4238 4239
    auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
    auto lldsttype = type_of(cx.fcx.lcx.ccx, t);
4240
    if (!ty.type_is_fp(cx.fcx.lcx.ccx.tcx, t)) {
4241
        // TODO: native-to-native casts
4242 4243
        if (ty.type_is_native(cx.fcx.lcx.ccx.tcx,
                              ty.expr_ty(cx.fcx.lcx.ccx.tcx, e))) {
4244
            e_res.val = e_res.bcx.build.PtrToInt(e_res.val, lldsttype);
4245
        } else if (ty.type_is_native(cx.fcx.lcx.ccx.tcx, t)) {
4246
            e_res.val = e_res.bcx.build.IntToPtr(e_res.val, lldsttype);
4247
        } else if (llvm.LLVMGetIntTypeWidth(lldsttype) >
4248
            llvm.LLVMGetIntTypeWidth(llsrctype)) {
4249
            if (ty.type_is_signed(cx.fcx.lcx.ccx.tcx, t)) {
4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266
                // 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 {
4267
        cx.fcx.lcx.ccx.sess.unimpl("fp cast");
4268 4269 4270 4271
    }
    ret e_res;
}

4272
fn trans_bind_thunk(@local_ctxt cx,
4273 4274
                    ty.t incoming_fty,
                    ty.t outgoing_fty,
4275
                    vec[option.t[@ast.expr]] args,
4276 4277
                    ty.t closure_ty,
                    vec[ty.t] bound_tys,
4278
                    uint ty_param_count) -> ValueRef {
4279 4280 4281
    // Construct a thunk-call with signature incoming_fty, and that copies
    // args forward into a call to outgoing_fty.

4282
    let str s = mangle_name_by_seq(cx.ccx, cx.path, "thunk");
4283 4284 4285
    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);
4286

4287
    auto fcx = new_fn_ctxt(cx, llthunk);
4288
    auto bcx = new_top_block_ctxt(fcx);
4289
    auto lltop = bcx.llbb;
4290

4291
    auto llclosure_ptr_ty =
4292
        type_of(cx.ccx, ty.mk_imm_box(cx.ccx.tcx, closure_ty));
4293
    auto llclosure = bcx.build.PointerCast(fcx.llenv, llclosure_ptr_ty);
4294

4295 4296 4297 4298 4299 4300
    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,
4301 4302 4303
                                         vec(C_int(0),
                                             C_int(abi.fn_field_box)));
    lltargetclosure = bcx.build.Load(lltargetclosure);
4304

4305 4306
    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);
4307 4308

    auto llretptr = fcx.llretptr;
4309
    if (ty.type_has_dynamic_size(cx.ccx.tcx, outgoing_ret_ty)) {
4310
        llretptr = bcx.build.PointerCast(llretptr, T_typaram_ptr(cx.ccx.tn));
4311 4312 4313
    }

    let vec[ValueRef] llargs = vec(llretptr,
4314
                                   fcx.lltaskptr,
4315
                                   lltargetclosure);
4316 4317 4318 4319 4320

    // Copy in the type parameters.
    let uint i = 0u;
    while (i < ty_param_count) {
        auto lltyparam_ptr =
4321 4322 4323 4324 4325 4326
            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;
4327 4328 4329
        auto td = bcx.build.Load(lltyparam_ptr.val);
        llargs += vec(td);
        fcx.lltydescs += vec(td);
4330 4331 4332
        i += 1u;
    }

4333
    let uint a = 3u;    // retptr, task ptr, env come first
4334
    let int b = 0;
4335
    let uint outgoing_arg_index = 0u;
4336
    let vec[TypeRef] llout_arg_tys =
4337
        type_of_explicit_args(cx.ccx, outgoing_args);
4338

4339
    for (option.t[@ast.expr] arg in args) {
4340 4341 4342 4343

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

4344 4345 4346
        alt (arg) {

            // Arg provided at binding time; thunk copies it from closure.
4347 4348
            case (some[@ast.expr](?e)) {
                auto e_ty = ty.expr_ty(cx.ccx.tcx, e);
4349 4350 4351 4352 4353 4354
                auto bound_arg =
                    GEP_tup_like(bcx, closure_ty, llclosure,
                                 vec(0,
                                     abi.box_rc_field_body,
                                     abi.closure_elt_bindings,
                                     b));
4355

4356
                bcx = bound_arg.bcx;
4357 4358 4359
                auto val = bound_arg.val;

                if (out_arg.mode == ast.val) {
4360 4361 4362 4363 4364 4365 4366
                    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);
                    }
4367 4368
                } else if (ty.type_contains_params(cx.ccx.tcx,
                                                   out_arg.ty)) {
4369 4370 4371 4372
                    check (out_arg.mode == ast.alias);
                    val = bcx.build.PointerCast(val, llout_arg_ty);
                }

4373
                llargs += vec(val);
4374 4375 4376 4377 4378 4379
                b += 1;
            }

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

4381
                if (ty.type_contains_params(cx.ccx.tcx, out_arg.ty)) {
4382
                    check (out_arg.mode == ast.alias);
4383
                    passed_arg = bcx.build.PointerCast(passed_arg,
4384
                                                       llout_arg_ty);
4385
                }
4386

4387
                llargs += vec(passed_arg);
4388 4389 4390
                a += 1u;
            }
        }
4391

4392
        outgoing_arg_index += 1u;
4393 4394 4395
    }

    // FIXME: turn this call + ret into a tail call.
4396
    auto lltargetfn = bcx.build.GEP(lltarget.val,
4397 4398
                                    vec(C_int(0),
                                        C_int(abi.fn_field_code)));
4399 4400 4401

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

4410
    lltargetfn = bcx.build.Load(lltargetfn);
4411

4412
    auto r = bcx.build.FastCall(lltargetfn, llargs);
4413
    bcx.build.RetVoid();
4414

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

4418 4419 4420
    ret llthunk;
}

4421 4422 4423
fn trans_bind(@block_ctxt cx, @ast.expr f,
              vec[option.t[@ast.expr]] args,
              &ast.ann ann) -> result {
4424 4425
    auto f_res = trans_lval(cx, f);
    if (f_res.is_mem) {
4426
        cx.fcx.lcx.ccx.sess.unimpl("re-binding existing function");
4427
    } else {
4428 4429
        let vec[@ast.expr] bound = vec();

4430 4431 4432 4433 4434
        for (option.t[@ast.expr] argopt in args) {
            alt (argopt) {
                case (none[@ast.expr]) {
                }
                case (some[@ast.expr](?e)) {
4435
                    _vec.push[@ast.expr](bound, e);
4436 4437 4438
                }
            }
        }
4439 4440

        // Figure out which tydescs we need to pass, if any.
4441
        let ty.t outgoing_fty;
B
Brian Anderson 已提交
4442
        let vec[ValueRef] lltydescs;
4443 4444
        alt (f_res.generic) {
            case (none[generic_info]) {
4445
                outgoing_fty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, f);
B
Brian Anderson 已提交
4446
                lltydescs = vec();
4447 4448 4449 4450 4451 4452 4453 4454 4455
            }
            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) {
4456 4457 4458 4459
            // Trivial 'binding': just return the static pair-ptr.
            ret f_res.res;
        } else {
            auto bcx = f_res.res.bcx;
4460
            auto pair_t = node_type(cx.fcx.lcx.ccx, ann);
4461
            auto pair_v = alloca(bcx, pair_t);
4462 4463

            // Translate the bound expressions.
4464
            let vec[ty.t] bound_tys = vec();
4465
            let vec[ValueRef] bound_vals = vec();
4466
            auto i = 0u;
4467 4468 4469
            for (@ast.expr e in bound) {
                auto arg = trans_expr(bcx, e);
                bcx = arg.bcx;
4470

4471
                _vec.push[ValueRef](bound_vals, arg.val);
4472
                _vec.push[ty.t](bound_tys,
4473
                                 ty.expr_ty(cx.fcx.lcx.ccx.tcx, e));
4474 4475

                i += 1u;
4476 4477 4478
            }

            // Synthesize a closure type.
4479
            let ty.t bindings_ty = ty.mk_imm_tup(cx.fcx.lcx.ccx.tcx,
4480
                                                  bound_tys);
4481 4482 4483 4484

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

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

4490
            let vec[ty.t] closure_tys =
4491 4492 4493
                vec(tydesc_ty,
                    outgoing_fty,
                    bindings_ty,
4494
                    ty.mk_imm_tup(cx.fcx.lcx.ccx.tcx, captured_tys));
4495

4496
            let ty.t closure_ty = ty.mk_imm_tup(cx.fcx.lcx.ccx.tcx,
4497
                                                 closure_tys);
4498 4499

            auto r = trans_malloc_boxed(bcx, closure_ty);
4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516
            auto box = r.val;
            bcx = r.bcx;
            auto rc = bcx.build.GEP(box,
                                    vec(C_int(0),
                                        C_int(abi.box_rc_field_refcnt)));
            auto closure =
                bcx.build.GEP(box,
                              vec(C_int(0),
                                  C_int(abi.box_rc_field_body)));
            bcx.build.Store(C_int(1), rc);

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

4520 4521 4522 4523 4524 4525
            // 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.
4526
            auto llfnty = type_of_fn(bcx.fcx.lcx.ccx,
4527 4528 4529
                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),
4530
                ty_param_count);
4531
            auto llclosurety = T_ptr(T_fn_pair(bcx.fcx.lcx.ccx.tn, llfnty));
4532

4533 4534
            // Store thunk-target.
            auto bound_target =
4535 4536
                bcx.build.GEP(closure,
                              vec(C_int(0),
4537
                                  C_int(abi.closure_elt_target)));
4538
            auto src = bcx.build.Load(f_res.res.val);
4539
            bound_target = bcx.build.PointerCast(bound_target, llclosurety);
4540
            bcx.build.Store(src, bound_target);
4541

4542
            // Copy expr values into boxed bindings.
4543
            i = 0u;
4544 4545 4546 4547
            auto bindings =
                bcx.build.GEP(closure,
                              vec(C_int(0),
                                  C_int(abi.closure_elt_bindings)));
4548 4549
            for (ValueRef v in bound_vals) {
                auto bound = bcx.build.GEP(bindings,
4550
                                           vec(C_int(0), C_int(i as int)));
4551
                bcx = copy_ty(bcx, INIT, bound, v, bound_tys.(i)).bcx;
4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571
                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;
                    }
4572 4573

                    outgoing_fty = ginfo.item_type;
4574
                }
4575 4576
            }

4577 4578 4579 4580
            // 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)));
4581

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

4584
            let ValueRef llthunk =
4585
                trans_bind_thunk(cx.fcx.lcx, pair_ty, outgoing_fty,
4586
                                 args, closure_ty, bound_tys,
4587
                                 ty_param_count);
4588 4589 4590 4591 4592 4593 4594

            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)));
4595 4596 4597
            bcx.build.Store
                (bcx.build.PointerCast
                 (box,
4598
                  T_opaque_closure_ptr(bcx.fcx.lcx.ccx.tn)),
4599
                 pair_box);
4600

4601
            find_scope_cx(cx).cleanups +=
4602
                vec(clean(bind drop_slot(_, pair_v, pair_ty)));
4603

4604 4605
            ret res(bcx, pair_v);
        }
4606 4607 4608
    }
}

4609 4610 4611 4612 4613 4614 4615
fn trans_arg_expr(@block_ctxt cx,
                  ty.arg arg,
                  TypeRef lldestty0,
                  @ast.expr e) -> result {

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

4618
    if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, e_ty)) {
4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648
        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;
    }

4649 4650 4651 4652
    if (arg.mode != ast.alias) {
        bcx = take_ty(bcx, val, e_ty).bcx;
    }

4653
    if (ty.type_contains_params(cx.fcx.lcx.ccx.tcx, arg.ty)) {
4654 4655 4656
        auto lldestty = lldestty0;
        if (arg.mode == ast.val) {
            // FIXME: we'd prefer to use &&, but rustboot doesn't like it
4657
            if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, e_ty)) {
4658 4659 4660 4661 4662 4663 4664 4665
                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
4666
        if (ty.type_is_structural(cx.fcx.lcx.ccx.tcx, e_ty)) {
4667 4668 4669 4670 4671 4672 4673 4674
            // 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);
}

4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685
// 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,
4686
              option.t[ValueRef] lliterbody,
4687
              &vec[@ast.expr] es,
4688
              ty.t fn_ty)
4689 4690
    -> tup(@block_ctxt, vec[ValueRef], ValueRef) {

4691
    let vec[ty.arg] args = ty.ty_fn_args(cx.fcx.lcx.ccx.tcx, fn_ty);
4692 4693 4694 4695 4696 4697
    let vec[ValueRef] llargs = vec();
    let vec[ValueRef] lltydescs = vec();
    let @block_ctxt bcx = cx;


    // Arg 0: Output pointer.
4698
    auto retty = ty.ty_fn_ret(cx.fcx.lcx.ccx.tcx, fn_ty);
4699 4700 4701 4702
    auto llretslot_res = alloc_ty(bcx, retty);
    bcx = llretslot_res.bcx;
    auto llretslot = llretslot_res.val;

4703 4704 4705
    alt (gen) {
        case (some[generic_info](?g)) {
            lltydescs = g.tydescs;
4706 4707
            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);
4708 4709 4710 4711
        }
        case (_) {
        }
    }
4712
    if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, retty)) {
4713 4714
        llargs += vec(bcx.build.PointerCast
                      (llretslot, T_typaram_ptr(cx.fcx.lcx.ccx.tn)));
4715
    } else if (ty.type_contains_params(cx.fcx.lcx.ccx.tcx, retty)) {
4716 4717 4718 4719 4720
        // 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.
4721 4722
        llargs +=
            vec(cx.build.PointerCast(llretslot,
4723
                                     T_ptr(type_of(bcx.fcx.lcx.ccx, retty))));
4724
    } else {
4725
        llargs += vec(llretslot);
4726 4727 4728 4729
    }


    // Arg 1: Task pointer.
4730
    llargs += vec(bcx.fcx.lltaskptr);
4731 4732 4733 4734 4735 4736 4737

    // 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).
4738
            llargs += vec(bcx.build.Load(ob));
4739 4740
        }
        case (_) {
4741
            llargs += vec(llenv);
4742 4743 4744 4745 4746 4747
        }
    }

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

4748 4749 4750 4751
    // ... then possibly an lliterbody argument.
    alt (lliterbody) {
        case (none[ValueRef]) {}
        case (some[ValueRef](?lli)) {
4752
            llargs += vec(lli);
4753 4754 4755
        }
    }

4756
    // ... then explicit args.
4757 4758 4759 4760

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

4763 4764
    auto i = 0u;
    for (@ast.expr e in es) {
4765 4766 4767
        auto r = trans_arg_expr(bcx, args.(i), arg_tys.(i), e);
        bcx = r.bcx;
        llargs += vec(r.val);
4768 4769 4770 4771 4772 4773
        i += 1u;
    }

    ret tup(bcx, llargs, llretslot);
}

4774
fn trans_call(@block_ctxt cx, @ast.expr f,
4775 4776 4777
              option.t[ValueRef] lliterbody,
              vec[@ast.expr] args,
              &ast.ann ann) -> result {
4778 4779 4780 4781 4782

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

4783
    auto f_res = trans_lval(cx, f);
4784
    auto faddr = f_res.res.val;
4785
    auto llenv = C_null(T_opaque_closure_ptr(cx.fcx.lcx.ccx.tn));
4786 4787 4788 4789 4790 4791 4792 4793 4794

    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;
4795 4796
            auto pair = faddr;
            faddr = bcx.build.GEP(pair, vec(C_int(0),
G
Graydon Hoare 已提交
4797
                                            C_int(abi.fn_field_code)));
4798
            faddr = bcx.build.Load(faddr);
4799

4800 4801 4802 4803
            auto llclosure = bcx.build.GEP(pair,
                                           vec(C_int(0),
                                               C_int(abi.fn_field_box)));
            llenv = bcx.build.Load(llclosure);
4804
        }
4805
    }
4806

4807
    let ty.t fn_ty;
4808
    alt (f_res.method_ty) {
4809
        case (some[ty.t](?meth)) {
4810 4811
            // self-call
            fn_ty = meth;
4812
        }
4813

4814
        case (_) {
4815
            fn_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, f);
4816 4817

        }
4818

4819
    }
4820

4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832
    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;

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

4835
    for (ValueRef arg in llargs) {
4836
        log "arg: " + val_str(cx.fcx.lcx.ccx.tn, arg);
4837
    }
4838 4839 4840 4841 4842
    */

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

4843 4844
    alt (lliterbody) {
        case (none[ValueRef]) {
4845
            if (!ty.type_is_nil(cx.fcx.lcx.ccx.tcx, ret_ty)) {
4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858
                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.
        }
4859 4860 4861 4862
    }
    ret res(bcx, retval);
}

4863 4864
fn trans_tup(@block_ctxt cx, vec[ast.elt] elts,
             &ast.ann ann) -> result {
4865
    auto bcx = cx;
4866
    auto t = node_ann_type(bcx.fcx.lcx.ccx, ann);
4867 4868 4869 4870
    auto tup_res = alloc_ty(bcx, t);
    auto tup_val = tup_res.val;
    bcx = tup_res.bcx;

4871 4872
    find_scope_cx(cx).cleanups +=
        vec(clean(bind drop_ty(_, tup_val, t)));
G
Graydon Hoare 已提交
4873
    let int i = 0;
4874

4875
    for (ast.elt e in elts) {
4876
        auto e_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, e.expr);
4877 4878 4879 4880 4881
        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 已提交
4882 4883
        i += 1;
    }
4884
    ret res(bcx, tup_val);
G
Graydon Hoare 已提交
4885 4886
}

4887 4888
fn trans_vec(@block_ctxt cx, vec[@ast.expr] args,
             &ast.ann ann) -> result {
4889
    auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
4890
    auto unit_ty = t;
4891
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
4892 4893
        case (ty.ty_vec(?mt)) {
            unit_ty = mt.ty;
G
Graydon Hoare 已提交
4894 4895
        }
        case (_) {
4896
            cx.fcx.lcx.ccx.sess.bug("non-vec type in trans_vec");
G
Graydon Hoare 已提交
4897 4898 4899
        }
    }

4900 4901 4902
    auto bcx = cx;
    auto unit_sz = size_of(bcx, unit_ty);
    bcx = unit_sz.bcx;
4903 4904
    auto data_sz = bcx.build.Mul(C_int(_vec.len[@ast.expr](args) as int),
                                 unit_sz.val);
G
Graydon Hoare 已提交
4905 4906

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

4910
    auto llty = type_of(bcx.fcx.lcx.ccx, t);
4911
    auto vec_val = vi2p(bcx, sub.val, llty);
4912 4913
    find_scope_cx(bcx).cleanups +=
        vec(clean(bind drop_ty(_, vec_val, t)));
G
Graydon Hoare 已提交
4914

4915 4916 4917 4918
    auto body = bcx.build.GEP(vec_val, vec(C_int(0),
                                           C_int(abi.vec_elt_data)));

    auto pseudo_tup_ty =
4919
        ty.mk_imm_tup(cx.fcx.lcx.ccx.tcx,
4920
                      _vec.init_elt[ty.t](unit_ty,
4921
                                           _vec.len[@ast.expr](args)));
G
Graydon Hoare 已提交
4922
    let int i = 0;
4923

G
Graydon Hoare 已提交
4924
    for (@ast.expr e in args) {
4925 4926 4927 4928
        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;
4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942

        // 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;
4943
        if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, unit_ty)) {
4944
            auto llunit_ty = type_of(cx.fcx.lcx.ccx, unit_ty);
4945 4946 4947 4948 4949 4950
            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 已提交
4951 4952
        i += 1;
    }
4953 4954 4955
    auto fill = bcx.build.GEP(vec_val,
                              vec(C_int(0), C_int(abi.vec_elt_fill)));
    bcx.build.Store(data_sz, fill);
4956

4957
    ret res(bcx, vec_val);
G
Graydon Hoare 已提交
4958 4959
}

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

4963
    auto bcx = cx;
4964
    auto t = node_ann_type(bcx.fcx.lcx.ccx, ann);
4965 4966 4967 4968
    auto rec_res = alloc_ty(bcx, t);
    auto rec_val = rec_res.val;
    bcx = rec_res.bcx;

4969 4970
    find_scope_cx(cx).cleanups +=
        vec(clean(bind drop_ty(_, rec_val, t)));
4971
    let int i = 0;
4972

G
Graydon Hoare 已提交
4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984
    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();
4985
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
G
Graydon Hoare 已提交
4986 4987 4988 4989
        case (ty.ty_rec(?flds)) { ty_fields = flds; }
    }

    for (ty.field tf in ty_fields) {
4990
        auto e_ty = tf.mt.ty;
4991 4992
        auto dst_res = GEP_tup_like(bcx, t, rec_val, vec(0, i));
        bcx = dst_res.bcx;
G
Graydon Hoare 已提交
4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005

        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,
5006
                          load_if_immediate(bcx, src_res.val, e_ty));
G
Graydon Hoare 已提交
5007 5008 5009 5010
        }

        bcx = src_res.bcx;
        bcx = copy_ty(bcx, INIT, dst_res.val, src_res.val, e_ty).bcx;
5011 5012
        i += 1;
    }
5013
    ret res(bcx, rec_val);
5014 5015
}

G
Graydon Hoare 已提交
5016

G
Graydon Hoare 已提交
5017

5018
fn trans_expr(@block_ctxt cx, @ast.expr e) -> result {
5019
    alt (e.node) {
5020
        case (ast.expr_lit(?lit, ?ann)) {
5021
            ret res(cx, trans_lit(cx.fcx.lcx.ccx, *lit, ann));
5022 5023
        }

5024
        case (ast.expr_unary(?op, ?x, ?ann)) {
5025 5026 5027
            if (op != ast.deref) {
                ret trans_unary(cx, op, x, ann);
            }
5028 5029
        }

P
Patrick Walton 已提交
5030
        case (ast.expr_binary(?op, ?x, ?y, _)) {
5031
            ret trans_binary(cx, op, x, y);
5032
        }
5033

P
Patrick Walton 已提交
5034
        case (ast.expr_if(?cond, ?thn, ?els, _)) {
5035
            ret trans_if(cx, cond, thn, els);
5036 5037
        }

G
Graydon Hoare 已提交
5038 5039 5040 5041
        case (ast.expr_for(?decl, ?seq, ?body, _)) {
            ret trans_for(cx, decl, seq, body);
        }

5042 5043 5044 5045
        case (ast.expr_for_each(?decl, ?seq, ?body, _)) {
            ret trans_for_each(cx, decl, seq, body);
        }

5046
        case (ast.expr_while(?cond, ?body, _)) {
5047
            ret trans_while(cx, cond, body);
5048 5049
        }

5050
        case (ast.expr_do_while(?body, ?cond, _)) {
5051
            ret trans_do_while(cx, body, cond);
5052 5053
        }

5054 5055
        case (ast.expr_alt(?expr, ?arms, ?ann)) {
            ret trans_alt(cx, expr, arms, ann);
P
Patrick Walton 已提交
5056 5057
        }

P
Patrick Walton 已提交
5058
        case (ast.expr_block(?blk, _)) {
5059 5060 5061 5062 5063 5064 5065 5066
            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);
5067
        }
5068

5069
        case (ast.expr_assign(?dst, ?src, ?ann)) {
5070
            auto lhs_res = trans_lval(cx, dst);
5071 5072
            check (lhs_res.is_mem);
            auto rhs_res = trans_expr(lhs_res.res.bcx, src);
5073
            auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
G
Graydon Hoare 已提交
5074
            // FIXME: calculate copy init-ness in typestate.
5075 5076
            ret copy_ty(rhs_res.bcx, DROP_EXISTING,
                        lhs_res.res.val, rhs_res.val, t);
5077
        }
G
Graydon Hoare 已提交
5078

5079
        case (ast.expr_assign_op(?op, ?dst, ?src, ?ann)) {
5080
            auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
5081
            auto lhs_res = trans_lval(cx, dst);
5082 5083
            check (lhs_res.is_mem);
            auto rhs_res = trans_expr(lhs_res.res.bcx, src);
5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095
            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);
5096 5097
            auto v = trans_eager_binop(rhs_res.bcx, op, t,
                                       lhs_val, rhs_res.val);
5098
            // FIXME: calculate copy init-ness in typestate.
5099 5100
            ret copy_ty(v.bcx, DROP_EXISTING,
                        lhs_res.res.val, v.val, t);
5101 5102
        }

5103 5104 5105 5106
        case (ast.expr_bind(?f, ?args, ?ann)) {
            ret trans_bind(cx, f, args, ann);
        }

G
Graydon Hoare 已提交
5107
        case (ast.expr_call(?f, ?args, ?ann)) {
5108
            ret trans_call(cx, f, none[ValueRef], args, ann);
5109 5110
        }

5111
        case (ast.expr_cast(?e, _, ?ann)) {
5112
            ret trans_cast(cx, e, ann);
5113
        }
G
Graydon Hoare 已提交
5114

5115
        case (ast.expr_vec(?args, _, ?ann)) {
G
Graydon Hoare 已提交
5116 5117 5118
            ret trans_vec(cx, args, ann);
        }

G
Graydon Hoare 已提交
5119 5120 5121
        case (ast.expr_tup(?args, ?ann)) {
            ret trans_tup(cx, args, ann);
        }
G
Graydon Hoare 已提交
5122

5123 5124
        case (ast.expr_rec(?args, ?base, ?ann)) {
            ret trans_rec(cx, args, base, ann);
5125 5126
        }

5127
        case (ast.expr_ext(_, _, _, ?expanded, _)) {
5128
            ret trans_expr(cx, expanded);
5129 5130
        }

5131
        case (ast.expr_fail(_)) {
5132
            ret trans_fail(cx, some[common.span](e.span), "explicit failure");
5133 5134
        }

M
Marijn Haverbeke 已提交
5135 5136
        case (ast.expr_log(?lvl, ?a, _)) {
            ret trans_log(lvl, cx, a);
5137 5138
        }

5139
        case (ast.expr_check_expr(?a, _)) {
5140 5141 5142
            ret trans_check_expr(cx, a);
        }

5143
        case (ast.expr_break(?a)) {
5144 5145 5146
            ret trans_break(cx);
        }

5147
        case (ast.expr_cont(?a)) {
5148 5149 5150
            ret trans_cont(cx);
        }

5151
        case (ast.expr_ret(?e, _)) {
5152 5153 5154
            ret trans_ret(cx, e);
        }

5155
        case (ast.expr_put(?e, _)) {
5156 5157 5158
            ret trans_put(cx, e);
        }

5159
        case (ast.expr_be(?e, _)) {
5160 5161 5162
            ret trans_be(cx, e);
        }

B
Brian Anderson 已提交
5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178
        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);
        }

5179
        case (_) {
5180
            // The expression is an lvalue. Fall through.
5181
        }
5182
    }
5183 5184 5185 5186

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

5187
    auto t = ty.expr_ty(cx.fcx.lcx.ccx.tcx, e);
5188
    auto sub = trans_lval(cx, e);
5189
    ret res(sub.res.bcx, load_if_immediate(sub.res.bcx, sub.res.val, t));
5190 5191
}

5192
// We pass structural values around the compiler "by pointer" and
5193 5194 5195 5196 5197
// 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.

5198
fn type_is_immediate(@crate_ctxt ccx, ty.t t) -> bool {
5199 5200 5201
    ret ty.type_is_scalar(ccx.tcx, t) ||
        ty.type_is_boxed(ccx.tcx, t) ||
        ty.type_is_native(ccx.tcx, t);
5202 5203 5204 5205 5206 5207 5208 5209
}

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

5211
fn spill_if_immediate(@block_ctxt cx, ValueRef v, ty.t t) -> ValueRef {
5212
    if (type_is_immediate(cx.fcx.lcx.ccx, t)) {
5213 5214 5215 5216 5217
        ret do_spill(cx, v);
    }
    ret v;
}

5218
fn load_if_immediate(@block_ctxt cx, ValueRef v, ty.t t) -> ValueRef {
5219
    if (type_is_immediate(cx.fcx.lcx.ccx, t)) {
5220 5221
        ret cx.build.Load(v);
    }
5222
    ret v;
5223 5224
}

M
Marijn Haverbeke 已提交
5225
fn trans_log(int lvl, @block_ctxt cx, @ast.expr e) -> result {
5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240
    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);
    }

5241
    auto log_cx = new_scope_block_ctxt(cx, "log");
5242 5243
    auto after_cx = new_sub_block_ctxt(cx, "after");
    auto load = cx.build.Load(global);
M
Marijn Haverbeke 已提交
5244
    auto test = cx.build.ICmp(lib.llvm.LLVMIntSGE, load, C_int(lvl));
5245 5246 5247
    cx.build.CondBr(test, log_cx.llbb, after_cx.llbb);

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

5250
    if (ty.type_is_fp(cx.fcx.lcx.ccx.tcx, e_ty)) {
5251 5252
        let TypeRef tr;
        let bool is32bit = false;
5253
        alt (ty.struct(cx.fcx.lcx.ccx.tcx, e_ty)) {
5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265
            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) {
5266 5267 5268 5269
            auto uval = trans_upcall(sub.bcx,
                                     "upcall_log_float",
                                     vec(C_int(lvl), sub.val));
            uval.bcx.build.Br(after_cx.llbb);
5270
        } else {
5271
            auto tmp = alloca(sub.bcx, tr);
5272
            sub.bcx.build.Store(sub.val, tmp);
5273 5274 5275 5276
            auto uval = trans_upcall(sub.bcx,
                                     "upcall_log_double",
                                     vec(C_int(lvl), vp2i(sub.bcx, tmp)));
            uval.bcx.build.Br(after_cx.llbb);
5277
        }
5278
    } else {
5279
        alt (ty.struct(cx.fcx.lcx.ccx.tcx, e_ty)) {
5280 5281 5282
            case (ty.ty_str) {
                auto v = vp2i(sub.bcx, sub.val);
                trans_upcall(sub.bcx,
5283
                             "upcall_log_str",
M
Marijn Haverbeke 已提交
5284
                             vec(C_int(lvl), v)).bcx.build.Br(after_cx.llbb);
5285 5286
            }
            case (_) {
M
Marijn Haverbeke 已提交
5287
                auto v = vec(C_int(lvl), sub.val);
5288
                trans_upcall(sub.bcx,
5289
                             "upcall_log_int",
M
Marijn Haverbeke 已提交
5290
                             v).bcx.build.Br(after_cx.llbb);
5291
            }
5292 5293
        }
    }
5294 5295

    ret res(after_cx, C_nil());
5296 5297
}

5298
fn trans_check_expr(@block_ctxt cx, @ast.expr e) -> result {
5299 5300
    auto cond_res = trans_expr(cx, e);

5301
    auto expr_str = pretty.pprust.expr_to_str(e);
5302
    auto fail_cx = new_sub_block_ctxt(cx, "fail");
5303
    auto fail_res = trans_fail(fail_cx, some[common.span](e.span), expr_str);
5304

5305
    auto next_cx = new_sub_block_ctxt(cx, "next");
5306 5307 5308 5309 5310 5311
    cond_res.bcx.build.CondBr(cond_res.val,
                              next_cx.llbb,
                              fail_cx.llbb);
    ret res(next_cx, C_nil());
}

5312 5313
fn trans_fail(@block_ctxt cx, option.t[common.span] sp_opt, str fail_str)
        -> result {
5314
    auto V_fail_str = p2i(C_cstr(cx.fcx.lcx.ccx, fail_str));
5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328

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

5331 5332 5333
    auto sub = trans_upcall(cx, "upcall_fail", args);
    sub.bcx.build.Unreachable();
    ret res(sub.bcx, C_nil());
B
Brian Anderson 已提交
5334 5335
}

5336
fn trans_put(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
5337 5338 5339 5340 5341
    auto llcallee = C_nil();
    auto llenv = C_nil();

    alt (cx.fcx.lliterbody) {
        case (some[ValueRef](?lli)) {
5342
            auto slot = alloca(cx, val_ty(lli));
5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354
            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;
5355
    auto dummy_retslot = alloca(bcx, T_nil());
5356 5357 5358 5359
    let vec[ValueRef] llargs = vec(dummy_retslot, cx.fcx.lltaskptr, llenv);
    alt (e) {
        case (none[@ast.expr]) { }
        case (some[@ast.expr](?x)) {
5360
            auto e_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, x);
5361 5362 5363
            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);
5364
            bcx = r.bcx;
5365
            llargs += vec(r.val);
5366 5367
        }
    }
5368

5369
    ret res(bcx, bcx.build.FastCall(llcallee, llargs));
5370 5371
}

5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391
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);
                        }
                    }
                }
5392
                ret res(bcx, C_nil());
5393 5394 5395 5396 5397 5398 5399 5400
            }
            case (_) {
                alt (cleanup_cx.parent) {
                    case (parent_some(?cx)) { cleanup_cx = cx; }
                }
            }
        }
    }
5401
    fail;
5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412
}

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


5413 5414 5415 5416
fn trans_ret(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
    auto bcx = cx;
    auto val = C_nil();

5417 5418
    alt (e) {
        case (some[@ast.expr](?x)) {
5419
            auto t = ty.expr_ty(cx.fcx.lcx.ccx.tcx, x);
5420 5421 5422
            auto r = trans_expr(cx, x);
            bcx = r.bcx;
            val = r.val;
5423
            bcx = copy_ty(bcx, INIT, cx.fcx.llretptr, val, t).bcx;
5424
        }
5425 5426 5427 5428 5429
        case (_) {
            auto t = llvm.LLVMGetElementType(val_ty(cx.fcx.llretptr));
            auto null = lib.llvm.llvm.LLVMConstNull(t);
            bcx.build.Store(null, cx.fcx.llretptr);
        }
5430 5431
    }

5432 5433
    // Run all cleanups and back out.
    let bool more_cleanups = true;
5434
    auto cleanup_cx = cx;
5435
    while (more_cleanups) {
5436
        bcx = trans_block_cleanups(bcx, cleanup_cx);
5437
        alt (cleanup_cx.parent) {
5438
            case (parent_some(?b)) {
5439
                cleanup_cx = b;
5440 5441 5442 5443 5444 5445 5446
            }
            case (parent_none) {
                more_cleanups = false;
            }
        }
    }

5447 5448
    bcx.build.RetVoid();
    ret res(bcx, C_nil());
5449 5450
}

5451
fn trans_be(@block_ctxt cx, @ast.expr e) -> result {
5452
    // FIXME: This should be a typestate precondition
5453
    check (ast.is_call_expr(e));
5454 5455
    // FIXME: Turn this into a real tail call once
    // calling convention issues are settled
5456 5457 5458
    ret trans_ret(cx, some(e));
}

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

5461
    auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
B
Brian Anderson 已提交
5462
    auto unit_ty;
5463
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, t)) {
B
Brian Anderson 已提交
5464 5465 5466 5467
        case (ty.ty_port(?t)) {
            unit_ty = t;
        }
        case (_) {
5468
            cx.fcx.lcx.ccx.sess.bug("non-port type in trans_port");
B
Brian Anderson 已提交
5469 5470 5471 5472
            fail;
        }
    }

5473
    auto llunit_ty = type_of(cx.fcx.lcx.ccx, unit_ty);
B
Brian Anderson 已提交
5474 5475 5476 5477 5478 5479

    auto bcx = cx;
    auto unit_sz = size_of(bcx, unit_ty);
    bcx = unit_sz.bcx;
    auto sub = trans_upcall(bcx, "upcall_new_port", vec(unit_sz.val));
    bcx = sub.bcx;
5480
    auto llty = type_of(cx.fcx.lcx.ccx, t);
B
Brian Anderson 已提交
5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497
    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);
    auto sub = trans_upcall(bcx, "upcall_new_chan", vec(prt_val));
    bcx = sub.bcx;

5498 5499
    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 已提交
5500 5501 5502 5503 5504 5505 5506 5507 5508
    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 {
5509 5510 5511 5512 5513 5514 5515

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

5516
    auto chan_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
5517
    auto unit_ty;
5518
    alt (ty.struct(cx.fcx.lcx.ccx.tcx, chan_ty)) {
5519 5520 5521 5522
        case (ty.ty_chan(?t)) {
            unit_ty = t;
        }
        case (_) {
5523
            bcx.fcx.lcx.ccx.sess.bug("non-chan type in trans_send");
5524 5525 5526 5527
            fail;
        }
    }

5528 5529 5530 5531
    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;
5532

5533 5534
    find_scope_cx(bcx).cleanups +=
        vec(clean(bind drop_ty(_, data_alloc.val, unit_ty)));
5535

5536 5537 5538
    auto sub = trans_upcall(bcx, "upcall_send",
                            vec(vp2i(bcx, chn.val),
                                vp2i(bcx, data_alloc.val)));
5539 5540
    bcx = sub.bcx;

5541
    ret res(bcx, chn.val);
B
Brian Anderson 已提交
5542 5543 5544 5545
}

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

    auto bcx = cx;
B
Brian Anderson 已提交
5548 5549 5550
    auto data = trans_lval(bcx, lhs);
    check (data.is_mem);
    bcx = data.res.bcx;
5551
    auto unit_ty = node_ann_type(bcx.fcx.lcx.ccx, ann);
5552 5553 5554

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

fn recv_val(@block_ctxt cx, ValueRef lhs, @ast.expr rhs,
5558
            ty.t unit_ty, copy_action action) -> result {
5559 5560

    auto bcx = cx;
5561 5562
    auto prt = trans_expr(bcx, rhs);
    bcx = prt.bcx;
B
Brian Anderson 已提交
5563

5564
    auto sub = trans_upcall(bcx, "upcall_recv",
5565
                            vec(vp2i(bcx, lhs),
5566 5567 5568
                                vp2i(bcx, prt.val)));
    bcx = sub.bcx;

5569
    auto data_load = load_if_immediate(bcx, lhs, unit_ty);
5570
    auto cp = copy_ty(bcx, action, lhs, data_load, unit_ty);
5571
    bcx = cp.bcx;
B
Brian Anderson 已提交
5572

5573
    // TODO: Any cleanup need to be done here?
5574

5575
    ret res(bcx, lhs);
B
Brian Anderson 已提交
5576 5577
}

5578 5579 5580 5581 5582
fn init_local(@block_ctxt cx, @ast.local local) -> result {

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

    find_scope_cx(cx).cleanups +=
5587
        vec(clean(bind drop_slot(_, llptr, ty)));
5588 5589

    alt (local.init) {
5590
        case (some[ast.initializer](?init)) {
5591 5592 5593 5594 5595 5596 5597 5598 5599
            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;
                }
            }
5600 5601
        }
        case (_) {
5602
            bcx = zero_alloca(bcx, llptr, ty).bcx;
5603 5604 5605 5606 5607
        }
    }
    ret res(bcx, llptr);
}

5608
fn zero_alloca(@block_ctxt cx, ValueRef llptr, ty.t t) -> result {
5609
    auto bcx = cx;
5610
    if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
5611 5612 5613
        auto llsz = size_of(bcx, t);
        bcx = call_bzero(llsz.bcx, llptr, llsz.val).bcx;
    } else {
5614
        auto llty = type_of(bcx.fcx.lcx.ccx, t);
5615 5616 5617 5618 5619 5620
        auto null = lib.llvm.llvm.LLVMConstNull(llty);
        bcx.build.Store(null, llptr);
    }
    ret res(bcx, llptr);
 }

5621 5622
fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
    auto bcx = cx;
5623
    alt (s.node) {
5624
        case (ast.stmt_expr(?e,_)) {
5625
            bcx = trans_expr(cx, e).bcx;
5626
        }
5627

5628
        case (ast.stmt_decl(?d,_)) {
5629 5630
            alt (d.node) {
                case (ast.decl_local(?local)) {
5631
                    bcx = init_local(bcx, local).bcx;
5632
                }
G
Graydon Hoare 已提交
5633
                case (ast.decl_item(?i)) {
5634
                    trans_item(cx.fcx.lcx, *i);
G
Graydon Hoare 已提交
5635
                }
5636 5637
            }
        }
5638
        case (_) {
5639
            cx.fcx.lcx.ccx.sess.unimpl("stmt variant");
5640 5641
        }
    }
5642
    ret res(bcx, C_nil());
5643 5644
}

5645
fn new_builder(BasicBlockRef llbb) -> builder {
5646 5647
    let BuilderRef llbuild = llvm.LLVMCreateBuilder();
    llvm.LLVMPositionBuilderAtEnd(llbuild, llbb);
5648
    ret builder(llbuild, @mutable false);
5649 5650
}

5651 5652
// You probably don't want to use this one. See the
// next three functions instead.
5653
fn new_block_ctxt(@fn_ctxt cx, block_parent parent,
5654
                  block_kind kind,
5655
                  str name) -> @block_ctxt {
5656
    let vec[cleanup] cleanups = vec();
5657
    let BasicBlockRef llbb =
5658
        llvm.LLVMAppendBasicBlock(cx.llfn,
5659
                                  _str.buf(cx.lcx.ccx.names.next(name)));
5660

5661
    ret @rec(llbb=llbb,
5662
             build=new_builder(llbb),
5663
             parent=parent,
5664
             kind=kind,
5665
             mutable cleanups=cleanups,
5666 5667 5668
             fcx=cx);
}

5669 5670
// 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 {
5671 5672
    ret new_block_ctxt(fcx, parent_none, SCOPE_BLOCK,
                       "function top level");
5673
}
5674

5675 5676
// 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 {
5677
    ret new_block_ctxt(bcx.fcx, parent_some(bcx), SCOPE_BLOCK, n);
5678 5679
}

5680 5681 5682 5683 5684 5685
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);
}

5686
// Use this when you're making a general CFG BB within a scope.
5687
fn new_sub_block_ctxt(@block_ctxt bcx, str n) -> @block_ctxt {
5688
    ret new_block_ctxt(bcx.fcx, parent_some(bcx), NON_SCOPE_BLOCK, n);
5689
}
5690

5691

5692 5693
fn trans_block_cleanups(@block_ctxt cx,
                        @block_ctxt cleanup_cx) -> @block_ctxt {
5694
    auto bcx = cx;
5695

5696
    if (cleanup_cx.kind == NON_SCOPE_BLOCK) {
5697 5698 5699
        check (_vec.len[cleanup](cleanup_cx.cleanups) == 0u);
    }

5700 5701 5702 5703
    auto i = _vec.len[cleanup](cleanup_cx.cleanups);
    while (i > 0u) {
        i -= 1u;
        auto c = cleanup_cx.cleanups.(i);
5704
        alt (c) {
5705
            case (clean(?cfn)) {
5706
                bcx = cfn(bcx).bcx;
5707 5708 5709
            }
        }
    }
5710 5711 5712
    ret bcx;
}

5713 5714 5715 5716 5717
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) {
5718
            case (ast.stmt_decl(?d,_)) {
5719 5720 5721 5722
                alt (d.node) {
                    case (ast.decl_local(?local)) {
                        put local;
                    }
5723
                    case (_) { /* fall through */ }
5724 5725
                }
            }
5726
            case (_) { /* fall through */ }
5727 5728 5729 5730
        }
    }
}

5731 5732 5733 5734 5735 5736 5737 5738 5739 5740
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);
}

5741
fn alloc_ty(@block_ctxt cx, ty.t t) -> result {
5742
    auto val = C_int(0);
5743
    if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
5744 5745 5746 5747 5748 5749 5750 5751 5752

        // 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);
5753
    } else {
5754
        val = alloca(cx, type_of(cx.fcx.lcx.ccx, t));
5755
    }
5756 5757 5758 5759 5760 5761 5762
    // 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);
5763 5764
}

5765
fn alloc_local(@block_ctxt cx, @ast.local local) -> result {
5766
    auto t = node_ann_type(cx.fcx.lcx.ccx, local.ann);
5767 5768 5769 5770 5771
    auto r = alloc_ty(cx, t);
    r.bcx.fcx.lllocals.insert(local.id, r.val);
    ret r;
}

5772
fn trans_block(@block_ctxt cx, &ast.block b) -> result {
5773 5774
    auto bcx = cx;

5775
    for each (@ast.local local in block_locals(b)) {
5776
        bcx = alloc_local(bcx, local).bcx;
5777
    }
5778
    auto r = res(bcx, C_nil());
5779

5780
    for (@ast.stmt s in b.node.stmts) {
5781 5782
        r = trans_stmt(bcx, *s);
        bcx = r.bcx;
5783 5784 5785 5786 5787
        // 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;
        }
5788
    }
5789

5790 5791 5792 5793
    alt (b.node.expr) {
        case (some[@ast.expr](?e)) {
            r = trans_expr(bcx, e);
            bcx = r.bcx;
5794

5795 5796
            if (is_terminated(bcx)) {
                ret r;
5797
            } else {
5798 5799
                auto r_ty = ty.expr_ty(cx.fcx.lcx.ccx.tcx, e);
                if (!ty.type_is_nil(cx.fcx.lcx.ccx.tcx, r_ty)) {
5800
                    // The value resulting from the block gets copied into an
B
Brian Anderson 已提交
5801
                    // alloca created in an outer scope and its refcount
5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813
                    // 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.
5814
                    auto res_alloca = alloc_ty(bcx, r_ty);
5815 5816
                    auto llbcx = llallocas_block_ctxt(bcx.fcx);
                    zero_alloca(llbcx, res_alloca.val, r_ty);
5817 5818

                    // Now we're working in our own block context again
5819 5820 5821 5822 5823 5824
                    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,
5825
                                       ty.t t) -> result {
5826
                        auto reg_val = load_if_immediate(cx,
5827 5828 5829 5830 5831 5832 5833 5834
                                                            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));
                }
5835 5836 5837 5838 5839 5840 5841
            }
        }
        case (none[@ast.expr]) {
            r = res(bcx, C_nil());
        }
    }

5842
    bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
5843
    ret res(bcx, r.val);
5844 5845
}

5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856
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);
}

5857 5858 5859 5860 5861 5862 5863
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args

5864
fn new_fn_ctxt(@local_ctxt cx,
5865
               ValueRef llfndecl) -> @fn_ctxt {
5866

5867 5868 5869
    let ValueRef llretptr = llvm.LLVMGetParam(llfndecl, 0u);
    let ValueRef lltaskptr = llvm.LLVMGetParam(llfndecl, 1u);
    let ValueRef llenv = llvm.LLVMGetParam(llfndecl, 2u);
5870 5871

    let hashmap[ast.def_id, ValueRef] llargs = new_def_hash[ValueRef]();
5872 5873
    let hashmap[ast.def_id, ValueRef] llobjfields = new_def_hash[ValueRef]();
    let hashmap[ast.def_id, ValueRef] lllocals = new_def_hash[ValueRef]();
5874
    let hashmap[ast.def_id, ValueRef] llupvars = new_def_hash[ValueRef]();
5875

5876 5877 5878
    let BasicBlockRef llallocas =
        llvm.LLVMAppendBasicBlock(llfndecl, _str.buf("allocas"));

5879
    ret @rec(llfn=llfndecl,
5880
             lltaskptr=lltaskptr,
5881 5882
             llenv=llenv,
             llretptr=llretptr,
5883
             mutable llallocas = llallocas,
5884
             mutable llself=none[self_vt],
5885
             mutable lliterbody=none[ValueRef],
5886
             llargs=llargs,
5887
             llobjfields=llobjfields,
5888
             lllocals=lllocals,
5889
             llupvars=llupvars,
5890
             mutable lltydescs=_vec.empty[ValueRef](),
5891
             lcx=cx);
5892 5893
}

5894 5895 5896 5897 5898 5899 5900
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args

5901
fn create_llargs_for_fn_args(&@fn_ctxt cx,
5902
                             ast.proto proto,
5903 5904
                             option.t[tup(TypeRef, ty.t)] ty_self,
                             ty.t ret_ty,
5905
                             &vec[ast.arg] args,
5906
                             &vec[ast.ty_param] ty_params) {
5907 5908

    auto arg_n = 3u;
5909

5910
    alt (ty_self) {
5911
        case (some[tup(TypeRef, ty.t)](?tt)) {
5912 5913
            cx.llself = some[self_vt](rec(v = cx.llenv, t = tt._1));
        }
5914
        case (none[tup(TypeRef, ty.t)]) {
5915
            auto i = 0u;
5916 5917 5918
            for (ast.ty_param tp in ty_params) {
                auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n);
                check (llarg as int != 0);
5919
                cx.lltydescs += vec(llarg);
5920
                arg_n += 1u;
5921
                i += 1u;
5922
            }
5923
        }
5924 5925
    }

5926
    if (proto == ast.proto_iter) {
5927 5928 5929 5930 5931
        auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n);
        check (llarg as int != 0);
        cx.lliterbody = some[ValueRef](llarg);
        arg_n += 1u;
    }
5932

5933 5934 5935 5936 5937 5938 5939 5940
    for (ast.arg arg in args) {
        auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n);
        check (llarg as int != 0);
        cx.llargs.insert(arg.id, llarg);
        arg_n += 1u;
    }
}

5941 5942 5943 5944
// 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.

5945
fn copy_any_self_to_alloca(@fn_ctxt fcx,
5946
                           option.t[tup(TypeRef, ty.t)] ty_self) {
5947

5948
    auto bcx = llallocas_block_ctxt(fcx);
5949

5950
    alt (fcx.llself) {
5951
        case (some[self_vt](?s_vt)) {
5952
            alt (ty_self) {
5953
                case (some[tup(TypeRef, ty.t)](?tt)) {
5954 5955 5956
                    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));
5957 5958 5959 5960 5961 5962
                }
            }
        }
        case (_) {
        }
    }
5963 5964 5965 5966 5967 5968 5969 5970 5971 5972
}


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

5974
    for (ast.arg aarg in args) {
5975
        if (aarg.mode != ast.alias) {
5976
            auto arg_t = type_of_arg(fcx.lcx, arg_tys.(arg_n));
5977 5978 5979
            auto a = alloca(bcx, arg_t);
            auto argval = fcx.llargs.get(aarg.id);
            bcx.build.Store(argval, a);
5980
            // Overwrite the llargs entry for this arg with its alloca.
5981
            fcx.llargs.insert(aarg.id, a);
5982 5983
        }

5984 5985
        arg_n += 1u;
    }
5986 5987

    fcx.llallocas = bcx.llbb;
5988 5989
}

5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004
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;
    }
}


6005 6006 6007 6008 6009
fn is_terminated(@block_ctxt cx) -> bool {
    auto inst = llvm.LLVMGetLastInstruction(cx.llbb);
    ret llvm.LLVMIsATerminatorInst(inst) as int != 0;
}

6010
fn arg_tys_of_fn(@crate_ctxt ccx, ast.ann ann) -> vec[ty.arg] {
6011
    alt (ty.struct(ccx.tcx, ty.ann_to_type(ann))) {
6012
        case (ty.ty_fn(_, ?arg_tys, _)) {
6013 6014 6015 6016 6017 6018
            ret arg_tys;
        }
    }
    fail;
}

6019
fn ret_ty_of_fn_ty(@crate_ctxt ccx, ty.t t) -> ty.t {
6020
    alt (ty.struct(ccx.tcx, t)) {
6021
        case (ty.ty_fn(_, _, ?ret_ty)) {
6022 6023 6024 6025 6026 6027
            ret ret_ty;
        }
    }
    fail;
}

6028

6029 6030
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));
6031 6032
}

6033
fn populate_fn_ctxt_from_llself(@fn_ctxt fcx, self_vt llself) {
6034
    auto bcx = llallocas_block_ctxt(fcx);
6035

6036
    let vec[ty.t] field_tys = vec();
6037

6038 6039
    for (ast.obj_field f in bcx.fcx.lcx.obj_fields) {
        field_tys += vec(node_ann_type(bcx.fcx.lcx.ccx, f.ann));
6040 6041
    }

6042 6043
    // Synthesize a tuple type for the fields so that GEP_tup_like() can work
    // its magic.
6044
    auto fields_tup_ty = ty.mk_imm_tup(fcx.lcx.ccx.tcx, field_tys);
6045

6046 6047
    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);
6048 6049

    auto box_cell =
6050
        bcx.build.GEP(llself.v,
6051 6052
                      vec(C_int(0),
                          C_int(abi.obj_field_box)));
6053

6054
    auto box_ptr = bcx.build.Load(box_cell);
6055

6056
    box_ptr = bcx.build.PointerCast(box_ptr, llobj_box_ty);
6057

6058
    auto obj_typarams = bcx.build.GEP(box_ptr,
6059 6060 6061
                                     vec(C_int(0),
                                         C_int(abi.box_rc_field_body),
                                         C_int(abi.obj_body_elt_typarams)));
6062

6063 6064 6065
    // 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),
6066
        llsize_of(llvm.LLVMGetElementType(val_ty(obj_typarams))));
6067 6068 6069 6070

    // 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 *.
6071
    if (!ty.type_has_dynamic_size(fcx.lcx.ccx.tcx, fields_tup_ty)) {
6072
        auto llfields_ty = type_of(fcx.lcx.ccx, fields_tup_ty);
6073 6074 6075 6076 6077
        obj_fields = vi2p(bcx, obj_fields, T_ptr(llfields_ty));
    } else {
        obj_fields = vi2p(bcx, obj_fields, T_ptr(T_i8()));
    }

6078 6079

    let int i = 0;
6080

6081
    for (ast.ty_param p in fcx.lcx.obj_typarams) {
6082 6083 6084 6085
        let ValueRef lltyparam = bcx.build.GEP(obj_typarams,
                                               vec(C_int(0),
                                                   C_int(i)));
        lltyparam = bcx.build.Load(lltyparam);
6086
        fcx.lltydescs += vec(lltyparam);
6087 6088 6089 6090
        i += 1;
    }

    i = 0;
6091
    for (ast.obj_field f in fcx.lcx.obj_fields) {
6092
        auto rslt = GEP_tup_like(bcx, fields_tup_ty, obj_fields, vec(0, i));
6093
        bcx = llallocas_block_ctxt(fcx);
6094
        auto llfield = rslt.val;
6095
        fcx.llobjfields.insert(f.id, llfield);
6096 6097
        i += 1;
    }
6098

6099
    fcx.llallocas = bcx.llbb;
6100 6101
}

6102
fn trans_fn(@local_ctxt cx, &ast._fn f, ast.def_id fid,
6103
            option.t[tup(TypeRef, ty.t)] ty_self,
6104
            &vec[ast.ty_param] ty_params, &ast.ann ann) {
6105

6106
    auto llfndecl = cx.ccx.item_ids.get(fid);
6107

6108
    auto fcx = new_fn_ctxt(cx, llfndecl);
6109
    create_llargs_for_fn_args(fcx, f.proto,
6110
                              ty_self, ret_ty_of_fn(cx.ccx, ann),
6111
                              f.decl.inputs, ty_params);
6112

6113
    copy_any_self_to_alloca(fcx, ty_self);
6114 6115

    alt (fcx.llself) {
6116
        case (some[self_vt](?llself)) {
6117
            populate_fn_ctxt_from_llself(fcx, llself);
6118 6119 6120 6121
        }
        case (_) {
        }
    }
6122

6123 6124
    auto arg_tys = arg_tys_of_fn(fcx.lcx.ccx, ann);
    copy_args_to_allocas(fcx, f.decl.inputs, arg_tys);
6125 6126

    auto bcx = new_top_block_ctxt(fcx);
6127 6128 6129

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

6130 6131
    auto lltop = bcx.llbb;

6132 6133
    auto res = trans_block(bcx, f.body);
    if (!is_terminated(res.bcx)) {
6134 6135
        // FIXME: until LLVM has a unit type, we are moving around
        // C_nil values rather than their void type.
6136
        res.bcx.build.RetVoid();
6137
    }
6138 6139 6140

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

6143
fn trans_vtbl(@local_ctxt cx,
6144
              TypeRef llself_ty,
6145
              ty.t self_ty,
6146 6147
              &ast._obj ob,
              &vec[ast.ty_param] ty_params) -> ValueRef {
G
Graydon Hoare 已提交
6148
    let vec[ValueRef] methods = vec();
6149 6150 6151 6152 6153 6154 6155 6156 6157

    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) {
6158

6159
        auto llfnty = T_nil();
6160
        alt (ty.struct(cx.ccx.tcx, node_ann_type(cx.ccx, m.node.ann))) {
6161
            case (ty.ty_fn(?proto, ?inputs, ?output)) {
6162
                llfnty = type_of_fn_full(cx.ccx, proto,
6163
                                         some[TypeRef](llself_ty),
6164 6165
                                         inputs, output,
                                         _vec.len[ast.ty_param](ty_params));
6166 6167 6168
            }
        }

6169
        let @local_ctxt mcx = extend_path(cx, m.node.ident);
6170
        let str s = mangle_name_by_seq(mcx.ccx, mcx.path, "method");
6171 6172 6173 6174
        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);
6175

6176
        trans_fn(mcx, m.node.meth, m.node.id,
6177
                 some[tup(TypeRef, ty.t)](tup(llself_ty, self_ty)),
6178
                 ty_params, m.node.ann);
6179
        methods += vec(llfn);
G
Graydon Hoare 已提交
6180
    }
6181
    auto vtbl = C_struct(methods);
6182
    auto vtbl_name = mangle_name_by_seq(cx.ccx, cx.path, "vtbl");
6183
    auto gvar = llvm.LLVMAddGlobal(cx.ccx.llmod, val_ty(vtbl),
6184
                                   _str.buf(vtbl_name));
6185 6186
    llvm.LLVMSetInitializer(gvar, vtbl);
    llvm.LLVMSetGlobalConstant(gvar, True);
6187
    llvm.LLVMSetLinkage(gvar, lib.llvm.LLVMInternalLinkage
6188
                        as llvm.Linkage);
6189
    ret gvar;
G
Graydon Hoare 已提交
6190 6191
}

6192
fn trans_dtor(@local_ctxt cx,
6193
              TypeRef llself_ty,
6194
              ty.t self_ty,
6195 6196 6197 6198
              &vec[ast.ty_param] ty_params,
              &@ast.method dtor) -> ValueRef {

    auto llfnty = T_nil();
6199
    alt (ty.struct(cx.ccx.tcx, node_ann_type(cx.ccx, dtor.node.ann))) {
6200
        case (ty.ty_fn(?proto, ?inputs, ?output)) {
6201
            llfnty = type_of_fn_full(cx.ccx, proto,
6202 6203 6204 6205 6206 6207
                                     some[TypeRef](llself_ty),
                                     inputs, output,
                                     _vec.len[ast.ty_param](ty_params));
        }
    }

6208
    let @local_ctxt dcx = extend_path(cx, "drop");
6209
    let str s = mangle_name_by_seq(dcx.ccx, dcx.path, "drop");
6210 6211 6212
    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);
6213 6214

    trans_fn(dcx, dtor.node.meth, dtor.node.id,
6215
             some[tup(TypeRef, ty.t)](tup(llself_ty, self_ty)),
6216 6217 6218 6219 6220
             ty_params, dtor.node.ann);

    ret llfn;
}

6221
fn trans_obj(@local_ctxt cx, &ast._obj ob, ast.def_id oid,
6222
             &vec[ast.ty_param] ty_params, &ast.ann ann) {
6223 6224
    auto ccx = cx.ccx;
    auto llctor_decl = ccx.item_ids.get(oid);
6225

6226
    // Translate obj ctor args to function arguments.
6227 6228 6229 6230 6231 6232 6233 6234
    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));
    }

6235
    auto fcx = new_fn_ctxt(cx, llctor_decl);
6236
    create_llargs_for_fn_args(fcx, ast.proto_fn,
6237
                              none[tup(TypeRef, ty.t)],
6238
                              ret_ty_of_fn(cx.ccx, ann),
6239
                              fn_args, ty_params);
6240

6241
    let vec[ty.arg] arg_tys = arg_tys_of_fn(cx.ccx, ann);
6242 6243 6244 6245
    copy_args_to_allocas(fcx, fn_args, arg_tys);

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

6247
    auto self_ty = ret_ty_of_fn(cx.ccx, ann);
6248
    auto llself_ty = type_of(ccx, self_ty);
6249
    auto pair = bcx.fcx.llretptr;
6250
    auto vtbl = trans_vtbl(cx, llself_ty, self_ty, ob, ty_params);
6251 6252 6253
    auto pair_vtbl = bcx.build.GEP(pair,
                                   vec(C_int(0),
                                       C_int(abi.obj_field_vtbl)));
6254 6255 6256
    auto pair_box = bcx.build.GEP(pair,
                                  vec(C_int(0),
                                      C_int(abi.obj_field_box)));
6257
    bcx.build.Store(vtbl, pair_vtbl);
6258

6259
    let TypeRef llbox_ty = T_opaque_obj_ptr(ccx.tn);
6260 6261 6262 6263

    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.
6264 6265 6266
        bcx.build.Store(C_null(llbox_ty), pair_box);
    } else {
        // Malloc a box for the body and copy args in.
6267
        let vec[ty.t] obj_fields = vec();
6268
        for (ty.arg a in arg_tys) {
6269
            _vec.push[ty.t](obj_fields, a.ty);
6270
        }
6271 6272

        // Synthesize an obj body type.
6273
        auto tydesc_ty = ty.mk_type(cx.ccx.tcx);
6274
        let vec[ty.t] tps = vec();
6275
        for (ast.ty_param tp in ty_params) {
6276
            _vec.push[ty.t](tps, tydesc_ty);
6277 6278
        }

6279 6280 6281
        let ty.t typarams_ty = ty.mk_imm_tup(cx.ccx.tcx, tps);
        let ty.t fields_ty = ty.mk_imm_tup(cx.ccx.tcx, obj_fields);
        let ty.t body_ty = ty.mk_imm_tup(cx.ccx.tcx,
6282
                                          vec(tydesc_ty,
6283 6284
                                              typarams_ty,
                                              fields_ty));
6285
        let ty.t boxed_body_ty = ty.mk_imm_box(cx.ccx.tcx, body_ty);
6286

6287
        // Malloc a box for the body.
6288
        auto box = trans_malloc_boxed(bcx, body_ty);
6289 6290 6291 6292 6293 6294 6295 6296
        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);
6297

6298 6299
        // Store body tydesc.
        auto body_tydesc =
6300 6301 6302
            GEP_tup_like(bcx, body_ty, body.val,
                         vec(0, abi.obj_body_elt_tydesc));
        bcx = body_tydesc.bcx;
6303

6304
        auto dtor = C_null(T_ptr(T_glue_fn(ccx.tn)));
6305 6306 6307 6308 6309 6310 6311
        alt (ob.dtor) {
            case (some[@ast.method](?d)) {
                dtor = trans_dtor(cx, llself_ty, self_ty, ty_params, d);
            }
            case (none[@ast.method]) {}
        }

6312 6313 6314
        auto body_td = get_tydesc(bcx, body_ty);
        bcx = body_td.bcx;
        bcx.build.Store(body_td.val, body_tydesc.val);
6315

6316 6317 6318 6319 6320 6321 6322
        // 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) {
6323
            auto typaram = bcx.fcx.lltydescs.(i);
6324 6325 6326 6327 6328 6329 6330
            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;
        }

6331 6332
        // Copy args into body fields.
        auto body_fields =
6333 6334 6335
            GEP_tup_like(bcx, body_ty, body.val,
                         vec(0, abi.obj_body_elt_fields));
        bcx = body_fields.bcx;
6336

6337
        i = 0;
6338
        for (ast.obj_field f in ob.fields) {
6339
            auto arg = bcx.fcx.llargs.get(f.id);
6340
            arg = load_if_immediate(bcx, arg, arg_tys.(i).ty);
6341 6342 6343 6344
            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;
6345 6346 6347
            i += 1;
        }
        // Store box ptr in outer pair.
6348
        auto p = bcx.build.PointerCast(box.val, llbox_ty);
6349
        bcx.build.Store(p, pair_box);
6350
    }
6351
    bcx.build.RetVoid();
6352 6353 6354

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

6357
fn trans_tag_variant(@local_ctxt cx, ast.def_id tag_id,
6358 6359
                     &ast.variant variant, int index,
                     &vec[ast.ty_param] ty_params) {
6360
    if (_vec.len[ast.variant_arg](variant.node.args) == 0u) {
6361 6362 6363
        ret;    // nullary constructors are just constants
    }

6364 6365 6366
    // Translate variant arguments to function arguments.
    let vec[ast.arg] fn_args = vec();
    auto i = 0u;
6367
    for (ast.variant_arg varg in variant.node.args) {
6368 6369 6370 6371 6372 6373
        fn_args += vec(rec(mode=ast.alias,
                           ty=varg.ty,
                           ident="arg" + _uint.to_str(i, 10u),
                           id=varg.id));
    }

6374 6375
    check (cx.ccx.item_ids.contains_key(variant.node.id));
    let ValueRef llfndecl = cx.ccx.item_ids.get(variant.node.id);
6376

6377
    auto fcx = new_fn_ctxt(cx, llfndecl);
6378

6379
    create_llargs_for_fn_args(fcx, ast.proto_fn,
6380
                              none[tup(TypeRef, ty.t)],
6381
                              ret_ty_of_fn(cx.ccx, variant.node.ann),
6382
                              fn_args, ty_params);
6383

6384
    let vec[ty.t] ty_param_substs = vec();
6385
    i = 0u;
6386
    for (ast.ty_param tp in ty_params) {
6387
        ty_param_substs += vec(ty.mk_param(cx.ccx.tcx, i));
6388
        i += 1u;
6389 6390
    }

6391
    auto arg_tys = arg_tys_of_fn(cx.ccx, variant.node.ann);
6392 6393 6394 6395
    copy_args_to_allocas(fcx, fn_args, arg_tys);

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

6397 6398
    // Cast the tag to a type we can GEP into.
    auto lltagptr = bcx.build.PointerCast(fcx.llretptr,
6399
                                          T_opaque_tag_ptr(fcx.lcx.ccx.tn));
6400 6401

    auto lldiscrimptr = bcx.build.GEP(lltagptr,
6402
                                      vec(C_int(0), C_int(0)));
6403 6404
    bcx.build.Store(C_int(index), lldiscrimptr);

6405
    auto llblobptr = bcx.build.GEP(lltagptr,
6406
                                   vec(C_int(0), C_int(1)));
6407 6408

    i = 0u;
6409 6410
    for (ast.variant_arg va in variant.node.args) {
        auto rslt = GEP_tag(bcx, llblobptr, tag_id, variant.node.id,
6411
                            ty_param_substs, i as int);
6412 6413
        bcx = rslt.bcx;
        auto lldestptr = rslt.val;
6414

6415 6416 6417 6418
        // 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),
6419
            val_ty(lldestptr));
6420

6421 6422
        auto arg_ty = arg_tys.(i).ty;
        auto llargval;
6423 6424
        if (ty.type_is_structural(cx.ccx.tcx, arg_ty) ||
                ty.type_has_dynamic_size(cx.ccx.tcx, arg_ty)) {
6425 6426 6427 6428 6429 6430 6431 6432
            llargval = llargptr;
        } else {
            llargval = bcx.build.Load(llargptr);
        }

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

6433 6434 6435 6436
        i += 1u;
    }

    bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
6437
    bcx.build.RetVoid();
6438 6439 6440

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

6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458
// 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);
6459 6460 6461 6462 6463 6464

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

6467
fn trans_item(@local_ctxt cx, &ast.item item) {
6468
    alt (item.node) {
6469
        case (ast.item_fn(?name, ?f, ?tps, ?fid, ?ann)) {
6470
            auto sub_cx = extend_path(cx, name);
6471
            trans_fn(sub_cx, f, fid, none[tup(TypeRef, ty.t)], tps, ann);
6472
        }
6473
        case (ast.item_obj(?name, ?ob, ?tps, ?oid, ?ann)) {
6474 6475 6476
            auto sub_cx = @rec(obj_typarams=tps,
                               obj_fields=ob.fields with
                               *extend_path(cx, name));
6477
            trans_obj(sub_cx, ob, oid.ctor, tps, ann);
6478
        }
6479
        case (ast.item_mod(?name, ?m, _)) {
6480 6481 6482
            auto sub_cx = @rec(path = cx.path + vec(name),
                               module_path = cx.module_path + vec(name)
                               with *cx);
6483
            trans_mod(sub_cx, m);
6484
        }
6485
        case (ast.item_tag(?name, ?variants, ?tps, ?tag_id, _)) {
6486
            auto sub_cx = extend_path(cx, name);
6487
            auto i = 0;
6488
            for (ast.variant variant in variants) {
6489
                trans_tag_variant(sub_cx, tag_id, variant, i, tps);
6490
                i += 1;
6491 6492
            }
        }
6493
        case (ast.item_const(?name, _, ?expr, ?cid, ?ann)) {
6494
            trans_const(cx.ccx, expr, cid, ann);
6495
        }
6496
        case (_) { /* fall through */ }
6497 6498 6499
    }
}

6500
fn trans_mod(@local_ctxt cx, &ast._mod m) {
6501 6502
    for (@ast.item item in m.items) {
        trans_item(cx, *item);
6503 6504 6505
    }
}

6506 6507 6508 6509 6510 6511 6512 6513
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));
}

6514 6515
fn decl_fn_and_pair(@crate_ctxt ccx,
                    vec[str] path,
6516
                    str flav,
6517
                    vec[ast.ty_param] ty_params,
6518 6519 6520
                    &ast.ann ann,
                    ast.def_id id) {

6521 6522
    auto llfty;
    auto llpairty;
6523
    alt (ty.struct(ccx.tcx, node_ann_type(ccx, ann))) {
6524
        case (ty.ty_fn(?proto, ?inputs, ?output)) {
6525
            llfty = type_of_fn(ccx, proto, inputs, output,
6526
                               _vec.len[ast.ty_param](ty_params));
6527
            llpairty = T_fn_pair(ccx.tn, llfty);
6528 6529
        }
        case (_) {
6530
            ccx.sess.bug("decl_fn_and_pair(): fn item doesn't have fn type!");
6531 6532 6533
            fail;
        }
    }
6534 6535

    // Declare the function itself.
6536
    let str s = mangle_name_by_seq(ccx, path, flav);
6537
    let ValueRef llfn = decl_internal_fastcall_fn(ccx.llmod, s, llfty);
6538 6539

    // Declare the global constant pair that points to it.
6540
    let str ps = mangle_name_by_type(ccx, path, node_ann_type(ccx, ann));
6541

6542
    register_fn_pair(ccx, ps, llpairty, llfn, id);
6543 6544 6545 6546
}

fn register_fn_pair(@crate_ctxt cx, str ps, TypeRef llpairty, ValueRef llfn,
                    ast.def_id id) {
6547 6548 6549
    let ValueRef gvar = llvm.LLVMAddGlobal(cx.llmod, llpairty,
                                           _str.buf(ps));
    auto pair = C_struct(vec(llfn,
6550
                             C_null(T_opaque_closure_ptr(cx.tn))));
6551 6552 6553

    llvm.LLVMSetInitializer(gvar, pair);
    llvm.LLVMSetGlobalConstant(gvar, True);
6554 6555 6556
    llvm.LLVMSetVisibility(gvar,
                           lib.llvm.LLVMProtectedVisibility
                           as llvm.Visibility);
6557 6558

    cx.item_ids.insert(id, llfn);
P
Patrick Walton 已提交
6559
    cx.item_symbols.insert(id, ps);
6560 6561 6562
    cx.fn_pairs.insert(id, gvar);
}

6563 6564 6565 6566 6567 6568 6569 6570 6571 6572
// 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;
        }
6573
        case (ast.native_item_fn(_, _, _, ?tps, _, _)) {
6574 6575 6576 6577 6578 6579
            count = _vec.len[ast.ty_param](tps);
        }
    }
    ret count;
}

6580
fn native_fn_wrapper_type(@crate_ctxt cx, uint ty_param_count, ty.t x)
6581
        -> TypeRef {
6582
    alt (ty.struct(cx.tcx, x)) {
6583
        case (ty.ty_native_fn(?abi, ?args, ?out)) {
6584
            ret type_of_fn(cx, ast.proto_fn, args, out, ty_param_count);
6585 6586 6587 6588 6589
        }
    }
    fail;
}

6590 6591
fn decl_native_fn_and_pair(@crate_ctxt ccx,
                           vec[str] path,
6592 6593 6594
                           str name,
                           &ast.ann ann,
                           ast.def_id id) {
6595
    auto num_ty_param = native_fn_ty_param_count(ccx, id);
6596

6597
    // Declare the wrapper.
6598 6599
    auto t = node_ann_type(ccx, ann);
    auto wrapper_type = native_fn_wrapper_type(ccx, num_ty_param, t);
6600
    let str s = mangle_name_by_seq(ccx, path, "wrapper");
6601 6602
    let ValueRef wrapper_fn = decl_internal_fastcall_fn(ccx.llmod, s,
                                                        wrapper_type);
6603

6604
    // Declare the global constant pair that points to it.
6605
    auto wrapper_pair_type = T_fn_pair(ccx.tn, wrapper_type);
6606
    let str ps = mangle_name_by_type(ccx, path, node_ann_type(ccx, ann));
6607

6608
    register_fn_pair(ccx, ps, wrapper_pair_type, wrapper_fn, id);
6609

6610
    // Build the wrapper.
6611
    auto fcx = new_fn_ctxt(new_local_ctxt(ccx), wrapper_fn);
6612
    auto bcx = new_top_block_ctxt(fcx);
6613
    auto lltop = bcx.llbb;
6614

6615
    // Declare the function itself.
6616 6617
    auto item = ccx.native_items.get(id);
    auto fn_type = node_ann_type(ccx, ann);  // NB: has no type params
6618

6619
    auto abi = ty.ty_fn_abi(ccx.tcx, fn_type);
6620
    auto llfnty = type_of_native_fn(ccx, abi,
6621 6622
        ty.ty_fn_args(ccx.tcx, fn_type),
        ty.ty_fn_ret(ccx.tcx, fn_type), num_ty_param);
6623

6624 6625 6626 6627 6628
    // 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));

6629
    let vec[ValueRef] call_args = vec();
6630
    auto arg_n = 3u;
6631 6632
    auto pass_task;

6633
    auto lltaskptr = vp2i(bcx, fcx.lltaskptr);
6634 6635
    alt (abi) {
        case (ast.native_abi_rust) {
6636
            pass_task = true;
6637
            call_args += vec(lltaskptr);
6638 6639
            for each (uint i in _uint.range(0u, num_ty_param)) {
                auto llarg = llvm.LLVMGetParam(fcx.llfn, arg_n);
G
Graydon Hoare 已提交
6640
                fcx.lltydescs += vec(llarg);
6641
                check (llarg as int != 0);
6642
                call_args += vec(vp2i(bcx, llarg));
6643 6644 6645 6646
                arg_n += 1u;
            }
        }
        case (ast.native_abi_cdecl) {
6647
            pass_task = false;
6648
        }
6649 6650 6651 6652
        case (ast.native_abi_llvm) {
            pass_task = false;
            // We handle this case below.
        }
6653
    }
6654

6655 6656 6657
    fn push_arg(@block_ctxt cx,
                &mutable vec[ValueRef] args,
                ValueRef v,
6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674
                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;
6675 6676
            }
        }
6677 6678

        args += vec(vp2i(cx, v));
6679 6680
    }

6681 6682
    auto r;
    auto rptr;
6683
    auto args = ty.ty_fn_args(ccx.tcx, fn_type);
6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694
    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,
6695
                                 type_of(ccx,
6696
                                         ty.ty_fn_ret(ccx.tcx, fn_type)));
6697
        auto llnativefn = get_extern_fn(ccx.externs, ccx.llmod, name,
6698 6699 6700 6701
                                        lib.llvm.LLVMCCallConv, llnativefnty);
        r = bcx.build.Call(llnativefn, call_args);
        rptr = fcx.llretptr;
    } else {
G
Graydon Hoare 已提交
6702 6703 6704

        let vec[tup(ValueRef, ty.t)] drop_args = vec();

6705 6706 6707
        for (ty.arg arg in args) {
            auto llarg = llvm.LLVMGetParam(fcx.llfn, arg_n);
            check (llarg as int != 0);
6708
            push_arg(bcx, call_args, llarg, arg.ty, arg.mode);
G
Graydon Hoare 已提交
6709 6710 6711
            if (arg.mode == ast.val) {
                drop_args += vec(tup(llarg, arg.ty));
            }
6712 6713 6714
            arg_n += 1u;
        }

6715 6716
        r = trans_native_call(bcx.build, ccx.glues, lltaskptr, ccx.externs,
                              ccx.tn, ccx.llmod, name, pass_task, call_args);
6717
        rptr = bcx.build.BitCast(fcx.llretptr, T_ptr(T_i32()));
G
Graydon Hoare 已提交
6718 6719 6720 6721

        for (tup(ValueRef, ty.t) d in drop_args) {
            bcx = drop_ty(bcx, d._0, d._1).bcx;
        }
6722
    }
6723

6724 6725 6726 6727 6728
    // 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); }

6729
    bcx.build.RetVoid();
6730 6731 6732

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

6735
type walk_ctxt = rec(mutable vec[str] path);
6736 6737 6738 6739
fn new_walk_ctxt() -> @walk_ctxt {
    let vec[str] path = vec();
    ret @rec(mutable path=path);
}
6740 6741 6742 6743 6744

fn enter_item(@walk_ctxt cx, @ast.item item) {
    alt (item.node) {
        case (ast.item_fn(?name, _, _, _, _)) {
            _vec.push[str](cx.path, name);
6745
        }
6746 6747 6748 6749 6750
        case (ast.item_obj(?name, _, _, _, _)) {
            _vec.push[str](cx.path, name);
        }
        case (ast.item_mod(?name, _, _)) {
            _vec.push[str](cx.path, name);
6751
        }
6752
        case (_) { }
6753 6754
    }
}
6755

6756 6757 6758 6759
fn leave_item(@walk_ctxt cx, @ast.item item) {
    alt (item.node) {
        case (ast.item_fn(_, _, _, _, _)) {
            _vec.pop[str](cx.path);
6760
        }
6761 6762
        case (ast.item_obj(_, _, _, _, _)) {
            _vec.pop[str](cx.path);
6763
        }
6764 6765
        case (ast.item_mod(_, _, _)) {
            _vec.pop[str](cx.path);
6766
        }
6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777
        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);
            }
6778
        }
6779 6780
        case (ast.native_item_ty(_, ?tid)) {
            ccx.native_items.insert(tid, i);
6781 6782 6783
        }
    }
}
6784

6785 6786 6787
fn collect_item_1(@crate_ctxt ccx, @walk_ctxt wcx, @ast.item i) {
    enter_item(wcx, i);

6788
    alt (i.node) {
6789
        case (ast.item_const(?name, _, _, ?cid, ?ann)) {
6790 6791 6792
            auto typ = node_ann_type(ccx, ann);
            auto g = llvm.LLVMAddGlobal(ccx.llmod, type_of(ccx, typ),
                                        _str.buf(ccx.names.next(name)));
6793
            llvm.LLVMSetLinkage(g, lib.llvm.LLVMInternalLinkage
6794
                                as llvm.Linkage);
6795 6796
            ccx.items.insert(cid, i);
            ccx.consts.insert(cid, g);
6797 6798
        }
        case (ast.item_mod(?name, ?m, ?mid)) {
6799
            ccx.items.insert(mid, i);
6800
        }
6801
        case (ast.item_ty(_, _, _, ?did, _)) {
6802
            ccx.items.insert(did, i);
6803
        }
6804
        case (ast.item_tag(?name, ?variants, ?tps, ?tag_id, _)) {
6805
            ccx.items.insert(tag_id, i);
6806
        }
6807
        case (_) {}
6808 6809 6810
    }
}

6811 6812 6813
fn collect_item_2(@crate_ctxt ccx, @walk_ctxt wcx, @ast.item i) {
    enter_item(wcx, i);

6814
    alt (i.node) {
6815
        case (ast.item_fn(?name, ?f, ?tps, ?fid, ?ann)) {
6816 6817 6818
            ccx.items.insert(fid, i);
            if (!ccx.obj_methods.contains_key(fid)) {
                decl_fn_and_pair(ccx, wcx.path, "fn", tps, ann, fid);
6819
            }
6820
        }
6821
        case (ast.item_obj(?name, ?ob, ?tps, ?oid, ?ann)) {
6822 6823
            ccx.items.insert(oid.ctor, i);
            decl_fn_and_pair(ccx, wcx.path, "obj_ctor", tps, ann, oid.ctor);
6824
            for (@ast.method m in ob.methods) {
6825
                ccx.obj_methods.insert(m.node.id, ());
6826
            }
6827
        }
6828
        case (_) {}
6829 6830 6831
    }
}

6832
fn collect_items(@crate_ctxt ccx, @ast.crate crate) {
6833
    auto wcx = new_walk_ctxt();
6834
    auto visitor0 = walk.default_visitor();
6835
    auto visitor1 = rec(visit_native_item_pre =
6836 6837 6838 6839 6840 6841 6842 6843 6844
                          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);
6845 6846
}

6847 6848
fn collect_tag_ctor(@crate_ctxt ccx, @walk_ctxt wcx, @ast.item i) {
    enter_item(wcx, i);
6849 6850

    alt (i.node) {
6851
        case (ast.item_tag(_, ?variants, ?tps, _, _)) {
6852
            for (ast.variant variant in variants) {
6853
                if (_vec.len[ast.variant_arg](variant.node.args) != 0u) {
6854
                    decl_fn_and_pair(ccx, wcx.path + vec(variant.node.name),
6855 6856
                                     "tag", tps, variant.node.ann,
                                     variant.node.id);
6857 6858 6859 6860 6861 6862 6863 6864
                }
            }
        }

        case (_) { /* fall through */ }
    }
}

6865 6866 6867 6868 6869 6870
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);
6871 6872
}

6873 6874
// The constant translation pass.

6875 6876
fn trans_constant(@crate_ctxt ccx, @walk_ctxt wcx, @ast.item it) {
    enter_item(wcx, it);
6877

6878
    alt (it.node) {
6879
        case (ast.item_tag(?ident, ?variants, _, ?tag_id, _)) {
6880
            auto i = 0u;
6881 6882 6883
            auto n_variants = _vec.len[ast.variant](variants);
            while (i < n_variants) {
                auto variant = variants.(i);
6884 6885 6886

                auto discrim_val = C_int(i as int);

6887
                auto s = mangle_name_by_seq(ccx, wcx.path,
6888 6889
                                            #fmt("_rust_tag_discrim_%s_%u",
                                                 ident, i));
6890
                auto discrim_gvar = llvm.LLVMAddGlobal(ccx.llmod, T_int(),
P
Patrick Walton 已提交
6891
                                                       _str.buf(s));
6892 6893 6894 6895

                llvm.LLVMSetInitializer(discrim_gvar, discrim_val);
                llvm.LLVMSetGlobalConstant(discrim_gvar, True);

6896 6897
                ccx.discrims.insert(variant.node.id, discrim_gvar);
                ccx.discrim_symbols.insert(variant.node.id, s);
6898 6899 6900 6901

                i += 1u;
            }
        }
6902 6903 6904 6905 6906

        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);
6907 6908 6909 6910
            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);
6911 6912
        }

6913
        case (_) {}
6914 6915 6916
    }
}

6917 6918 6919 6920 6921 6922
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);
6923 6924
}

6925 6926 6927 6928 6929 6930 6931 6932 6933 6934

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

6935 6936 6937 6938
fn p2i(ValueRef v) -> ValueRef {
    ret llvm.LLVMConstPtrToInt(v, T_int());
}

6939 6940 6941 6942
fn i2p(ValueRef v, TypeRef t) -> ValueRef {
    ret llvm.LLVMConstIntToPtr(v, t);
}

6943
fn trans_exit_task_glue(@glue_fns glues,
6944
                        &hashmap[str, ValueRef] externs,
6945
                        type_names tn, ModuleRef llmod) {
6946 6947 6948
    let vec[TypeRef] T_args = vec();
    let vec[ValueRef] V_args = vec();

6949
    auto llfn = glues.exit_task_glue;
6950
    let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 4u);
6951

6952 6953
    auto entrybb = llvm.LLVMAppendBasicBlock(llfn, _str.buf("entry"));
    auto build = new_builder(entrybb);
6954
    auto tptr = build.PtrToInt(lltaskptr, T_int());
6955
    auto V_args2 = vec(tptr) + V_args;
6956 6957
    trans_native_call(build, glues, lltaskptr,
                      externs, tn, llmod, "upcall_exit", true, V_args2);
6958
    build.RetVoid();
6959 6960
}

6961
fn create_typedefs(@crate_ctxt cx) {
6962 6963 6964
    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));
6965 6966
}

6967
fn create_crate_constant(ValueRef crate_ptr, @glue_fns glues) {
6968

6969
    let ValueRef crate_addr = p2i(crate_ptr);
6970 6971

    let ValueRef activate_glue_off =
6972
        llvm.LLVMConstSub(p2i(glues.activate_glue), crate_addr);
6973 6974

    let ValueRef yield_glue_off =
6975
        llvm.LLVMConstSub(p2i(glues.yield_glue), crate_addr);
6976

6977
    let ValueRef exit_task_glue_off =
6978
        llvm.LLVMConstSub(p2i(glues.exit_task_glue), crate_addr);
6979 6980 6981

    let ValueRef crate_val =
        C_struct(vec(C_null(T_int()),     // ptrdiff_t image_base_off
6982
                     p2i(crate_ptr),      // uintptr_t self_addr
6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993
                     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
6994
                     C_null(T_int()),     // int n_libs
6995
                     C_int(abi.abi_x86_rustc_fastcall) // uintptr_t abi_tag
6996 6997
                     ));

6998
    llvm.LLVMSetInitializer(crate_ptr, crate_val);
6999 7000
}

7001 7002 7003 7004
fn find_main_fn(@crate_ctxt cx) -> ValueRef {
    auto e = sep() + "main";
    let ValueRef v = C_nil();
    let uint n = 0u;
7005 7006
    for each (@tup(ast.def_id, str) i in cx.item_symbols.items()) {
        if (_str.ends_with(i._1, e)) {
7007
            n += 1u;
7008
            v = cx.item_ids.get(i._0);
7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024
        }
    }
    alt (n) {
        case (0u) {
            cx.sess.err("main fn not found");
        }
        case (1u) {
            ret v;
        }
        case (_) {
            cx.sess.err("multiple main fns found");
        }
    }
    fail;
}

7025
fn trans_main_fn(@local_ctxt cx, ValueRef llcrate, ValueRef crate_map) {
7026
    auto T_main_args = vec(T_int(), T_int());
7027
    auto T_rust_start_args = vec(T_int(), T_int(), T_int(), T_int(), T_int());
7028

7029 7030 7031 7032 7033 7034 7035
    auto main_name;
    if (_str.eq(std.os.target_os(), "win32")) {
        main_name = "WinMain@16";
    } else {
        main_name = "main";
    }

7036
    auto llmain =
7037
        decl_cdecl_fn(cx.ccx.llmod, main_name, T_fn(T_main_args, T_int()));
7038

7039
    auto llrust_start = decl_cdecl_fn(cx.ccx.llmod, "rust_start",
7040
                                      T_fn(T_rust_start_args, T_int()));
7041 7042 7043

    auto llargc = llvm.LLVMGetParam(llmain, 0u);
    auto llargv = llvm.LLVMGetParam(llmain, 1u);
7044
    auto llrust_main = find_main_fn(cx.ccx);
7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055

    //
    // 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(""));
7056
    auto b = new_builder(llbb);
7057

7058 7059
    auto start_args = vec(p2i(llrust_main), p2i(llcrate), llargc, llargv,
                          p2i(crate_map));
7060 7061 7062 7063

    b.Ret(b.Call(llrust_start, start_args));
}

7064 7065
fn declare_intrinsics(ModuleRef llmod) -> hashmap[str,ValueRef] {

7066
    let vec[TypeRef] T_trap_args = vec();
7067 7068 7069 7070 7071 7072
    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;
7073 7074
}

7075 7076

fn trace_str(@block_ctxt cx, str s) {
7077
    trans_upcall(cx, "upcall_trace_str", vec(p2i(C_cstr(cx.fcx.lcx.ccx, s))));
7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089
}

fn trace_word(@block_ctxt cx, ValueRef v) {
    trans_upcall(cx, "upcall_trace_word", vec(v));
}

fn trace_ptr(@block_ctxt cx, ValueRef v) {
    trace_word(cx, cx.build.PtrToInt(v, T_int()));
}

fn trap(@block_ctxt bcx) {
    let vec[ValueRef] v = vec();
7090
    bcx.build.Call(bcx.fcx.lcx.ccx.intrinsics.get("llvm.trap"), v);
7091
}
7092 7093 7094 7095
tag output_type {
    output_type_none;
    output_type_bitcode;
    output_type_assembly;
R
Rafael Ávila de Espíndola 已提交
7096 7097 7098
    output_type_object;
}

7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111
// 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 已提交
7112 7113 7114 7115 7116 7117 7118 7119
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;
7120
}
7121

7122 7123
fn run_passes(ModuleRef llmod, bool opt, bool verify, bool save_temps,
              str output, output_type ot) {
7124 7125 7126
    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 已提交
7127

7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144
    // 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 已提交
7145 7146 7147 7148 7149 7150 7151 7152
    // 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
7153 7154
        llvm.LLVMAddTypeBasedAliasAnalysisPass(fpm.llpm);
        llvm.LLVMAddBasicAliasAnalysisPass(fpm.llpm);
R
Rafael Ávila de Espíndola 已提交
7155 7156
        llvm.LLVMAddCFGSimplificationPass(fpm.llpm);
        llvm.LLVMAddScalarReplAggregatesPass(fpm.llpm);
7157
        llvm.LLVMAddEarlyCSEPass(fpm.llpm);
R
Rafael Ávila de Espíndola 已提交
7158 7159 7160 7161

        llvm.LLVMRunPassManager(fpm.llpm, llmod);

        // createStandardModulePasses
7162 7163
        llvm.LLVMAddTypeBasedAliasAnalysisPass(pm.llpm);
        llvm.LLVMAddBasicAliasAnalysisPass(pm.llpm);
R
Rafael Ávila de Espíndola 已提交
7164 7165 7166 7167 7168 7169 7170
        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);
7171
        llvm.LLVMAddFunctionAttrsPass(pm.llpm);
7172 7173
        llvm.LLVMAddScalarReplAggregatesPassSSA(pm.llpm);
        llvm.LLVMAddEarlyCSEPass(pm.llpm);
R
Rafael Ávila de Espíndola 已提交
7174 7175
        llvm.LLVMAddSimplifyLibCallsPass(pm.llpm);
        llvm.LLVMAddJumpThreadingPass(pm.llpm);
7176
        llvm.LLVMAddCorrelatedValuePropagationPass(pm.llpm);
R
Rafael Ávila de Espíndola 已提交
7177 7178 7179 7180 7181 7182 7183 7184 7185 7186
        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);
7187
        llvm.LLVMAddLoopIdiomPass(pm.llpm);
R
Rafael Ávila de Espíndola 已提交
7188 7189 7190 7191 7192 7193 7194 7195
        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);
7196
        llvm.LLVMAddCorrelatedValuePropagationPass(pm.llpm);
R
Rafael Ávila de Espíndola 已提交
7197 7198 7199 7200 7201 7202 7203
        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 已提交
7204 7205 7206 7207

    if (verify) {
        llvm.LLVMAddVerifierPass(pm.llpm);
    }
7208

7209
    // TODO: Write .s if -c was specified and -save-temps was on.
R
Rafael Ávila de Espíndola 已提交
7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220
    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;
        }

7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233
        // 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 已提交
7234 7235 7236 7237
        llvm.LLVMRustWriteOutputFile(pm.llpm, llmod,
                                     _str.buf(x86.get_target_triple()),
                                     _str.buf(output),
                                     FileType);
7238
        llvm.LLVMDisposeModule(llmod);
7239 7240 7241
        ret;
    }

R
Rafael Ávila de Espíndola 已提交
7242
    llvm.LLVMRunPassManager(pm.llpm, llmod);
7243 7244 7245

    llvm.LLVMWriteBitcodeToFile(llmod, _str.buf(output));
    llvm.LLVMDisposeModule(llmod);
7246 7247
}

7248
fn decl_no_op_type_glue(ModuleRef llmod, type_names tn) -> ValueRef {
7249
    auto ty = T_fn(vec(T_taskptr(tn), T_ptr(T_i8())), T_void());
7250 7251 7252 7253
    ret decl_fastcall_fn(llmod, abi.no_op_type_glue_name(), ty);
}

fn make_no_op_type_glue(ValueRef fun) {
7254 7255
    auto bb_name = _str.buf("_rust_no_op_type_glue_bb");
    auto llbb = llvm.LLVMAppendBasicBlock(fun, bb_name);
7256
    new_builder(llbb).RetVoid();
7257 7258
}

7259
fn decl_memcpy_glue(ModuleRef llmod) -> ValueRef {
7260 7261 7262
    auto p8 = T_ptr(T_i8());

    auto ty = T_fn(vec(p8, p8, T_int()), T_void());
7263 7264
    ret decl_fastcall_fn(llmod, abi.memcpy_glue_name(), ty);
}
7265

7266 7267 7268 7269
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.
7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302
    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();
}

7303
fn decl_bzero_glue(ModuleRef llmod) -> ValueRef {
7304 7305 7306
    auto p8 = T_ptr(T_i8());

    auto ty = T_fn(vec(p8, T_int()), T_void());
7307 7308
    ret decl_fastcall_fn(llmod, abi.bzero_glue_name(), ty);
}
7309

7310
fn make_bzero_glue(ValueRef fun) -> ValueRef {
7311
    // We're not using the LLVM memset intrinsic. Same as with memcpy.
7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343
    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;
}

7344
fn make_vec_append_glue(ModuleRef llmod, type_names tn) -> ValueRef {
7345
    /*
7346
     * Args to vec_append_glue:
7347 7348 7349 7350 7351 7352 7353 7354 7355 7356
     *
     *   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.
     *
7357
     *   3. Dst vec ptr (i.e. ptr to ptr to rust_vec).
7358 7359
     *
     *   4. Src vec (i.e. ptr to rust_vec).
7360
     *
7361
     *   5. Flag indicating whether to skip trailing null on dst.
7362 7363 7364 7365 7366 7367
     *
     */

    auto ty = T_fn(vec(T_taskptr(tn),
                       T_ptr(T_tydesc(tn)),
                       T_ptr(T_tydesc(tn)),
7368 7369 7370
                       T_ptr(T_opaque_vec_ptr()),
                       T_opaque_vec_ptr(), T_bool()),
                   T_void());
7371

7372
    auto llfn = decl_fastcall_fn(llmod, abi.vec_append_glue_name(), ty);
7373 7374 7375
    ret llfn;
}

7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414

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

7415
fn trans_vec_append_glue(@local_ctxt cx) {
7416

7417
    auto llfn = cx.ccx.glues.vec_append_glue;
7418 7419 7420 7421

    let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 0u);
    let ValueRef llvec_tydesc = llvm.LLVMGetParam(llfn, 1u);
    let ValueRef llelt_tydesc = llvm.LLVMGetParam(llfn, 2u);
7422 7423 7424
    let ValueRef lldst_vec_ptr = llvm.LLVMGetParam(llfn, 3u);
    let ValueRef llsrc_vec = llvm.LLVMGetParam(llfn, 4u);
    let ValueRef llskipnull = llvm.LLVMGetParam(llfn, 5u);
7425

7426 7427 7428
    let BasicBlockRef llallocas =
        llvm.LLVMAppendBasicBlock(llfn, _str.buf("allocas"));

7429 7430 7431 7432
    auto fcx = @rec(llfn=llfn,
                    lltaskptr=lltaskptr,
                    llenv=C_null(T_ptr(T_nil())),
                    llretptr=C_null(T_ptr(T_nil())),
7433
                    mutable llallocas = llallocas,
7434
                    mutable llself=none[self_vt],
7435 7436 7437 7438
                    mutable lliterbody=none[ValueRef],
                    llargs=new_def_hash[ValueRef](),
                    llobjfields=new_def_hash[ValueRef](),
                    lllocals=new_def_hash[ValueRef](),
7439
                    llupvars=new_def_hash[ValueRef](),
7440
                    mutable lltydescs=_vec.empty[ValueRef](),
7441
                    lcx=cx);
7442 7443

    auto bcx = new_top_block_ctxt(fcx);
7444
    auto lltop = bcx.llbb;
7445

7446 7447
    auto lldst_vec = bcx.build.Load(lldst_vec_ptr);

7448 7449
    // 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.
7450

7451
    auto llcopy_dst_ptr = alloca(bcx, T_int());
7452 7453
    auto llnew_vec_res =
        trans_upcall(bcx, "upcall_vec_grow",
7454 7455 7456
                     vec(vp2i(bcx, lldst_vec),
                         vec_fill_adjusted(bcx, llsrc_vec, llskipnull),
                         vp2i(bcx, llcopy_dst_ptr),
7457 7458 7459
                         vp2i(bcx, llvec_tydesc)));

    bcx = llnew_vec_res.bcx;
7460 7461
    auto llnew_vec = vi2p(bcx, llnew_vec_res.val,
                          T_opaque_vec_ptr());
7462
    llvm.LLVMSetValueName(llnew_vec, _str.buf("llnew_vec"));
7463

7464 7465
    auto copy_dst_cx = new_sub_block_ctxt(bcx, "copy new <- dst");
    auto copy_src_cx = new_sub_block_ctxt(bcx, "copy new <- src");
7466

7467
    auto pp0 = alloca(bcx, T_ptr(T_i8()));
7468
    bcx.build.Store(vec_p1_adjusted(bcx, llnew_vec, llskipnull), pp0);
7469
    llvm.LLVMSetValueName(pp0, _str.buf("pp0"));
7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484

    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));
7485
        llvm.LLVMSetValueName(src_lim, _str.buf("src_lim"));
7486 7487 7488 7489 7490

        auto elt_llsz =
            cx.build.Load(cx.build.GEP(elt_tydesc,
                                       vec(C_int(0),
                                           C_int(abi.tydesc_field_size))));
7491
        llvm.LLVMSetValueName(elt_llsz, _str.buf("elt_llsz"));
7492 7493

        fn take_one(ValueRef elt_tydesc,
7494 7495 7496
                    @block_ctxt cx,
                    ValueRef dst, ValueRef src) -> result {
            call_tydesc_glue_full(cx, src,
7497
                                  elt_tydesc,
7498
                                  abi.tydesc_field_take_glue);
7499
            ret res(cx, src);
7500 7501
        }

7502
        auto bcx = iter_sequence_raw(cx, dst, src, src_lim,
7503
                                     elt_llsz, bind take_one(elt_tydesc,
7504
                                                             _, _, _)).bcx;
7505 7506 7507 7508 7509

        ret call_memcpy(bcx, dst, src, n_bytes);
    }

    // Copy any dst elements in, omitting null if doing str.
7510

7511
    auto n_bytes = vec_fill_adjusted(copy_dst_cx, lldst_vec, llskipnull);
7512 7513
    llvm.LLVMSetValueName(n_bytes, _str.buf("n_bytes"));

7514 7515
    copy_dst_cx = copy_elts(copy_dst_cx,
                            llelt_tydesc,
7516
                            vec_p0(copy_dst_cx, llnew_vec),
7517 7518 7519
                            vec_p0(copy_dst_cx, lldst_vec),
                            n_bytes).bcx;

7520 7521 7522 7523
    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);
7524 7525 7526 7527 7528 7529 7530 7531 7532 7533 7534 7535
    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,
7536 7537 7538
                 copy_src_cx.build.Add(vec_fill_adjusted(copy_src_cx,
                                                         llnew_vec,
                                                         llskipnull),
7539
                                        n_bytes));
7540 7541 7542 7543

    // 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();
7544 7545 7546

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


7550 7551 7552
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()),
7553 7554
             /*
              * Note: the signature passed to decl_cdecl_fn here looks unusual
7555
              * because it is. It corresponds neither to a native signature
7556 7557 7558 7559 7560 7561 7562 7563
              * 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(),
7564
                                            T_fn(vec(T_int(),
7565
                                                     T_int(),
7566 7567 7568
                                                     T_int(),
                                                     T_int(),
                                                     T_taskptr(tn)),
7569
                                                 T_void())),
7570

7571 7572
             native_glues_rust =
             _vec.init_fn[ValueRef](bind decl_native_glue(llmod, tn, true,
7573
                                                          _),
7574 7575 7576
                                    abi.n_native_glues + 1 as uint),
             native_glues_cdecl =
             _vec.init_fn[ValueRef](bind decl_native_glue(llmod, tn, false,
7577
                                                          _),
7578
                                    abi.n_native_glues + 1 as uint),
7579 7580 7581
             no_op_type_glue = decl_no_op_type_glue(llmod, tn),
             memcpy_glue = decl_memcpy_glue(llmod),
             bzero_glue = decl_bzero_glue(llmod),
7582
             vec_append_glue = make_vec_append_glue(llmod, tn));
7583 7584
}

7585
fn make_common_glue(str output, bool optimize, bool verify, bool save_temps,
7586
                    output_type ot) {
7587 7588 7589
    // 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.
7590 7591 7592 7593
    auto llmod =
        llvm.LLVMModuleCreateWithNameInContext(_str.buf("rust_out"),
                                               llvm.LLVMGetGlobalContext());

7594 7595
    llvm.LLVMSetDataLayout(llmod, _str.buf(x86.get_data_layout()));
    llvm.LLVMSetTarget(llmod, _str.buf(x86.get_target_triple()));
7596
    auto td = mk_target_data(x86.get_data_layout());
7597
    auto tn = mk_type_names();
7598 7599
    let ValueRef crate_ptr =
        llvm.LLVMAddGlobal(llmod, T_crate(tn), _str.buf("rust_crate"));
7600

7601 7602
    auto intrinsics = declare_intrinsics(llmod);

7603
    llvm.LLVMSetModuleInlineAsm(llmod, _str.buf(x86.get_module_asm()));
7604

7605
    auto glues = make_glues(llmod, tn);
7606
    create_crate_constant(crate_ptr, glues);
7607
    make_memcpy_glue(glues.memcpy_glue);
7608
    make_bzero_glue(glues.bzero_glue);
7609 7610 7611

    trans_exit_task_glue(glues, new_str_hash[ValueRef](), tn, llmod);

7612
    run_passes(llmod, optimize, verify, save_temps, output, ot);
7613 7614
}

7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662
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;
}

7663
fn trans_crate(session.session sess, @ast.crate crate, ty.ctxt tcx,
7664
               &ty.type_cache type_cache, str output, bool shared,
7665
               bool optimize, bool verify, bool save_temps, output_type ot) {
7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676
    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"));

7677
    auto intrinsics = declare_intrinsics(llmod);
7678

7679
    auto glues = make_glues(llmod, tn);
7680 7681
    auto hasher = ty.hash_ty;
    auto eqer = ty.eq_ty;
7682 7683 7684
    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);
7685
    auto sha1s = map.mk_hashmap[ty.t,str](hasher, eqer);
7686
    auto abbrevs = map.mk_hashmap[ty.t,metadata.ty_abbrev](hasher, eqer);
7687

7688 7689 7690 7691 7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 7706
    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,
7707
                    module_data = new_str_hash[ValueRef](),
7708
                    lltypes = lltypes,
7709 7710
                    glues = glues,
                    names = namegen(0),
7711
                    sha = std.sha1.mk_sha1(),
7712
                    type_sha1s = sha1s,
7713
                    type_abbrevs = abbrevs,
7714
                    tcx = tcx);
7715
    auto cx = new_local_ctxt(ccx);
7716

7717
    create_typedefs(ccx);
7718

7719
    collect_items(ccx, crate);
7720 7721
    collect_tag_ctors(ccx, crate);
    trans_constants(ccx, crate);
7722
    trans_mod(cx, crate.node.module);
7723
    trans_vec_append_glue(cx);
7724
    auto crate_map = create_crate_map(ccx);
7725
    if (!shared) {
7726
        trans_main_fn(cx, crate_ptr, crate_map);
7727
    }
7728

7729
    // Translate the metadata.
7730
    middle.metadata.write_metadata(cx.ccx, crate);
7731

7732
    run_passes(llmod, optimize, verify, save_temps, output, ot);
7733 7734 7735 7736 7737 7738 7739 7740 7741
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
7742
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
7743 7744
// End:
//