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

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

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

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

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

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

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

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

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

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

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

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

111 112 113 114 115 116

tag block_kind {
    SCOPE_BLOCK;
    NON_SCOPE_BLOCK;
}

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

124 125 126 127 128 129 130 131
// 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);
}

132

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

136 137 138 139
fn sep() -> str {
    ret "_";
}

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

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

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

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


// LLVM type constructors.

160 161 162 163 164 165 166 167 168 169 170
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.
171 172 173
    ret llvm.LLVMVoidType();
}

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

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

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

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

fn T_i32() -> TypeRef {
192 193 194
    ret llvm.LLVMInt32Type();
}

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

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

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

207 208 209 210
fn T_bool() -> TypeRef {
    ret T_i1();
}

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

216 217 218 219 220
fn T_float() -> TypeRef {
    // FIXME: switch on target type.
    ret T_f64();
}

221 222 223 224
fn T_char() -> TypeRef {
    ret T_i32();
}

225 226 227 228
fn T_fn(vec[TypeRef] inputs, TypeRef output) -> TypeRef {
    ret llvm.LLVMFunctionType(output,
                              _vec.buf[TypeRef](inputs),
                              _vec.len[TypeRef](inputs),
229 230 231
                              False);
}

232
fn T_fn_pair(type_names tn, TypeRef tfn) -> TypeRef {
233
    ret T_struct(vec(T_ptr(tfn),
234
                     T_opaque_closure_ptr(tn)));
235 236
}

237 238 239 240 241 242 243 244 245 246 247 248 249 250
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();
}

251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
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;
268 269
}

270 271 272 273 274 275
fn T_glue_fn(type_names tn) -> TypeRef {
    auto s = "glue_fn";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }

276 277
    // Bit of a kludge: pick the fn typeref out of the tydesc..
    let vec[TypeRef] tydesc_elts = _vec.init_elt[TypeRef](T_nil(), 10u);
278
    llvm.LLVMGetStructElementTypes(T_tydesc(tn),
279
                                   _vec.buf[TypeRef](tydesc_elts));
280 281 282 283 284
    auto t =
        llvm.LLVMGetElementType
        (tydesc_elts.(abi.tydesc_field_drop_glue_off));
    tn.associate(s, t);
    ret t;
285 286
}

287 288 289 290 291 292
fn T_tydesc(type_names tn) -> TypeRef {

    auto s = "tydesc";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }
293 294 295

    auto th = mk_type_handle();
    auto abs_tydesc = llvm.LLVMResolveTypeHandle(th.llth);
296
    auto tydescpp = T_ptr(T_ptr(abs_tydesc));
297
    auto pvoid = T_ptr(T_i8());
298
    auto glue_fn_ty = T_ptr(T_fn(vec(T_ptr(T_nil()),
299
                                     T_taskptr(tn),
300
                                     T_ptr(T_nil()),
301
                                     tydescpp,
302
                                     pvoid), T_void()));
303
    auto tydesc = T_struct(vec(tydescpp,          // first_param
304 305 306 307 308 309 310 311 312 313 314
                               T_int(),           // size
                               T_int(),           // align
                               glue_fn_ty,        // take_glue_off
                               glue_fn_ty,        // drop_glue_off
                               glue_fn_ty,        // free_glue_off
                               glue_fn_ty,        // sever_glue_off
                               glue_fn_ty,        // mark_glue_off
                               glue_fn_ty,        // obj_drop_glue_off
                               glue_fn_ty));      // is_stateful

    llvm.LLVMRefineType(abs_tydesc, tydesc);
315 316 317
    auto t = llvm.LLVMResolveTypeHandle(th.llth);
    tn.associate(s, t);
    ret t;
318 319
}

320 321 322 323
fn T_array(TypeRef t, uint n) -> TypeRef {
    ret llvm.LLVMArrayType(t, n);
}

324 325 326 327 328
fn T_vec(TypeRef t) -> TypeRef {
    ret T_struct(vec(T_int(),       // Refcount
                     T_int(),       // Alloc
                     T_int(),       // Fill
                     T_array(t, 0u) // Body elements
329 330 331
                     ));
}

332 333 334 335
fn T_opaque_vec_ptr() -> TypeRef {
    ret T_ptr(T_vec(T_int()));
}

336 337
fn T_str() -> TypeRef {
    ret T_vec(T_i8());
338 339
}

340 341 342 343
fn T_box(TypeRef t) -> TypeRef {
    ret T_struct(vec(T_int(), t));
}

B
Brian Anderson 已提交
344 345 346 347 348 349 350 351
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
}

352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
fn T_crate(type_names tn) -> TypeRef {
    auto s = "crate";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }

    auto t = T_struct(vec(T_int(),      // ptrdiff_t image_base_off
                          T_int(),      // uintptr_t self_addr
                          T_int(),      // ptrdiff_t debug_abbrev_off
                          T_int(),      // size_t debug_abbrev_sz
                          T_int(),      // ptrdiff_t debug_info_off
                          T_int(),      // size_t debug_info_sz
                          T_int(),      // size_t activate_glue_off
                          T_int(),      // size_t yield_glue_off
                          T_int(),      // size_t unwind_glue_off
                          T_int(),      // size_t gc_glue_off
                          T_int(),      // size_t main_exit_task_glue_off
                          T_int(),      // int n_rust_syms
                          T_int(),      // int n_c_syms
371 372
                          T_int(),      // int n_libs
                          T_int()       // uintptr_t abi_tag
373 374 375
                          ));
    tn.associate(s, t);
    ret t;
376 377
}

378 379
fn T_taskptr(type_names tn) -> TypeRef {
    ret T_ptr(T_task(tn));
380 381
}

382 383
// This type must never be used directly; it must always be cast away.
fn T_typaram(type_names tn) -> TypeRef {
384 385 386 387 388
    auto s = "typaram";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }

389
    auto t = T_i8();
390 391
    tn.associate(s, t);
    ret t;
392 393
}

394 395 396 397
fn T_typaram_ptr(type_names tn) -> TypeRef {
    ret T_ptr(T_typaram(tn));
}

398 399
fn T_closure_ptr(type_names tn,
                 TypeRef lltarget_ty,
400 401
                 TypeRef llbindings_ty,
                 uint n_ty_params) -> TypeRef {
402 403 404 405

    // 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.
406
    ret T_ptr(T_box(T_struct(vec(T_ptr(T_tydesc(tn)),
407
                                 lltarget_ty,
408 409
                                 llbindings_ty,
                                 T_captured_tydescs(tn, n_ty_params))
410 411 412
                             )));
}

413 414 415 416 417 418 419
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()))),
420 421
                           T_nil(),
                           0u);
422 423
    tn.associate(s, t);
    ret t;
424 425
}

426 427 428 429 430 431 432 433 434 435 436 437
fn T_tag(type_names tn, uint size) -> TypeRef {
    auto s = "tag_" + _uint.to_str(size, 10u);
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }
    auto t = T_struct(vec(T_int(), T_array(T_i8(), size)));
    tn.associate(s, t);
    ret t;
}

fn T_opaque_tag(type_names tn) -> TypeRef {
    auto s = "tag";
438 439 440
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }
441
    auto t = T_struct(vec(T_int(), T_i8()));
442 443 444 445
    tn.associate(s, t);
    ret t;
}

446 447 448 449
fn T_opaque_tag_ptr(type_names tn) -> TypeRef {
    ret T_ptr(T_opaque_tag(tn));
}

450 451
fn T_captured_tydescs(type_names tn, uint n) -> TypeRef {
    ret T_struct(_vec.init_elt[TypeRef](T_ptr(T_tydesc(tn)), n));
452 453
}

454 455 456 457 458 459 460
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)));
    }
461

462
    ret T_ptr(T_box(T_obj(tn, n_captured_tydescs)));
463 464
}

465
fn T_opaque_obj_ptr(type_names tn) -> TypeRef {
466
    ret T_obj_ptr(tn, 0u);
467 468
}

469

470 471 472 473
// 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.
474
fn type_of(@crate_ctxt cx, @ty.t t) -> TypeRef {
475 476 477 478 479 480
    if (ty.type_has_dynamic_size(t)) {
        log "type_of() called on a type with dynamic size: " +
            ty.ty_to_str(t);
        fail;
    }

481
    ret type_of_inner(cx, t, false);
482 483
}

484 485 486 487 488 489
fn type_of_explicit_args(@crate_ctxt cx,
                     vec[ty.arg] inputs) -> vec[TypeRef] {
    let vec[TypeRef] atys = vec();
    for (ty.arg arg in inputs) {
        if (ty.type_has_dynamic_size(arg.ty)) {
            check (arg.mode == ast.alias);
490
            atys += vec(T_typaram_ptr(cx.tn));
491
        } else {
492
            let TypeRef t;
493 494
            alt (arg.mode) {
                case (ast.alias) {
495 496 497 498
                    t = T_ptr(type_of_inner(cx, arg.ty, true));
                }
                case (_) {
                    t = type_of_inner(cx, arg.ty, false);
499 500
                }
            }
501
            atys += vec(t);
502 503 504 505
        }
    }
    ret atys;
}
506 507 508 509 510 511 512 513

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

514
fn type_of_fn_full(@crate_ctxt cx,
515
                   ast.proto proto,
516 517
                   option.t[TypeRef] obj_self,
                   vec[ty.arg] inputs,
518 519
                   @ty.t output,
                   uint ty_param_count) -> TypeRef {
520
    let vec[TypeRef] atys = vec();
521

522
    // Arg 0: Output pointer.
523
    if (ty.type_has_dynamic_size(output)) {
524
        atys += vec(T_typaram_ptr(cx.tn));
525
    } else {
526
        atys += vec(T_ptr(type_of_inner(cx, output, false)));
527 528
    }

529
    // Arg 1: Task pointer.
530
    atys += vec(T_taskptr(cx.tn));
531 532

    // Arg 2: Env (closure-bindings / self-obj)
533 534 535
    alt (obj_self) {
        case (some[TypeRef](?t)) {
            check (t as int != 0);
536
            atys += vec(t);
537
        }
538
        case (_) {
539
            atys += vec(T_opaque_closure_ptr(cx.tn));
540
        }
541 542
    }

543 544 545 546
    // Args >3: ty params, if not acquired via capture...
    if (obj_self == none[TypeRef]) {
        auto i = 0u;
        while (i < ty_param_count) {
547
            atys += vec(T_ptr(T_tydesc(cx.tn)));
548 549
            i += 1u;
        }
550 551
    }

552
    if (proto == ast.proto_iter) {
553 554 555
        // 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.
556 557
        atys +=
            vec(T_fn_pair(cx.tn,
558
                          type_of_fn_full(cx, ast.proto_fn, none[TypeRef],
559
                                          vec(rec(mode=ast.val, ty=output)),
560
                                          plain_ty(ty.ty_nil), 0u)));
561 562
    }

563
    // ... then explicit args.
564
    atys += type_of_explicit_args(cx, inputs);
565

566
    ret T_fn(atys, llvm.LLVMVoidType());
567 568
}

569
fn type_of_fn(@crate_ctxt cx,
570
              ast.proto proto,
571 572 573 574 575
              vec[ty.arg] inputs,
              @ty.t output,
              uint ty_param_count) -> TypeRef {
    ret type_of_fn_full(cx, proto, none[TypeRef], inputs, output,
                        ty_param_count);
576 577
}

578 579
fn type_of_native_fn(@crate_ctxt cx, ast.native_abi abi,
                     vec[ty.arg] inputs,
580 581
                     @ty.t output,
                     uint ty_param_count) -> TypeRef {
582 583
    let vec[TypeRef] atys = vec();
    if (abi == ast.native_abi_rust) {
584
        atys += vec(T_taskptr(cx.tn));
585 586 587
        auto t = ty.ty_native_fn(abi, inputs, output);
        auto i = 0u;
        while (i < ty_param_count) {
588
            atys += vec(T_ptr(T_tydesc(cx.tn)));
589 590 591 592
            i += 1u;
        }
    }
    atys += type_of_explicit_args(cx, inputs);
593
    ret T_fn(atys, type_of_inner(cx, output, false));
594 595
}

596
fn type_of_inner(@crate_ctxt cx, @ty.t t, bool boxed) -> TypeRef {
597 598
    let TypeRef llty = 0 as TypeRef;

599
    alt (t.struct) {
600 601 602 603
        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(); }
604
        case (ty.ty_float) { llty = T_float(); }
605
        case (ty.ty_uint) { llty = T_int(); }
606
        case (ty.ty_machine(?tm)) {
607
            alt (tm) {
608 609 610 611 612 613 614 615 616 617
                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(); }
618 619
            }
        }
620 621
        case (ty.ty_char) { llty = T_char(); }
        case (ty.ty_str) { llty = T_ptr(T_str()); }
622 623 624 625 626 627 628
        case (ty.ty_tag(_, _)) {
            if (boxed) {
                llty = T_opaque_tag(cx.tn);
            } else {
                auto size = static_size_of_tag(cx, t);
                llty = T_tag(cx.tn, size);
            }
629
        }
630 631
        case (ty.ty_box(?mt)) {
            llty = T_ptr(T_box(type_of_inner(cx, mt.ty, true)));
632
        }
633 634
        case (ty.ty_vec(?mt)) {
            llty = T_ptr(T_vec(type_of_inner(cx, mt.ty, true)));
635
        }
B
Brian Anderson 已提交
636 637 638 639 640 641
        case (ty.ty_port(?t)) {
            llty = T_ptr(T_port(type_of_inner(cx, t, true)));
        }
        case (ty.ty_chan(?t)) {
            llty = T_ptr(T_chan(type_of_inner(cx, t, true)));
        }
642
        case (ty.ty_tup(?elts)) {
643
            let vec[TypeRef] tys = vec();
644 645
            for (ty.mt elt in elts) {
                tys += vec(type_of_inner(cx, elt.ty, boxed));
646
            }
647
            llty = T_struct(tys);
648
        }
649
        case (ty.ty_rec(?fields)) {
650
            let vec[TypeRef] tys = vec();
651
            for (ty.field f in fields) {
652
                tys += vec(type_of_inner(cx, f.mt.ty, boxed));
653
            }
654
            llty = T_struct(tys);
655
        }
656
        case (ty.ty_fn(?proto, ?args, ?out)) {
657
            llty = T_fn_pair(cx.tn, type_of_fn(cx, proto, args, out, 0u));
658
        }
659
        case (ty.ty_native_fn(?abi, ?args, ?out)) {
660 661
            auto nft = type_of_native_fn(cx, abi, args, out, 0u);
            llty = T_fn_pair(cx.tn, nft);
662
        }
663
        case (ty.ty_obj(?meths)) {
664 665 666
            auto th = mk_type_handle();
            auto self_ty = llvm.LLVMResolveTypeHandle(th.llth);

667
            let vec[TypeRef] mtys = vec();
668
            for (ty.method m in meths) {
669
                let TypeRef mty =
670
                    type_of_fn_full(cx, m.proto,
671
                                    some[TypeRef](self_ty),
672
                                    m.inputs, m.output, 0u);
673
                mtys += vec(T_ptr(mty));
674
            }
675
            let TypeRef vtbl = T_struct(mtys);
676
            let TypeRef pair = T_struct(vec(T_ptr(vtbl),
677
                                            T_opaque_obj_ptr(cx.tn)));
678

679 680 681
            auto abs_pair = llvm.LLVMResolveTypeHandle(th.llth);
            llvm.LLVMRefineType(abs_pair, pair);
            abs_pair = llvm.LLVMResolveTypeHandle(th.llth);
682
            llty = abs_pair;
683
        }
684
        case (ty.ty_var(_)) {
685
            log "ty_var in trans.type_of";
686 687
            fail;
        }
688
        case (ty.ty_param(_)) {
689
            llty = T_i8();
690
        }
691
        case (ty.ty_type) { llty = T_ptr(T_tydesc(cx.tn)); }
692
    }
693 694 695 696

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

699
fn type_of_arg(@crate_ctxt cx, &ty.arg arg) -> TypeRef {
700 701 702 703 704 705 706 707 708 709 710
    alt (arg.ty.struct) {
        case (ty.ty_param(_)) {
            if (arg.mode == ast.alias) {
                ret T_typaram_ptr(cx.tn);
            }
        }
        case (_) {
            // fall through
        }
    }

711
    auto typ;
712
    if (arg.mode == ast.alias) {
713 714 715
        typ = T_ptr(type_of_inner(cx, arg.ty, true));
    } else {
        typ = type_of_inner(cx, arg.ty, false);
716
    }
717
    ret typ;
718 719
}

720 721 722 723 724 725 726 727 728
// 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 {
729 730 731 732 733 734 735
            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 已提交
736 737
                        c != (' ' as u8) && c != ('\t' as u8) &&
                        c != (';' as u8)) {
738 739 740 741 742
                        auto v = vec(c);
                        result += _str.from_bytes(v);
                    }
                }
            }
743 744 745 746 747
        }
    }
    ret result;
}

748 749 750 751 752 753
// LLVM constant constructors.

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

754
fn C_integral(int i, TypeRef t) -> ValueRef {
755 756 757 758 759 760
    // 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);
    //
761 762 763
    ret llvm.LLVMConstIntOfString(t, _str.buf(istr(i)), 10);
}

764 765 766 767
fn C_float(str s) -> ValueRef {
    ret llvm.LLVMConstRealOfString(T_float(), _str.buf(s));
}

768 769 770 771
fn C_floating(str s, TypeRef t) -> ValueRef {
    ret llvm.LLVMConstRealOfString(t, _str.buf(s));
}

772 773 774 775 776
fn C_nil() -> ValueRef {
    // NB: See comment above in T_void().
    ret C_integral(0, T_i1());
}

777 778
fn C_bool(bool b) -> ValueRef {
    if (b) {
779
        ret C_integral(1, T_bool());
780
    } else {
781
        ret C_integral(0, T_bool());
782 783 784
    }
}

785 786
fn C_int(int i) -> ValueRef {
    ret C_integral(i, T_int());
787 788
}

789 790 791
// 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 {
792
    auto sc = llvm.LLVMConstString(_str.buf(s), _str.byte_len(s), False);
793
    auto g = llvm.LLVMAddGlobal(cx.llmod, val_ty(sc),
794 795
                                _str.buf(cx.names.next("str")));
    llvm.LLVMSetInitializer(g, sc);
796
    llvm.LLVMSetGlobalConstant(g, True);
797 798
    llvm.LLVMSetLinkage(g, lib.llvm.LLVMPrivateLinkage
                        as llvm.Linkage);
799
    ret g;
800 801
}

802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818
// A rust boxed-and-length-annotated string.
fn C_str(@crate_ctxt cx, str s) -> ValueRef {
    auto len = _str.byte_len(s);
    auto box = C_struct(vec(C_int(abi.const_refcount as int),
                            C_int(len + 1u as int), // 'alloc'
                            C_int(len + 1u as int), // 'fill'
                            llvm.LLVMConstString(_str.buf(s),
                                                 len, False)));
    auto g = llvm.LLVMAddGlobal(cx.llmod, val_ty(box),
                                _str.buf(cx.names.next("str")));
    llvm.LLVMSetInitializer(g, box);
    llvm.LLVMSetGlobalConstant(g, True);
    llvm.LLVMSetLinkage(g, lib.llvm.LLVMPrivateLinkage
                        as llvm.Linkage);
    ret llvm.LLVMConstPointerCast(g, T_ptr(T_str()));
}

819 820 821 822 823 824 825 826 827 828 829
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));
}

830 831 832 833 834 835
fn C_struct(vec[ValueRef] elts) -> ValueRef {
    ret llvm.LLVMConstStruct(_vec.buf[ValueRef](elts),
                             _vec.len[ValueRef](elts),
                             False);
}

836
fn decl_fn(ModuleRef llmod, str name, uint cc, TypeRef llty) -> ValueRef {
837 838
    let ValueRef llfn =
        llvm.LLVMAddFunction(llmod, _str.buf(name), llty);
839
    llvm.LLVMSetFunctionCallConv(llfn, cc);
840 841 842
    ret llfn;
}

843 844
fn decl_cdecl_fn(ModuleRef llmod, str name, TypeRef llty) -> ValueRef {
    ret decl_fn(llmod, name, lib.llvm.LLVMCCallConv, llty);
845 846
}

847 848
fn decl_fastcall_fn(ModuleRef llmod, str name, TypeRef llty) -> ValueRef {
    ret decl_fn(llmod, name, lib.llvm.LLVMFastCallConv, llty);
849 850
}

851 852
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()));
853 854
}

855 856
fn decl_upcall_glue(ModuleRef llmod, type_names tn,
                    bool pass_task, uint _n) -> ValueRef {
857 858 859 860
    // It doesn't actually matter what type we come up with here, at the
    // moment, as we cast the upcall function pointers to int before passing
    // them to the indirect upcall-invocation glue.  But eventually we'd like
    // to call them directly, once we have a calling convention worked out.
861
    let int n = _n as int;
862 863
    let str s = abi.upcall_glue_name(n, pass_task);
    let vec[TypeRef] args = vec(T_int()); // callee
864 865
    if (!pass_task) {
        args += vec(T_int()); // taskptr, will not be passed
866 867
    }
    args += _vec.init_elt[TypeRef](T_int(), n as uint);
868

869
    ret decl_fastcall_fn(llmod, s, T_fn(args, T_int()));
870 871
}

872
fn get_upcall(&hashmap[str, ValueRef] upcalls,
873
              ModuleRef llmod, str name, int n_args) -> ValueRef {
874 875
    if (upcalls.contains_key(name)) {
        ret upcalls.get(name);
876
    }
877
    auto inputs = _vec.init_elt[TypeRef](T_int(), n_args as uint);
878
    auto output = T_int();
879 880
    auto f = decl_cdecl_fn(llmod, name, T_fn(inputs, output));
    upcalls.insert(name, f);
881 882 883
    ret f;
}

884
fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args) -> result {
885
    auto cxx = cx.fcx.ccx;
886 887 888 889
    auto lltaskptr = cx.build.PtrToInt(cx.fcx.lltaskptr, T_int());
    auto args2 = vec(lltaskptr) + args;
    auto t = trans_upcall2(cx.build, cxx.glues, lltaskptr,
                           cxx.upcalls, cxx.tn, cxx.llmod, name, true, args2);
890 891 892
    ret res(cx, t);
}

893
fn trans_upcall2(builder b, @glue_fns glues, ValueRef lltaskptr,
894 895
                 &hashmap[str, ValueRef] upcalls,
                 type_names tn, ModuleRef llmod, str name,
896
                 bool pass_task, vec[ValueRef] args) -> ValueRef {
897
    let int n = (_vec.len[ValueRef](args) as int);
898
    let ValueRef llupcall = get_upcall(upcalls, llmod, name, n);
899 900
    llupcall = llvm.LLVMConstPointerCast(llupcall, T_int());

901 902 903 904 905 906
    let ValueRef llglue;
    if (pass_task) {
        llglue = glues.upcall_glues_rust.(n);
    } else {
        llglue = glues.upcall_glues_cdecl.(n);
    }
907
    let vec[ValueRef] call_args = vec(llupcall);
908

909 910 911
    if (!pass_task) {
        call_args += vec(lltaskptr);
    }
912

913
    for (ValueRef a in args) {
914
        call_args += vec(b.ZExtOrBitCast(a, T_int()));
915
    }
916

917
    ret b.FastCall(llglue, call_args);
918 919
}

920
fn trans_non_gc_free(@block_ctxt cx, ValueRef v) -> result {
921
    ret trans_upcall(cx, "upcall_free", vec(vp2i(cx, v),
922
                                            C_int(0)));
923 924
}

925
fn find_scope_cx(@block_ctxt cx) -> @block_ctxt {
926
    if (cx.kind == SCOPE_BLOCK) {
927 928 929 930 931 932 933 934 935 936 937 938
        ret cx;
    }
    alt (cx.parent) {
        case (parent_some(?b)) {
            be find_scope_cx(b);
        }
        case (parent_none) {
            fail;
        }
    }
}

939 940 941 942 943
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);
}

944 945 946 947 948
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);
}

949 950 951 952 953 954
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));
}

955 956 957 958 959
// 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);
}

960
fn llsize_of(TypeRef t) -> ValueRef {
961 962 963
    ret llvm.LLVMConstIntCast(lib.llvm.llvm.LLVMSizeOf(t), T_int(), False);
}

964
fn llalign_of(TypeRef t) -> ValueRef {
965 966 967
    ret llvm.LLVMConstIntCast(lib.llvm.llvm.LLVMAlignOf(t), T_int(), False);
}

968
fn size_of(@block_ctxt cx, @ty.t t) -> result {
969
    if (!ty.type_has_dynamic_size(t)) {
970
        ret res(cx, llsize_of(type_of(cx.fcx.ccx, t)));
971 972 973 974
    }
    ret dynamic_size_of(cx, t);
}

975
fn align_of(@block_ctxt cx, @ty.t t) -> result {
976
    if (!ty.type_has_dynamic_size(t)) {
977
        ret res(cx, llalign_of(type_of(cx.fcx.ccx, t)));
978 979 980 981
    }
    ret dynamic_align_of(cx, t);
}

982 983 984 985 986 987 988 989 990 991 992
// Computes the size of the data part of a non-dynamically-sized tag.
fn static_size_of_tag(@crate_ctxt cx, @ty.t t) -> uint {
    if (ty.type_has_dynamic_size(t)) {
        log "dynamically sized type passed to static_size_of_tag()";
        fail;
    }

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

B
Brian Anderson 已提交
993 994
    auto tid;
    let vec[@ty.t] subtys;
995 996 997 998 999 1000 1001 1002 1003 1004 1005
    alt (t.struct) {
        case (ty.ty_tag(?tid_, ?subtys_)) {
            tid = tid_;
            subtys = subtys_;
        }
        case (_) {
            log "non-tag passed to static_size_of_tag()";
            fail;
        }
    }

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

1009 1010 1011 1012
    // Compute max(variant sizes).
    auto max_size = 0u;
    auto variants = tag_variants(cx, tid);
    for (ast.variant variant in variants) {
1013
        auto tup_ty = ty.plain_tup_ty(variant_types(cx, variant));
1014

1015 1016 1017
        // Perform any type parameter substitutions.
        tup_ty = ty.substitute_ty_params(ty_params, subtys, tup_ty);

1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
        // 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;
}

1030
fn dynamic_size_of(@block_ctxt cx, @ty.t t) -> result {
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055
    fn align_elements(@block_ctxt cx, vec[@ty.t] elts) -> result {
        //
        // C padding rules:
        //
        //
        //   - Pad after each element so that next element is aligned.
        //   - Pad after final structure member so that whole structure
        //     is aligned to max alignment of interior.
        //
        auto off = C_int(0);
        auto max_align = C_int(1);
        auto bcx = cx;
        for (@ty.t e in elts) {
            auto elt_align = align_of(bcx, e);
            bcx = elt_align.bcx;
            auto elt_size = size_of(bcx, e);
            bcx = elt_size.bcx;
            auto aligned_off = align_to(bcx, off, elt_align.val);
            off = cx.build.Add(aligned_off, elt_size.val);
            max_align = umax(bcx, max_align, elt_align.val);
        }
        off = align_to(bcx, off, max_align);
        ret res(bcx, off);
    }

1056 1057 1058
    alt (t.struct) {
        case (ty.ty_param(?p)) {
            auto szptr = field_of_tydesc(cx, t, abi.tydesc_field_size);
1059
            ret res(szptr.bcx, szptr.bcx.build.Load(szptr.val));
1060 1061
        }
        case (ty.ty_tup(?elts)) {
1062 1063 1064 1065 1066
            let vec[@ty.t] tys = vec();
            for (ty.mt mt in elts) {
                tys += vec(mt.ty);
            }
            ret align_elements(cx, tys);
1067 1068
        }
        case (ty.ty_rec(?flds)) {
1069
            let vec[@ty.t] tys = vec();
1070
            for (ty.field f in flds) {
1071
                tys += vec(f.mt.ty);
1072
            }
1073
            ret align_elements(cx, tys);
1074
        }
1075 1076 1077 1078 1079 1080 1081
        case (ty.ty_tag(?tid, ?tps)) {
            auto bcx = cx;

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

1082
            auto ty_params = tag_ty_params(bcx.fcx.ccx, tid);
1083 1084
            auto variants = tag_variants(bcx.fcx.ccx, tid);
            for (ast.variant variant in variants) {
1085 1086 1087 1088 1089 1090 1091 1092
                // Perform type substitution on the raw variant types.
                let vec[@ty.t] raw_tys = variant_types(bcx.fcx.ccx, variant);
                let vec[@ty.t] tys = vec();
                for (@ty.t raw_ty in raw_tys) {
                    auto t = ty.substitute_ty_params(ty_params, tps, raw_ty);
                    tys += vec(t);
                }

1093 1094 1095 1096 1097 1098 1099 1100
                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);
            }

1101 1102 1103
            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);
1104
        }
1105 1106 1107
    }
}

1108
fn dynamic_align_of(@block_ctxt cx, @ty.t t) -> result {
1109 1110 1111
    alt (t.struct) {
        case (ty.ty_param(?p)) {
            auto aptr = field_of_tydesc(cx, t, abi.tydesc_field_align);
1112
            ret res(aptr.bcx, aptr.bcx.build.Load(aptr.val));
1113 1114 1115
        }
        case (ty.ty_tup(?elts)) {
            auto a = C_int(1);
1116
            auto bcx = cx;
1117 1118
            for (ty.mt e in elts) {
                auto align = align_of(bcx, e.ty);
1119 1120
                bcx = align.bcx;
                a = umax(bcx, a, align.val);
1121
            }
1122
            ret res(bcx, a);
1123 1124 1125
        }
        case (ty.ty_rec(?flds)) {
            auto a = C_int(1);
1126
            auto bcx = cx;
1127
            for (ty.field f in flds) {
1128
                auto align = align_of(bcx, f.mt.ty);
1129 1130
                bcx = align.bcx;
                a = umax(bcx, a, align.val);
1131
            }
1132
            ret res(bcx, a);
1133
        }
1134 1135 1136
        case (ty.ty_tag(_, _)) {
            ret res(cx, C_int(1)); // FIXME: stub
        }
1137 1138 1139
    }
}

1140
// Replacement for the LLVM 'GEP' instruction when field-indexing into a
1141 1142 1143 1144
// 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.
1145 1146

fn GEP_tup_like(@block_ctxt cx, @ty.t t,
1147
                ValueRef base, vec[int] ixs) -> result {
1148 1149 1150 1151 1152 1153 1154 1155

    check (ty.type_is_tup_like(t));

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

    if (! ty.type_has_dynamic_size(t)) {
        let vec[ValueRef] v = vec();
        for (int i in ixs) {
1156
            v += vec(C_int(i));
1157
        }
1158
        ret res(cx, cx.build.GEP(base, v));
1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202
    }

    // It is a dynamic-containing type that, if we convert directly to an LLVM
    // TypeRef, will be all wrong; there's no proper LLVM type to represent
    // it, and the lowering function will stick in i8* values for each
    // ty_param, which is not right; the ty_params are all of some dynamic
    // size.
    //
    // What we must do instead is sadder. We must look through the indices
    // manually and split the input type into a prefix and a target. We then
    // measure the prefix size, bump the input pointer by that amount, and
    // cast to a pointer-to-target type.


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

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

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

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

        check (len > 1u);

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

        check (n < len);

        let int ix = ixs.(n);
        let vec[@ty.t] prefix = vec();
        let int i = 0;
        while (i < ix) {
1203 1204
            _vec.push[@ty.t](prefix, ty.get_element_type(t, i as uint));
            i += 1 ;
1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227
        }

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

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

        } else {
            // Not the innermost index; call self recursively to dig deeper.
            // Once we get an inner result, append it current prefix and
            // return to caller.
            auto inner = split_type(selected, ixs, n+1u);
            prefix += inner.prefix;
            ret rec(prefix=prefix with inner);
        }
    }

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

    auto s = split_type(t, ixs, 0u);
1228
    auto prefix_ty = ty.plain_tup_ty(s.prefix);
1229 1230 1231 1232 1233
    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));
1234 1235 1236

    if (ty.type_has_dynamic_size(s.target)) {
        ret res(bcx, bumped);
1237
    }
1238 1239 1240

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

1243 1244 1245 1246
// 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.
1247 1248 1249 1250 1251 1252
fn GEP_tag(@block_ctxt cx,
           ValueRef llblobptr,
           &ast.def_id tag_id,
           &ast.def_id variant_id,
           vec[@ty.t] ty_substs,
           int ix)
1253
        -> result {
1254 1255 1256
    auto ty_params = tag_ty_params(cx.fcx.ccx, tag_id);
    auto variant = tag_variant_with_id(cx.fcx.ccx, tag_id, variant_id);

1257 1258 1259 1260 1261 1262 1263
    // Synthesize a tuple type so that GEP_tup_like() can work its magic.
    // Separately, store the type of the element we're interested in.
    auto arg_tys = arg_tys_of_fn(variant.ann);
    auto elem_ty = ty.plain_ty(ty.ty_nil);  // typestate infelicity
    auto i = 0;
    let vec[@ty.t] true_arg_tys = vec();
    for (ty.arg a in arg_tys) {
1264 1265
        auto arg_ty = ty.substitute_ty_params(ty_params, ty_substs, a.ty);
        true_arg_tys += vec(arg_ty);
1266
        if (i == ix) {
1267
            elem_ty = arg_ty;
1268 1269 1270 1271
        }

        i += 1;
    }
1272 1273

    auto tup_ty = ty.plain_tup_ty(true_arg_tys);
1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299

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

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

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

    ret res(rslt.bcx, val);
}

1300

1301 1302
fn trans_raw_malloc(@block_ctxt cx, TypeRef llptr_ty, ValueRef llsize)
        -> result {
1303 1304
    // FIXME: need a table to collect tydesc globals.
    auto tydesc = C_int(0);
1305 1306 1307 1308 1309
    auto rslt = trans_upcall(cx, "upcall_malloc", vec(llsize, tydesc));
    rslt = res(rslt.bcx, vi2p(cx, rslt.val, llptr_ty));
    ret rslt;
}

1310 1311 1312
fn trans_malloc_boxed(@block_ctxt cx, @ty.t t) -> result {
    // Synthesize a fake box type structurally so we have something
    // to measure the size of.
1313 1314
    auto boxed_body = ty.plain_tup_ty(vec(plain_ty(ty.ty_int), t));
    auto box_ptr = ty.plain_box_ty(t);
1315 1316 1317
    auto sz = size_of(cx, boxed_body);
    auto llty = type_of(cx.fcx.ccx, box_ptr);
    ret trans_raw_malloc(sz.bcx, llty, sz.val);
1318 1319 1320
}


1321 1322 1323 1324 1325
// 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.
1326
fn field_of_tydesc(@block_ctxt cx, @ty.t t, int field) -> result {
1327
    auto tydesc = get_tydesc(cx, t);
1328 1329
    ret res(tydesc.bcx,
            tydesc.bcx.build.GEP(tydesc.val, vec(C_int(0), C_int(field))));
1330
}
1331

1332 1333 1334 1335 1336 1337 1338 1339 1340
// Given a type containing ty params, build a vector containing a ValueRef for
// each of the ty params it uses (from the current frame), as well as a vec
// containing a def_id for each such param. This is used solely for
// constructing derived tydescs.
fn linearize_ty_params(@block_ctxt cx, @ty.t t)
    -> tup(vec[ast.def_id], vec[ValueRef]) {
    let vec[ValueRef] param_vals = vec();
    let vec[ast.def_id] param_defs = vec();
    type rr = rec(@block_ctxt cx,
1341 1342
                  mutable vec[ValueRef] vals,
                  mutable vec[ast.def_id] defs);
1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354

    state obj folder(@rr r) {
        fn fold_simple_ty(@ty.t t) -> @ty.t {
            alt(t.struct) {
                case (ty.ty_param(?pid)) {
                    let bool seen = false;
                    for (ast.def_id d in r.defs) {
                        if (d == pid) {
                            seen = true;
                        }
                    }
                    if (!seen) {
1355 1356
                        r.vals += vec(r.cx.fcx.lltydescs.get(pid));
                        r.defs += vec(pid);
1357 1358
                    }
                }
1359
                case (_) { }
1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374
            }
            ret t;
        }
    }


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

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

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

1375
fn get_tydesc(&@block_ctxt cx, @ty.t t) -> result {
1376
    // Is the supplied type a type param? If so, return the passed-in tydesc.
1377
    alt (ty.type_param(t)) {
1378
        case (some[ast.def_id](?id)) {
1379
            check (cx.fcx.lltydescs.contains_key(id));
1380 1381
            ret res(cx, cx.fcx.lltydescs.get(id));
        }
1382
        case (none[ast.def_id])      { /* fall through */ }
1383
    }
1384 1385

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

1388
    if (ty.count_ty_params(t) > 0u) {
1389
        auto tys = linearize_ty_params(cx, t);
1390

1391 1392 1393
        check (n_params == _vec.len[ast.def_id](tys._0));
        check (n_params == _vec.len[ValueRef](tys._1));

1394
        if (!cx.fcx.ccx.tydescs.contains_key(t)) {
1395 1396
            declare_tydesc(cx.fcx.ccx, t);
            define_tydesc(cx.fcx.ccx, t, tys._0);
1397 1398
        }

1399
        auto root = cx.fcx.ccx.tydescs.get(t).tydesc;
1400

1401 1402
        auto tydescs = cx.build.Alloca(T_array(T_ptr(T_tydesc(cx.fcx.ccx.tn)),
                                               n_params));
1403

1404
        auto i = 0;
1405 1406 1407
        auto tdp = cx.build.GEP(tydescs, vec(C_int(0), C_int(i)));
        cx.build.Store(root, tdp);
        i += 1;
1408 1409
        for (ValueRef td in tys._1) {
            auto tdp = cx.build.GEP(tydescs, vec(C_int(0), C_int(i)));
1410
            cx.build.Store(td, tdp);
1411
            i += 1;
1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423
        }

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

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

1427 1428
        ret res(v.bcx, vi2p(v.bcx, v.val,
                            T_ptr(T_tydesc(cx.fcx.ccx.tn))));
1429 1430 1431
    }

    // Otherwise, generate a tydesc if necessary, and return it.
1432
    if (!cx.fcx.ccx.tydescs.contains_key(t)) {
1433
        let vec[ast.def_id] defs = vec();
1434 1435
        declare_tydesc(cx.fcx.ccx, t);
        define_tydesc(cx.fcx.ccx, t, defs);
1436
    }
1437
    ret res(cx, cx.fcx.ccx.tydescs.get(t).tydesc);
1438 1439
}

1440 1441 1442 1443 1444 1445
// Generates the declaration for (but doesn't fill in) a type descriptor. This
// needs to be separate from make_tydesc() below, because sometimes type glue
// functions needs to refer to their own type descriptors.
fn declare_tydesc(@crate_ctxt cx, @ty.t t) {
    auto take_glue = declare_generic_glue(cx, t, "take");
    auto drop_glue = declare_generic_glue(cx, t, "drop");
1446

1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459
    auto llsize;
    auto llalign;
    if (!ty.type_has_dynamic_size(t)) {
        auto llty = type_of(cx, t);
        llsize = llsize_of(llty);
        llalign = llalign_of(llty);
    } else {
        // These will be overwritten as the derived tydesc is generated, so
        // we create placeholder values.
        llsize = C_int(0);
        llalign = C_int(0);
    }

1460
    auto glue_fn_ty = T_ptr(T_glue_fn(cx.tn));
1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472

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

    auto name = sanitize(cx.names.next("tydesc_" + ty.ty_to_str(t)));
1473 1474 1475
    auto gvar = llvm.LLVMAddGlobal(cx.llmod, T_tydesc(cx.tn),
                                   _str.buf(name));
    auto tydesc = C_struct(vec(C_null(T_ptr(T_ptr(T_tydesc(cx.tn)))),
1476 1477
                               llsize,
                               llalign,
1478 1479
                               off(gvar, take_glue),  // take_glue_off
                               off(gvar, drop_glue),  // drop_glue_off
1480 1481 1482 1483 1484 1485 1486 1487
                               C_null(glue_fn_ty),    // free_glue_off
                               C_null(glue_fn_ty),    // sever_glue_off
                               C_null(glue_fn_ty),    // mark_glue_off
                               C_null(glue_fn_ty),    // obj_drop_glue_off
                               C_null(glue_fn_ty)));  // is_stateful

    llvm.LLVMSetInitializer(gvar, tydesc);
    llvm.LLVMSetGlobalConstant(gvar, True);
1488 1489
    llvm.LLVMSetLinkage(gvar, lib.llvm.LLVMPrivateLinkage
                        as llvm.Linkage);
1490 1491 1492 1493 1494 1495 1496 1497

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

    cx.tydescs.insert(t, @info);
1498 1499
}

1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513
// declare_tydesc() above must have been called first.
fn define_tydesc(@crate_ctxt cx, @ty.t t, vec[ast.def_id] typaram_defs) {
    auto info = cx.tydescs.get(t);
    auto gvar = info.tydesc;

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

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

1516
    auto fn_name = cx.names.next("_rust_" + name) + sep() + ty.ty_to_str(t);
1517
    fn_name = sanitize(fn_name);
1518 1519 1520
    auto llfn = decl_fastcall_fn(cx.llmod, fn_name, llfnty);
    llvm.LLVMSetLinkage(llfn, lib.llvm.LLVMPrivateLinkage as llvm.Linkage);
    ret llfn;
1521
}
1522

1523 1524 1525
fn make_generic_glue(@crate_ctxt cx, @ty.t t, ValueRef llfn,
                     val_and_ty_fn helper,
                     vec[ast.def_id] typaram_defs) -> ValueRef {
1526
    auto fcx = new_fn_ctxt(cx, llfn);
1527 1528
    auto bcx = new_top_block_ctxt(fcx);

1529
    auto re;
1530
    if (!ty.type_is_scalar(t)) {
1531
        auto llty;
1532 1533 1534
        if (ty.type_has_dynamic_size(t)) {
            llty = T_ptr(T_i8());
        } else if (ty.type_is_structural(t)) {
1535 1536 1537 1538
            llty = T_ptr(type_of(cx, t));
        } else {
            llty = type_of(cx, t);
        }
1539

1540
        auto lltyparams = llvm.LLVMGetParam(llfn, 3u);
1541 1542 1543 1544 1545 1546 1547 1548
        auto p = 0;
        for (ast.def_id d in typaram_defs) {
            auto llparam = bcx.build.GEP(lltyparams, vec(C_int(p)));
            llparam = bcx.build.Load(llparam);
            bcx.fcx.lltydescs.insert(d, llparam);
            p += 1;
        }

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

1552 1553 1554 1555
        re = helper(bcx, llval, t);
    } else {
        re = res(bcx, C_nil());
    }
1556

1557
    re.bcx.build.RetVoid();
1558 1559 1560
    ret llfn;
}

1561 1562
fn make_take_glue(@block_ctxt cx, ValueRef v, @ty.t t) -> result {
    if (ty.type_is_boxed(t)) {
1563 1564
        ret incr_refcnt_of_boxed(cx, v);

1565
    } else if (ty.type_is_structural(t)) {
1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590
        ret iter_structural_ty(cx, v, t,
                               bind incr_all_refcnts(_, _, _));
    }
    ret res(cx, C_nil());
}

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

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

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

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

    ret res(next_cx, C_nil());
}

1591
fn make_drop_glue(@block_ctxt cx, ValueRef v, @ty.t t) -> result {
1592
    alt (t.struct) {
1593
        case (ty.ty_str) {
G
Graydon Hoare 已提交
1594 1595 1596 1597
            ret decr_refcnt_and_if_zero
                (cx, v, bind trans_non_gc_free(_, v),
                 "free string",
                 T_int(), C_int(0));
1598 1599
        }

1600
        case (ty.ty_vec(_)) {
G
Graydon Hoare 已提交
1601 1602 1603 1604
            fn hit_zero(@block_ctxt cx, ValueRef v,
                        @ty.t t) -> result {
                auto res = iter_sequence(cx, v, t,
                                         bind drop_ty(_,_,_));
1605 1606 1607 1608 1609 1610 1611 1612 1613
                // FIXME: switch gc/non-gc on layer of the type.
                ret trans_non_gc_free(res.bcx, v);
            }
            ret decr_refcnt_and_if_zero(cx, v,
                                        bind hit_zero(_, v, t),
                                        "free vector",
                                        T_int(), C_int(0));
        }

1614
        case (ty.ty_box(?body_mt)) {
G
Graydon Hoare 已提交
1615 1616
            fn hit_zero(@block_ctxt cx, ValueRef v,
                        @ty.t body_ty) -> result {
1617 1618 1619 1620
                auto body = cx.build.GEP(v,
                                         vec(C_int(0),
                                             C_int(abi.box_rc_field_body)));

1621
                auto body_val = load_scalar_or_boxed(cx, body, body_ty);
1622 1623 1624 1625 1626
                auto res = drop_ty(cx, body_val, body_ty);
                // FIXME: switch gc/non-gc on layer of the type.
                ret trans_non_gc_free(res.bcx, v);
            }
            ret decr_refcnt_and_if_zero(cx, v,
1627
                                        bind hit_zero(_, v, body_mt.ty),
1628 1629 1630 1631
                                        "free box",
                                        T_int(), C_int(0));
        }

B
Brian Anderson 已提交
1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653
        case (ty.ty_port(_)) {
            fn hit_zero(@block_ctxt cx, ValueRef v) -> result {
                ret trans_upcall(cx, "upcall_del_port",
                                 vec(vp2i(cx, v)));
            }
            ret decr_refcnt_and_if_zero(cx, v,
                                        bind hit_zero(_, v),
                                        "free port",
                                        T_int(), C_int(0));
        }

        case (ty.ty_chan(_)) {
            fn hit_zero(@block_ctxt cx, ValueRef v) -> result {
                ret trans_upcall(cx, "upcall_del_chan",
                                 vec(vp2i(cx, v)));
            }
            ret decr_refcnt_and_if_zero(cx, v,
                                        bind hit_zero(_, v),
                                        "free chan",
                                        T_int(), C_int(0));
        }

1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666
        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)));
1667

1668
                call_tydesc_glue_full(cx, body, cx.build.Load(tydescptr),
1669
                                      abi.tydesc_field_drop_glue_off);
1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687

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

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

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

1688
        case (ty.ty_fn(_,_,_)) {
1689 1690 1691 1692 1693 1694 1695
            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)));
1696 1697 1698 1699
                auto bindings =
                    cx.build.GEP(body,
                                 vec(C_int(0),
                                     C_int(abi.closure_elt_bindings)));
1700 1701 1702 1703 1704

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

1706
                call_tydesc_glue_full(cx, bindings, cx.build.Load(tydescptr),
1707 1708
                                      abi.tydesc_field_drop_glue_off);

1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726

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

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

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

1727
        case (_) {
1728
            if (ty.type_is_structural(t)) {
1729 1730 1731
                ret iter_structural_ty(cx, v, t,
                                       bind drop_ty(_, _, _));

1732
            } else if (ty.type_is_scalar(t) ||
1733
                       ty.type_is_native(t) ||
1734
                       ty.type_is_nil(t)) {
1735 1736 1737 1738
                ret res(cx, C_nil());
            }
        }
    }
1739
    cx.fcx.ccx.sess.bug("bad type in trans.make_drop_glue_inner: " +
1740
                        ty.ty_to_str(t));
1741 1742 1743
    fail;
}

1744 1745
fn decr_refcnt_and_if_zero(@block_ctxt cx,
                           ValueRef box_ptr,
1746
                           fn(@block_ctxt cx) -> result inner,
1747
                           str inner_name,
1748
                           TypeRef t_else, ValueRef v_else) -> result {
1749

1750
    auto load_rc_cx = new_sub_block_ctxt(cx, "load rc");
1751 1752 1753 1754
    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");

1755 1756
    auto null_test = cx.build.IsNull(box_ptr);
    cx.build.CondBr(null_test, next_cx.llbb, load_rc_cx.llbb);
1757

1758 1759 1760 1761 1762 1763 1764 1765 1766 1767

    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);
1768 1769 1770 1771

    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);
1772 1773 1774 1775
    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);
1776

1777
    auto phi = next_cx.build.Phi(t_else,
1778
                                 vec(v_else, v_else, v_else, inner_res.val),
1779
                                 vec(cx.llbb,
1780
                                     load_rc_cx.llbb,
1781
                                     rc_adj_cx.llbb,
1782 1783
                                     inner_res.bcx.llbb));

1784
    ret res(next_cx, phi);
1785 1786
}

1787 1788
// Tag information

1789 1790
fn variant_types(@crate_ctxt cx, &ast.variant v) -> vec[@ty.t] {
    let vec[@ty.t] tys = vec();
1791
    alt (ty.ann_to_type(v.ann).struct) {
1792
        case (ty.ty_fn(_, ?args, _)) {
1793
            for (ty.arg arg in args) {
1794
                tys += vec(arg.ty);
1795 1796
            }
        }
1797
        case (ty.ty_tag(_, _)) { /* nothing */ }
1798
        case (_) { fail; }
1799
    }
1800 1801 1802
    ret tys;
}

1803 1804 1805 1806 1807 1808 1809 1810 1811
// Returns the type parameters of a tag.
fn tag_ty_params(@crate_ctxt cx, ast.def_id id) -> vec[ast.ty_param] {
    check (cx.items.contains_key(id));
    alt (cx.items.get(id).node) {
        case (ast.item_tag(_, _, ?tps, _)) { ret tps; }
    }
    fail;   // not reached
}

1812 1813
// Returns the variants in a tag.
fn tag_variants(@crate_ctxt cx, ast.def_id id) -> vec[ast.variant] {
1814 1815
    check (cx.items.contains_key(id));
    alt (cx.items.get(id).node) {
1816
        case (ast.item_tag(_, ?variants, _, _)) { ret variants; }
1817 1818 1819 1820
    }
    fail;   // not reached
}

1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839
// Returns the tag variant with the given ID.
fn tag_variant_with_id(@crate_ctxt cx,
                       &ast.def_id tag_id,
                       &ast.def_id variant_id) -> ast.variant {
    auto variants = tag_variants(cx, tag_id);

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

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

1840 1841 1842 1843 1844 1845 1846 1847
// Returns a new plain tag type of the given ID with no type parameters. Don't
// use this function in new code; it's a hack to keep things working for now.
fn mk_plain_tag(ast.def_id tid) -> @ty.t {
    let vec[@ty.t] tps = vec();
    ret ty.plain_ty(ty.ty_tag(tid, tps));
}


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

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

1852 1853 1854
type val_pair_and_ty_fn =
    fn(@block_ctxt cx, ValueRef av, ValueRef bv, @ty.t t) -> result;

1855
// Iterates through the elements of a structural type.
1856 1857
fn iter_structural_ty(@block_ctxt cx,
                      ValueRef v,
1858
                      @ty.t t,
1859 1860
                      val_and_ty_fn f)
    -> result {
1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878
    fn adaptor_fn(val_and_ty_fn f,
                  @block_ctxt cx,
                  ValueRef av,
                  ValueRef bv,
                  @ty.t t) -> result {
        ret f(cx, av, t);
    }
    be iter_structural_ty_full(cx, v, v, t,
                               bind adaptor_fn(f, _, _, _, _));
}


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

1881
    fn iter_boxpp(@block_ctxt cx,
1882 1883 1884 1885 1886
                  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);
1887
        auto tnil = plain_ty(ty.ty_nil);
1888
        auto tbox = ty.plain_box_ty(tnil);
1889 1890 1891

        auto inner_cx = new_sub_block_ctxt(cx, "iter box");
        auto next_cx = new_sub_block_ctxt(cx, "next");
1892
        auto null_test = cx.build.IsNull(box_a_ptr);
1893 1894
        cx.build.CondBr(null_test, next_cx.llbb, inner_cx.llbb);

1895
        auto r = f(inner_cx, box_a_ptr, box_b_ptr, tbox);
1896 1897 1898 1899
        r.bcx.build.Br(next_cx.llbb);
        ret res(next_cx, r.val);
    }

1900
    alt (t.struct) {
1901
        case (ty.ty_tup(?args)) {
1902
            let int i = 0;
1903
            for (ty.mt arg in args) {
1904 1905 1906 1907
                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;
1908
                r = f(r.bcx,
1909 1910 1911
                      load_scalar_or_boxed(r.bcx, elt_a, arg.ty),
                      load_scalar_or_boxed(r.bcx, elt_b, arg.ty),
                      arg.ty);
1912 1913 1914
                i += 1;
            }
        }
1915
        case (ty.ty_rec(?fields)) {
1916
            let int i = 0;
1917
            for (ty.field fld in fields) {
1918 1919 1920 1921
                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;
1922
                r = f(r.bcx,
1923 1924 1925
                      load_scalar_or_boxed(r.bcx, llfld_a, fld.mt.ty),
                      load_scalar_or_boxed(r.bcx, llfld_b, fld.mt.ty),
                      fld.mt.ty);
1926 1927 1928
                i += 1;
            }
        }
1929
        case (ty.ty_tag(?tid, ?tps)) {
1930 1931
            auto variants = tag_variants(cx.fcx.ccx, tid);
            auto n_variants = _vec.len[ast.variant](variants);
1932

1933 1934 1935 1936 1937 1938 1939 1940 1941
            // Cast the tags to types we can GEP into.
            auto lltagty = T_opaque_tag_ptr(cx.fcx.ccx.tn);
            auto av_tag = cx.build.PointerCast(av, lltagty);
            auto bv_tag = cx.build.PointerCast(bv, lltagty);

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

1944 1945 1946 1947
            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)));
1948
            auto lldiscrim_b = cx.build.Load(lldiscrim_b_ptr);
G
Graydon Hoare 已提交
1949

1950 1951 1952 1953 1954 1955 1956
            // NB: we must hit the discriminant first so that structural
            // comparison know not to proceed when the discriminants differ.
            auto bcx = cx;
            bcx = f(bcx, lldiscrim_a, lldiscrim_b,
                    plain_ty(ty.ty_int)).bcx;

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

1959
            auto llswitch = bcx.build.Switch(lldiscrim_a, unr_cx.llbb,
1960
                                             n_variants);
G
Graydon Hoare 已提交
1961

1962
            auto next_cx = new_sub_block_ctxt(bcx, "tag-iter-next");
1963

1964 1965
            auto ty_params = tag_ty_params(bcx.fcx.ccx, tid);

1966
            auto i = 0u;
1967
            for (ast.variant variant in variants) {
1968
                auto variant_cx = new_sub_block_ctxt(bcx,
1969
                                                     "tag-iter-variant-" +
1970 1971 1972
                                                     _uint.to_str(i, 10u));
                llvm.LLVMAddCase(llswitch, C_int(i as int), variant_cx.llbb);

1973 1974 1975 1976 1977
                if (_vec.len[ast.variant_arg](variant.args) > 0u) {
                    // N-ary variant.
                    auto fn_ty = ty.ann_to_type(variants.(i).ann);
                    alt (fn_ty.struct) {
                        case (ty.ty_fn(_, ?args, _)) {
1978
                            auto j = 0;
1979 1980
                            for (ty.arg a in args) {
                                auto v = vec(C_int(0), C_int(j as int));
1981

1982 1983 1984 1985
                                auto rslt = GEP_tag(variant_cx, llunion_a_ptr,
                                    tid, variants.(i).id, tps, j);
                                auto llfldp_a = rslt.val;
                                variant_cx = rslt.bcx;
1986

1987 1988 1989 1990
                                rslt = GEP_tag(variant_cx, llunion_b_ptr, tid,
                                    variants.(i).id, tps, j);
                                auto llfldp_b = rslt.val;
                                variant_cx = rslt.bcx;
1991 1992

                                auto ty_subst = ty.substitute_ty_params(
1993
                                    ty_params, tps, a.ty);
1994

1995
                                auto llfld_a =
1996
                                    load_scalar_or_boxed(variant_cx,
1997
                                                         llfldp_a,
1998 1999
                                                         ty_subst);

2000 2001 2002 2003 2004 2005 2006
                                auto llfld_b =
                                    load_scalar_or_boxed(variant_cx,
                                                         llfldp_b,
                                                         ty_subst);

                                auto res = f(variant_cx,
                                             llfld_a, llfld_b, ty_subst);
2007
                                variant_cx = res.bcx;
2008
                                j += 1;
2009 2010
                            }
                        }
2011
                        case (_) { fail; }
2012
                    }
2013 2014 2015 2016 2017

                    variant_cx.build.Br(next_cx.llbb);
                } else {
                    // Nullary variant; nothing to do.
                    variant_cx.build.Br(next_cx.llbb);
2018 2019 2020 2021 2022 2023 2024
                }

                i += 1u;
            }

            ret res(next_cx, C_nil());
        }
2025
        case (ty.ty_fn(_,_,_)) {
2026 2027 2028 2029 2030 2031
            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,
2032 2033
                             vec(C_int(0),
                                 C_int(abi.fn_field_box)));
2034
            ret iter_boxpp(cx, box_cell_a, box_cell_b, f);
2035
        }
2036
        case (ty.ty_obj(_)) {
2037 2038 2039 2040 2041 2042
            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,
2043 2044
                             vec(C_int(0),
                                 C_int(abi.obj_field_box)));
2045
            ret iter_boxpp(cx, box_cell_a, box_cell_b, f);
2046
        }
2047
        case (_) {
2048
            cx.fcx.ccx.sess.unimpl("type in iter_structural_ty_full");
2049
        }
2050
    }
2051
    ret r;
2052 2053
}

2054 2055
// Iterates through a pointer range, until the src* hits the src_lim*.
fn iter_sequence_raw(@block_ctxt cx,
2056
                     ValueRef dst,     // elt*
2057 2058 2059
                     ValueRef src,     // elt*
                     ValueRef src_lim, // elt*
                     ValueRef elt_sz,
2060
                     val_pair_fn f) -> result {
2061 2062 2063

    auto bcx = cx;

2064
    let ValueRef dst_int = vp2i(bcx, dst);
2065 2066 2067 2068 2069 2070 2071 2072 2073
    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);

2074 2075
    let ValueRef dst_curr = cond_cx.build.Phi(T_int(),
                                              vec(dst_int), vec(bcx.llbb));
2076 2077 2078
    let ValueRef src_curr = cond_cx.build.Phi(T_int(),
                                              vec(src_int), vec(bcx.llbb));

2079
    auto end_test = cond_cx.build.ICmp(lib.llvm.LLVMIntULT,
2080 2081 2082 2083
                                       src_curr, src_lim_int);

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

2084
    auto dst_curr_ptr = vi2p(body_cx, dst_curr, T_ptr(T_i8()));
2085
    auto src_curr_ptr = vi2p(body_cx, src_curr, T_ptr(T_i8()));
2086

2087
    auto body_res = f(body_cx, dst_curr_ptr, src_curr_ptr);
2088 2089
    body_cx = body_res.bcx;

2090
    auto dst_next = body_cx.build.Add(dst_curr, elt_sz);
2091
    auto src_next = body_cx.build.Add(src_curr, elt_sz);
2092 2093
    body_cx.build.Br(cond_cx.llbb);

2094 2095
    cond_cx.build.AddIncomingToPhi(dst_curr, vec(dst_next),
                                   vec(body_cx.llbb));
2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108
    cond_cx.build.AddIncomingToPhi(src_curr, vec(src_next),
                                   vec(body_cx.llbb));

    ret res(next_cx, C_nil());
}


fn iter_sequence_inner(@block_ctxt cx,
                       ValueRef src,     // elt*
                       ValueRef src_lim, // elt*
                       @ty.t elt_ty,
                       val_and_ty_fn f) -> result {
    fn adaptor_fn(val_and_ty_fn f,
2109
                  @ty.t elt_ty,
2110
                  @block_ctxt cx,
2111 2112
                  ValueRef dst,
                  ValueRef src) -> result {
2113 2114 2115 2116 2117 2118 2119 2120 2121
        auto llptrty;
        if (!ty.type_has_dynamic_size(elt_ty)) {
            auto llty = type_of(cx.fcx.ccx, elt_ty);
            llptrty = T_ptr(llty);
        } else {
            llptrty = T_ptr(T_ptr(T_i8()));
        }

        auto p = cx.build.PointerCast(src, llptrty);
2122
        ret f(cx, load_scalar_or_boxed(cx, p, elt_ty), elt_ty);
2123 2124
    }

2125
    auto elt_sz = size_of(cx, elt_ty);
2126 2127
    be iter_sequence_raw(elt_sz.bcx, src, src, src_lim, elt_sz.val,
                         bind adaptor_fn(f, elt_ty, _, _, _));
2128 2129 2130
}


2131 2132 2133
// Iterates through the elements of a vec or str.
fn iter_sequence(@block_ctxt cx,
                 ValueRef v,
2134
                 @ty.t t,
2135 2136 2137 2138
                 val_and_ty_fn f) -> result {

    fn iter_sequence_body(@block_ctxt cx,
                          ValueRef v,
2139
                          @ty.t elt_ty,
2140 2141 2142 2143 2144 2145 2146
                          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)));
2147

2148 2149 2150 2151 2152 2153 2154
        auto llunit_ty;
        if (ty.type_has_dynamic_size(elt_ty)) {
            llunit_ty = T_i8();
        } else {
            llunit_ty = type_of(cx.fcx.ccx, elt_ty);
        }

2155
        auto bcx = cx;
2156

2157
        auto len = bcx.build.Load(lenptr);
2158
        if (trailing_null) {
2159 2160
            auto unit_sz = size_of(bcx, elt_ty);
            bcx = unit_sz.bcx;
2161
            len = bcx.build.Sub(len, unit_sz.val);
2162 2163
        }

2164 2165
        auto p1 = vi2p(bcx, bcx.build.Add(vp2i(bcx, p0), len),
                       T_ptr(llunit_ty));
2166

2167
        ret iter_sequence_inner(cx, p0, p1, elt_ty, f);
2168 2169
    }

2170
    alt (t.struct) {
2171 2172
        case (ty.ty_vec(?elt)) {
            ret iter_sequence_body(cx, v, elt.ty, f, false);
2173
        }
2174
        case (ty.ty_str) {
2175
            auto et = plain_ty(ty.ty_machine(common.ty_u8));
2176
            ret iter_sequence_body(cx, v, et, f, true);
2177
        }
2178
        case (_) { fail; }
2179
    }
2180 2181 2182 2183
    cx.fcx.ccx.sess.bug("bad type in trans.iter_sequence");
    fail;
}

2184 2185 2186 2187 2188 2189 2190 2191 2192
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);
2193 2194 2195 2196 2197

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

2202 2203 2204 2205 2206
    cx.build.FastCall(llfn, vec(C_null(T_ptr(T_nil())),
                                cx.fcx.lltaskptr,
                                C_null(T_ptr(T_nil())),
                                lltydescs,
                                llrawptr));
2207 2208 2209
}

fn call_tydesc_glue(@block_ctxt cx, ValueRef v, @ty.t t, int field) {
2210 2211
    auto td = get_tydesc(cx, t);
    call_tydesc_glue_full(td.bcx, v, td.val, field);
2212 2213
}

2214 2215
fn incr_all_refcnts(@block_ctxt cx,
                    ValueRef v,
2216 2217
                    @ty.t t) -> result {
    if (!ty.type_is_scalar(t)) {
2218
        call_tydesc_glue(cx, v, t, abi.tydesc_field_take_glue_off);
2219
    }
2220
    ret res(cx, C_nil());
2221 2222
}

2223 2224
fn drop_slot(@block_ctxt cx,
             ValueRef slot,
2225
             @ty.t t) -> result {
2226
    auto llptr = load_scalar_or_boxed(cx, slot, t);
2227 2228 2229 2230 2231 2232
    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;
2233 2234
}

2235 2236
fn drop_ty(@block_ctxt cx,
           ValueRef v,
2237
           @ty.t t) -> result {
2238

2239
    if (!ty.type_is_scalar(t)) {
2240
        call_tydesc_glue(cx, v, t, abi.tydesc_field_drop_glue_off);
2241
    }
2242
    ret res(cx, C_nil());
2243 2244
}

2245 2246 2247 2248
fn call_memcpy(@block_ctxt cx,
               ValueRef dst,
               ValueRef src,
               ValueRef n_bytes) -> result {
2249 2250
    auto src_ptr = cx.build.PointerCast(src, T_ptr(T_i8()));
    auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
2251 2252 2253
    auto size = cx.build.IntCast(n_bytes, T_int());
    ret res(cx, cx.build.FastCall(cx.fcx.ccx.glues.memcpy_glue,
                                  vec(dst_ptr, src_ptr, size)));
2254 2255
}

2256 2257 2258 2259 2260 2261 2262 2263 2264
fn call_bzero(@block_ctxt cx,
              ValueRef dst,
              ValueRef n_bytes) -> result {
    auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
    auto size = cx.build.IntCast(n_bytes, T_int());
    ret res(cx, cx.build.FastCall(cx.fcx.ccx.glues.bzero_glue,
                                  vec(dst_ptr, size)));
}

2265 2266 2267 2268 2269 2270
fn memcpy_ty(@block_ctxt cx,
             ValueRef dst,
             ValueRef src,
             @ty.t t) -> result {
    if (ty.type_has_dynamic_size(t)) {
        auto llszptr = field_of_tydesc(cx, t, abi.tydesc_field_size);
2271 2272
        auto llsz = llszptr.bcx.build.Load(llszptr.val);
        ret call_memcpy(llszptr.bcx, dst, src, llsz);
2273 2274 2275 2276 2277 2278

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

2279 2280 2281 2282 2283
tag copy_action {
    INIT;
    DROP_EXISTING;
}

2284
fn copy_ty(@block_ctxt cx,
2285
           copy_action action,
2286 2287
           ValueRef dst,
           ValueRef src,
2288
           @ty.t t) -> result {
2289
    if (ty.type_is_scalar(t) || ty.type_is_native(t)) {
2290 2291
        ret res(cx, cx.build.Store(src, dst));

2292
    } else if (ty.type_is_nil(t)) {
2293 2294
        ret res(cx, C_nil());

2295
    } else if (ty.type_is_boxed(t)) {
2296
        auto r = incr_all_refcnts(cx, src, t);
2297
        if (action == DROP_EXISTING) {
2298
            r = drop_ty(r.bcx, r.bcx.build.Load(dst), t);
2299 2300 2301
        }
        ret res(r.bcx, r.bcx.build.Store(src, dst));

2302 2303
    } else if (ty.type_is_structural(t) ||
               ty.type_has_dynamic_size(t)) {
2304
        auto r = incr_all_refcnts(cx, src, t);
2305
        if (action == DROP_EXISTING) {
2306 2307
            r = drop_ty(r.bcx, dst, t);
        }
2308
        ret memcpy_ty(r.bcx, dst, src, t);
2309 2310 2311
    }

    cx.fcx.ccx.sess.bug("unexpected type in trans.copy_ty: " +
2312
                        ty.ty_to_str(t));
2313 2314 2315
    fail;
}

2316
fn trans_lit(@crate_ctxt cx, &ast.lit lit, &ast.ann ann) -> ValueRef {
2317
    alt (lit.node) {
2318
        case (ast.lit_int(?i)) {
2319
            ret C_int(i);
2320 2321
        }
        case (ast.lit_uint(?u)) {
2322
            ret C_int(u as int);
2323
        }
2324 2325 2326 2327 2328 2329
        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 已提交
2330 2331 2332 2333 2334 2335 2336 2337 2338
                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(); }
2339
            }
2340
            ret C_integral(i, t);
2341
        }
2342 2343 2344
        case(ast.lit_float(?fs)) {
            ret C_float(fs);
        }
2345 2346 2347 2348 2349 2350 2351 2352
        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);
        }
2353
        case (ast.lit_char(?c)) {
2354
            ret C_integral(c as int, T_char());
2355 2356
        }
        case (ast.lit_bool(?b)) {
2357
            ret C_bool(b);
2358 2359
        }
        case (ast.lit_nil) {
2360
            ret C_nil();
2361 2362
        }
        case (ast.lit_str(?s)) {
2363
            ret C_str(cx, s);
2364 2365 2366 2367
        }
    }
}

2368
fn target_type(@crate_ctxt cx, @ty.t t) -> @ty.t {
2369
    alt (t.struct) {
2370 2371
        case (ty.ty_int) {
            auto tm = ty.ty_machine(cx.sess.get_targ_cfg().int_type);
2372 2373
            ret @rec(struct=tm with *t);
        }
2374 2375
        case (ty.ty_uint) {
            auto tm = ty.ty_machine(cx.sess.get_targ_cfg().uint_type);
2376 2377
            ret @rec(struct=tm with *t);
        }
2378
        case (_) { /* fall through */ }
2379 2380 2381 2382
    }
    ret t;
}

2383
fn node_ann_type(@crate_ctxt cx, &ast.ann a) -> @ty.t {
2384 2385
    alt (a) {
        case (ast.ann_none) {
2386
            cx.sess.bug("missing type annotation");
2387
        }
2388
        case (ast.ann_type(?t, _)) {
2389
            ret target_type(cx, t);
2390 2391 2392 2393
        }
    }
}

2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411
fn node_ann_ty_params(&ast.ann a) -> vec[@ty.t] {
    alt (a) {
        case (ast.ann_none) {
            log "missing type annotation";
            fail;
        }
        case (ast.ann_type(_, ?tps_opt)) {
            alt (tps_opt) {
                case (none[vec[@ty.t]]) {
                    log "type annotation has no ty params";
                    fail;
                }
                case (some[vec[@ty.t]](?tps)) { ret tps; }
            }
        }
    }
}

2412 2413 2414 2415
fn node_type(@crate_ctxt cx, &ast.ann a) -> TypeRef {
    ret type_of(cx, node_ann_type(cx, a));
}

2416 2417
fn trans_unary(@block_ctxt cx, ast.unop op,
               @ast.expr e, &ast.ann a) -> result {
2418 2419

    auto sub = trans_expr(cx, e);
2420
    auto e_ty = ty.expr_ty(e);
2421

2422 2423
    alt (op) {
        case (ast.bitnot) {
2424
            sub = autoderef(sub.bcx, sub.val, ty.expr_ty(e));
2425
            ret res(sub.bcx, sub.bcx.build.Not(sub.val));
2426 2427
        }
        case (ast.not) {
2428
            sub = autoderef(sub.bcx, sub.val, ty.expr_ty(e));
2429
            ret res(sub.bcx, sub.bcx.build.Not(sub.val));
2430 2431
        }
        case (ast.neg) {
2432
            sub = autoderef(sub.bcx, sub.val, ty.expr_ty(e));
2433 2434 2435 2436 2437 2438
            if(e_ty.struct == ty.ty_float) {
                ret res(sub.bcx, sub.bcx.build.FNeg(sub.val));
            }
            else {
                ret res(sub.bcx, sub.bcx.build.Neg(sub.val));
            }
2439
        }
2440
        case (ast.box) {
2441
            auto e_ty = ty.expr_ty(e);
2442
            auto e_val = sub.val;
2443 2444 2445
            auto box_ty = node_ann_type(sub.bcx.fcx.ccx, a);
            sub = trans_malloc_boxed(sub.bcx, e_ty);
            find_scope_cx(cx).cleanups +=
2446
                vec(clean(bind drop_ty(_, sub.val, box_ty)));
2447

2448 2449
            auto box = sub.val;
            auto rc = sub.bcx.build.GEP(box,
2450 2451
                                        vec(C_int(0),
                                            C_int(abi.box_rc_field_refcnt)));
2452 2453 2454 2455
            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);
2456 2457 2458 2459 2460 2461 2462 2463 2464

            // Cast the body type to the type of the value. This is needed to
            // make tags work, since tags have a different LLVM type depending
            // on whether they're boxed or not.
            if (!ty.type_has_dynamic_size(e_ty)) {
                auto llety = T_ptr(type_of(sub.bcx.fcx.ccx, e_ty));
                body = sub.bcx.build.PointerCast(body, llety);
            }

2465
            sub = copy_ty(sub.bcx, INIT, body, e_val, e_ty);
2466
            ret res(sub.bcx, box);
2467
        }
2468
        case (ast.deref) {
2469 2470 2471
            auto val = sub.bcx.build.GEP(sub.val,
                                         vec(C_int(0),
                                             C_int(abi.box_rc_field_body)));
2472
            auto e_ty = node_ann_type(sub.bcx.fcx.ccx, a);
2473 2474
            if (ty.type_is_scalar(e_ty) ||
                ty.type_is_nil(e_ty)) {
2475
                val = sub.bcx.build.Load(val);
2476
            }
2477
            ret res(sub.bcx, val);
2478
        }
2479 2480 2481 2482
    }
    fail;
}

2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496
fn trans_compare(@block_ctxt cx0, ast.binop op, @ty.t t0,
                 ValueRef lhs0, ValueRef rhs0) -> result {

    auto cx = cx0;

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

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

    auto t = autoderefed_ty(t0);
2497 2498 2499 2500

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

2501 2502 2503
    } else if (ty.type_is_structural(t)
               || ty.type_is_sequence(t)) {

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

2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531
        /*
         * 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.
         */

2532 2533
        auto flag = scx.build.Alloca(T_i1());

2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557
        if (ty.type_is_sequence(t)) {

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

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

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

2558 2559
            }
        }
2560

2561
        fn inner(@block_ctxt last_cx,
2562
                 bool load_inner,
2563 2564 2565
                 ValueRef flag,
                 ast.binop op,
                 @block_ctxt cx,
2566 2567
                 ValueRef av0,
                 ValueRef bv0,
2568
                 @ty.t t) -> result {
2569

2570 2571 2572
            auto cnt_cx = new_sub_block_ctxt(cx, "continue comparison");
            auto stop_cx = new_sub_block_ctxt(cx, "stop comparison");

2573 2574 2575 2576 2577 2578 2579
            auto av = av0;
            auto bv = bv0;
            if (load_inner) {
                av = load_scalar_or_boxed(cx, av, t);
                bv = load_scalar_or_boxed(cx, bv, t);
            }

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

2584 2585 2586 2587
            // Second 'op' comparison: find out how this elt-pair decides.
            auto stop_r = trans_compare(stop_cx, op, t, av, bv);
            stop_r.bcx.build.Store(stop_r.val, flag);
            stop_r.bcx.build.Br(last_cx.llbb);
2588 2589 2590
            ret res(cnt_cx, C_nil());
        }

2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608
        auto r;
        if (ty.type_is_structural(t)) {
            r = iter_structural_ty_full(scx, lhs, rhs, t,
                                        bind inner(next, false, flag, op,
                                                   _, _, _, _));
        } else {
            auto lhs_p0 = vec_p0(scx, lhs);
            auto rhs_p0 = vec_p0(scx, rhs);
            auto min_len = umin(scx, vec_fill(scx, lhs), vec_fill(scx, rhs));
            auto rhs_lim = scx.build.GEP(rhs_p0, vec(min_len));
            auto elt_ty = ty.sequence_element_type(t);
            auto elt_llsz_r = size_of(scx, elt_ty);
            scx = elt_llsz_r.bcx;
            r = iter_sequence_raw(scx, lhs, rhs, rhs_lim,
                                  elt_llsz_r.val,
                                  bind inner(next, true, flag, op,
                                             _, _, _, elt_ty));
        }
2609

2610 2611
        r.bcx.build.Br(next.llbb);
        auto v = next.build.Load(flag);
2612 2613
        ret res(next, v);

2614

2615
    } else {
2616
        // FIXME: compare obj, fn by pointer?
2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632
        cx.fcx.ccx.sess.unimpl("type in trans_compare");
        ret res(cx, C_bool(false));
    }
}

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

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

2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650
    auto cmp = lib.llvm.LLVMIntEQ;
    alt (op) {
        // FIXME: possibly use the unordered-or-< predicates here,
        // for now we're only going with ordered-and-< style (no NaNs).
        case (ast.eq) { cmp = lib.llvm.LLVMRealOEQ; }
        case (ast.ne) { cmp = lib.llvm.LLVMRealONE; }
        case (ast.lt) { cmp = lib.llvm.LLVMRealOLT; }
        case (ast.gt) { cmp = lib.llvm.LLVMRealOGT; }
        case (ast.le) { cmp = lib.llvm.LLVMRealOLE; }
        case (ast.ge) { cmp = lib.llvm.LLVMRealOGE; }
    }

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

fn trans_integral_compare(@block_ctxt cx, ast.binop op, @ty.t intype,
                          ValueRef lhs, ValueRef rhs) -> ValueRef {
2651 2652 2653 2654 2655
    auto cmp = lib.llvm.LLVMIntEQ;
    alt (op) {
        case (ast.eq) { cmp = lib.llvm.LLVMIntEQ; }
        case (ast.ne) { cmp = lib.llvm.LLVMIntNE; }

2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683
        case (ast.lt) {
            if (ty.type_is_signed(intype)) {
                cmp = lib.llvm.LLVMIntSLT;
            } else {
                cmp = lib.llvm.LLVMIntULT;
            }
        }
        case (ast.le) {
            if (ty.type_is_signed(intype)) {
                cmp = lib.llvm.LLVMIntSLE;
            } else {
                cmp = lib.llvm.LLVMIntULE;
            }
        }
        case (ast.gt) {
            if (ty.type_is_signed(intype)) {
                cmp = lib.llvm.LLVMIntSGT;
            } else {
                cmp = lib.llvm.LLVMIntUGT;
            }
        }
        case (ast.ge) {
            if (ty.type_is_signed(intype)) {
                cmp = lib.llvm.LLVMIntSGE;
            } else {
                cmp = lib.llvm.LLVMIntUGE;
            }
        }
2684 2685 2686 2687
    }
    ret cx.build.ICmp(cmp, lhs, rhs);
}

2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706
fn trans_vec_append(@block_ctxt cx, @ty.t t,
                    ValueRef lhs, ValueRef rhs) -> result {

    auto elt_ty = ty.sequence_element_type(t);

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

    auto bcx = cx;

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

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

2707 2708 2709 2710 2711 2712 2713 2714
    auto dst = bcx.build.PointerCast(lhs, T_ptr(T_opaque_vec_ptr()));
    auto src = bcx.build.PointerCast(rhs, T_opaque_vec_ptr());

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

2717 2718
fn trans_vec_add(@block_ctxt cx, @ty.t t,
                 ValueRef lhs, ValueRef rhs) -> result {
2719
    auto r = alloc_ty(cx, t);
2720 2721
    auto tmp = r.val;
    r = copy_ty(r.bcx, INIT, tmp, lhs, t);
2722
    auto bcx = trans_vec_append(r.bcx, t, tmp, rhs).bcx;
2723
    tmp = load_scalar_or_boxed(bcx, tmp, t);
2724 2725
    find_scope_cx(cx).cleanups +=
        vec(clean(bind drop_ty(_, tmp, t)));
2726
    ret res(bcx, tmp);
2727 2728 2729
}


2730
fn trans_eager_binop(@block_ctxt cx, ast.binop op, @ty.t intype,
2731
                     ValueRef lhs, ValueRef rhs) -> result {
2732

2733
    auto is_float = false;
2734
    alt (intype.struct) {
2735 2736 2737 2738 2739 2740 2741
        case (ty.ty_float) {
            is_float = true;
        }
        case (_) {
            is_float = false;
        }
    }
2742

2743
    alt (op) {
2744 2745
        case (ast.add) {
            if (ty.type_is_sequence(intype)) {
2746
                ret trans_vec_add(cx, intype, lhs, rhs);
2747
            }
2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763
            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));
            }
        }

2764
        case (ast.mul) {
2765 2766 2767 2768 2769 2770
            if (is_float) {
                ret res(cx, cx.build.FMul(lhs, rhs));
            }
            else {
                ret res(cx, cx.build.Mul(lhs, rhs));
            }
2771
        }
2772

2773
        case (ast.div) {
2774 2775 2776
            if (is_float) {
                ret res(cx, cx.build.FDiv(lhs, rhs));
            }
2777
            if (ty.type_is_signed(intype)) {
2778
                ret res(cx, cx.build.SDiv(lhs, rhs));
2779
            } else {
2780
                ret res(cx, cx.build.UDiv(lhs, rhs));
2781 2782 2783
            }
        }
        case (ast.rem) {
2784 2785 2786
            if (is_float) {
                ret res(cx, cx.build.FRem(lhs, rhs));
            }
2787
            if (ty.type_is_signed(intype)) {
2788
                ret res(cx, cx.build.SRem(lhs, rhs));
2789
            } else {
2790
                ret res(cx, cx.build.URem(lhs, rhs));
2791 2792
            }
        }
2793

2794 2795 2796 2797 2798 2799
        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)); }
2800
        case (_) {
2801
            ret trans_compare(cx, op, intype, lhs, rhs);
2802 2803 2804 2805 2806
        }
    }
    fail;
}

2807 2808 2809 2810 2811 2812
fn autoderef(@block_ctxt cx, ValueRef v, @ty.t t) -> result {
    let ValueRef v1 = v;
    let @ty.t t1 = t;

    while (true) {
        alt (t1.struct) {
2813
            case (ty.ty_box(?mt)) {
2814 2815 2816
                auto body = cx.build.GEP(v1,
                                         vec(C_int(0),
                                             C_int(abi.box_rc_field_body)));
2817 2818
                t1 = mt.ty;
                v1 = load_scalar_or_boxed(cx, body, t1);
2819 2820 2821 2822 2823 2824 2825 2826
            }
            case (_) {
                ret res(cx, v1);
            }
        }
    }
}

2827 2828 2829 2830 2831
fn autoderefed_ty(@ty.t t) -> @ty.t {
    let @ty.t t1 = t;

    while (true) {
        alt (t1.struct) {
2832 2833
            case (ty.ty_box(?mt)) {
                t1 = mt.ty;
2834 2835 2836 2837 2838 2839 2840 2841
            }
            case (_) {
                ret t1;
            }
        }
    }
}

2842 2843
fn trans_binary(@block_ctxt cx, ast.binop op,
                @ast.expr a, @ast.expr b) -> result {
2844

2845 2846 2847 2848 2849 2850
    // First couple cases are lazy:

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

2853
            auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
2854
            auto rhs_res = trans_expr(rhs_cx, b);
2855
            rhs_res = autoderef(rhs_res.bcx, rhs_res.val, ty.expr_ty(b));
2856

2857
            auto lhs_false_cx = new_scope_block_ctxt(cx, "lhs false");
2858
            auto lhs_false_res = res(lhs_false_cx, C_bool(false));
2859 2860 2861

            lhs_res.bcx.build.CondBr(lhs_res.val,
                                     rhs_cx.llbb,
2862 2863 2864 2865
                                     lhs_false_cx.llbb);

            ret join_results(cx, T_bool(),
                             vec(lhs_false_res, rhs_res));
2866 2867 2868 2869 2870
        }

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

2873
            auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
2874
            auto rhs_res = trans_expr(rhs_cx, b);
2875
            rhs_res = autoderef(rhs_res.bcx, rhs_res.val, ty.expr_ty(b));
2876

2877
            auto lhs_true_cx = new_scope_block_ctxt(cx, "lhs true");
2878
            auto lhs_true_res = res(lhs_true_cx, C_bool(true));
2879 2880

            lhs_res.bcx.build.CondBr(lhs_res.val,
2881
                                     lhs_true_cx.llbb,
2882
                                     rhs_cx.llbb);
2883 2884 2885

            ret join_results(cx, T_bool(),
                             vec(lhs_true_res, rhs_res));
2886
        }
2887 2888

        case (_) {
2889 2890
            // Remaining cases are eager:
            auto lhs = trans_expr(cx, a);
2891 2892
            auto lhty = ty.expr_ty(a);
            lhs = autoderef(lhs.bcx, lhs.val, lhty);
2893
            auto rhs = trans_expr(lhs.bcx, b);
2894 2895
            auto rhty = ty.expr_ty(b);
            rhs = autoderef(rhs.bcx, rhs.val, rhty);
2896 2897 2898
            ret trans_eager_binop(rhs.bcx, op,
                                  autoderefed_ty(lhty),
                                  lhs.val, rhs.val);
2899
        }
2900 2901 2902 2903
    }
    fail;
}

2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914
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)) {
2915 2916 2917
            live += vec(r);
            vals += vec(r.val);
            bbs += vec(r.bcx.llbb);
2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934
        }
    }

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

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

        case (_) { /* fall through */ }
2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947
    }

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

2948
fn trans_if(@block_ctxt cx, @ast.expr cond,
2949
            &ast.block thn, &option.t[@ast.expr] els) -> result {
2950 2951 2952

    auto cond_res = trans_expr(cx, cond);

2953
    auto then_cx = new_scope_block_ctxt(cx, "then");
2954 2955
    auto then_res = trans_block(then_cx, thn);

2956
    auto else_cx = new_scope_block_ctxt(cx, "else");
2957
    auto else_res = res(else_cx, C_nil());
2958 2959

    alt (els) {
2960
        case (some[@ast.expr](?elexpr)) {
2961
            else_res = trans_expr(else_cx, elexpr);
2962
        }
2963
        case (_) { /* fall through */ }
2964 2965
    }

2966
    cond_res.bcx.build.CondBr(cond_res.val,
2967 2968
                              then_cx.llbb,
                              else_cx.llbb);
2969 2970 2971 2972

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

G
Graydon Hoare 已提交
2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988
fn trans_for(@block_ctxt cx,
             @ast.decl decl,
             @ast.expr seq,
             &ast.block body) -> result {

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

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

        cx.build.Br(scope_cx.llbb);
        auto local_res = alloc_local(scope_cx, local);
2989
        auto bcx = copy_ty(local_res.bcx, INIT, local_res.val, curr, t).bcx;
2990 2991
        scope_cx.cleanups +=
            vec(clean(bind drop_slot(_, local_res.val, t)));
2992
        bcx = trans_block(bcx, body).bcx;
G
Graydon Hoare 已提交
2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010
        bcx.build.Br(next_cx.llbb);
        ret res(next_cx, C_nil());
    }


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

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

3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066

// Iterator translation

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

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

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

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

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

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

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

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

    ret result;
}

3067 3068 3069 3070
fn trans_for_each(@block_ctxt cx,
                  @ast.decl decl,
                  @ast.expr seq,
                  &ast.block body) -> result {
3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099

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

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

    // FIXME: possibly support alias-mode here?
    auto decl_ty = plain_ty(ty.ty_nil);
3100
    auto decl_id;
3101 3102 3103
    alt (decl.node) {
        case (ast.decl_local(?local)) {
            decl_ty = node_ann_type(cx.fcx.ccx, local.ann);
3104
            decl_id = local.id;
3105 3106 3107
        }
    }

3108
    auto upvars = collect_upvars(cx, body, decl_id);
3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119
    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]) {
3120 3121 3122 3123 3124 3125
                    alt (cx.fcx.llupvars.find(did)) {
                        case (none[ValueRef]) {
                            llbinding = cx.fcx.llargs.get(did);
                        }
                        case (some[ValueRef](?llval)) { llbinding = llval; }
                    }
3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144
                }
                case (some[ValueRef](?llval)) { llbinding = llval; }
            }
            llbindings += vec(llbinding);
            llbindingtys += vec(val_ty(llbinding));
        }

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

3147 3148 3149 3150 3151 3152 3153 3154 3155 3156
    // Create an environment and populate it with the bindings.
    auto llenvptrty = T_closure_ptr(cx.fcx.ccx.tn, T_ptr(T_nil()),
                                    val_ty(llbindingsptr), 0u);
    auto llenvptr = cx.build.Alloca(llvm.LLVMGetElementType(llenvptrty));

    auto llbindingsptrptr = cx.build.GEP(llenvptr,
                                         vec(C_int(0),
                                             C_int(abi.box_rc_field_body),
                                             C_int(2)));
    cx.build.Store(llbindingsptr, llbindingsptrptr);
3157 3158 3159

    // Step 2: Declare foreach body function.

3160 3161 3162 3163 3164 3165 3166 3167 3168 3169
    let str s =
        cx.fcx.ccx.names.next("_rust_foreach")
        + sep() + cx.fcx.ccx.path;

    // The 'env' arg entering the body function is a fake env member (as in
    // the env-part of the normal rust calling convention) that actually
    // points to a stack allocated env in this frame. We bundle that env
    // pointer along with the foreach-body-fn pointer into a 'normal' fn pair
    // and pass it in as a first class fn-arg to the iterator.

3170 3171 3172
    auto iter_body_llty = type_of_fn_full(cx.fcx.ccx, ast.proto_fn,
                                          none[TypeRef],
                                          vec(rec(mode=ast.val, ty=decl_ty)),
3173
                                          plain_ty(ty.ty_nil), 0u);
3174

3175 3176
    let ValueRef lliterbody = decl_fastcall_fn(cx.fcx.ccx.llmod,
                                               s, iter_body_llty);
3177 3178 3179 3180

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

3181
    auto fcx = new_fn_ctxt(cx.fcx.ccx, lliterbody);
3182 3183
    auto bcx = new_top_block_ctxt(fcx);

3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207
    // Populate the upvars from the environment.
    auto llremoteenvptr = bcx.build.PointerCast(fcx.llenv, llenvptrty);
    auto llremotebindingsptrptr = bcx.build.GEP(llremoteenvptr,
        vec(C_int(0), C_int(abi.box_rc_field_body), C_int(2)));
    auto llremotebindingsptr = bcx.build.Load(llremotebindingsptrptr);

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

        i += 1u;
    }

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

3208 3209 3210 3211
    auto res = trans_block(bcx, body);
    res.bcx.build.RetVoid();


3212
    // Step 3: Call iter passing [lliterbody, llenv], plus other args.
3213 3214

    alt (seq.node) {
3215

3216
        case (ast.expr_call(?f, ?args, ?ann)) {
3217

3218 3219 3220 3221 3222 3223 3224
            auto pair = cx.build.Alloca(T_fn_pair(cx.fcx.ccx.tn,
                                                  iter_body_llty));
            auto code_cell = cx.build.GEP(pair,
                                          vec(C_int(0),
                                              C_int(abi.fn_field_code)));
            cx.build.Store(lliterbody, code_cell);

3225 3226 3227 3228 3229 3230
            auto env_cell = cx.build.GEP(pair, vec(C_int(0),
                                                   C_int(abi.fn_field_box)));
            auto llenvblobptr = cx.build.PointerCast(llenvptr,
                T_opaque_closure_ptr(cx.fcx.ccx.tn));
            cx.build.Store(llenvblobptr, env_cell);

3231 3232
            // log "lliterbody: " + val_str(cx.fcx.ccx.tn, lliterbody);
            ret trans_call(cx, f,
3233
                           some[ValueRef](cx.build.Load(pair)),
3234 3235
                           args,
                           ann);
3236 3237
        }
    }
3238 3239 3240 3241
    fail;
}


3242 3243
fn trans_while(@block_ctxt cx, @ast.expr cond,
               &ast.block body) -> result {
3244

3245 3246
    auto cond_cx = new_scope_block_ctxt(cx, "while cond");
    auto body_cx = new_scope_block_ctxt(cx, "while loop body");
3247
    auto next_cx = new_sub_block_ctxt(cx, "next");
3248 3249

    auto body_res = trans_block(body_cx, body);
3250 3251 3252
    auto cond_res = trans_expr(cond_cx, cond);

    body_res.bcx.build.Br(cond_cx.llbb);
3253 3254 3255

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

    cx.build.Br(cond_cx.llbb);
3258 3259 3260
    ret res(next_cx, C_nil());
}

3261 3262
fn trans_do_while(@block_ctxt cx, &ast.block body,
                  @ast.expr cond) -> result {
3263

3264
    auto body_cx = new_scope_block_ctxt(cx, "do-while loop body");
3265
    auto next_cx = new_sub_block_ctxt(cx, "next");
3266 3267

    auto body_res = trans_block(body_cx, body);
3268 3269 3270 3271 3272 3273
    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);
3274 3275 3276
    ret res(next_cx, body_res.val);
}

P
Patrick Walton 已提交
3277 3278
// Pattern matching translation

3279 3280
fn trans_pat_match(@block_ctxt cx, @ast.pat pat, ValueRef llval,
                   @block_ctxt next_cx) -> result {
P
Patrick Walton 已提交
3281 3282 3283
    alt (pat.node) {
        case (ast.pat_wild(_)) { ret res(cx, llval); }
        case (ast.pat_bind(_, _, _)) { ret res(cx, llval); }
3284 3285 3286

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

3290 3291
            auto matched_cx = new_sub_block_ctxt(lleq.bcx, "matched_cx");
            lleq.bcx.build.CondBr(lleq.val, matched_cx.llbb, next_cx.llbb);
3292 3293 3294
            ret res(matched_cx, llval);
        }

P
Patrick Walton 已提交
3295
        case (ast.pat_tag(?id, ?subpats, ?vdef_opt, ?ann)) {
3296 3297 3298 3299 3300
            auto lltagptr = cx.build.PointerCast(llval,
                T_opaque_tag_ptr(cx.fcx.ccx.tn));

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

P
Patrick Walton 已提交
3303 3304 3305
            auto vdef = option.get[ast.variant_def](vdef_opt);
            auto variant_id = vdef._1;
            auto variant_tag = 0;
3306 3307

            auto variants = tag_variants(cx.fcx.ccx, vdef._0);
P
Patrick Walton 已提交
3308
            auto i = 0;
3309 3310
            for (ast.variant v in variants) {
                auto this_variant_id = v.id;
P
Patrick Walton 已提交
3311
                if (variant_id._0 == this_variant_id._0 &&
G
Graydon Hoare 已提交
3312
                    variant_id._1 == this_variant_id._1) {
P
Patrick Walton 已提交
3313 3314 3315 3316 3317 3318 3319
                    variant_tag = i;
                }
                i += 1;
            }

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

3320
            auto lleq = cx.build.ICmp(lib.llvm.LLVMIntEQ, lldiscrim,
P
Patrick Walton 已提交
3321 3322 3323
                                      C_int(variant_tag));
            cx.build.CondBr(lleq, matched_cx.llbb, next_cx.llbb);

3324 3325
            auto ty_params = node_ann_ty_params(ann);

P
Patrick Walton 已提交
3326
            if (_vec.len[@ast.pat](subpats) > 0u) {
3327 3328
                auto llblobptr = matched_cx.build.GEP(lltagptr,
                    vec(C_int(0), C_int(1)));
P
Patrick Walton 已提交
3329 3330
                auto i = 0;
                for (@ast.pat subpat in subpats) {
3331 3332
                    auto rslt = GEP_tag(matched_cx, llblobptr, vdef._0,
                                        vdef._1, ty_params, i);
3333 3334 3335
                    auto llsubvalptr = rslt.val;
                    matched_cx = rslt.bcx;

3336
                    auto llsubval = load_scalar_or_boxed(matched_cx,
G
Graydon Hoare 已提交
3337 3338
                                                         llsubvalptr,
                                                         pat_ty(subpat));
P
Patrick Walton 已提交
3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351
                    auto subpat_res = trans_pat_match(matched_cx, subpat,
                                                      llsubval, next_cx);
                    matched_cx = subpat_res.bcx;
                }
            }

            ret res(matched_cx, llval);
        }
    }

    fail;
}

3352 3353
fn trans_pat_binding(@block_ctxt cx, @ast.pat pat, ValueRef llval)
    -> result {
P
Patrick Walton 已提交
3354 3355
    alt (pat.node) {
        case (ast.pat_wild(_)) { ret res(cx, llval); }
3356
        case (ast.pat_lit(_, _)) { ret res(cx, llval); }
P
Patrick Walton 已提交
3357 3358 3359
        case (ast.pat_bind(?id, ?def_id, ?ann)) {
            auto ty = node_ann_type(cx.fcx.ccx, ann);

3360 3361 3362 3363
            auto rslt = alloc_ty(cx, ty);
            auto dst = rslt.val;
            auto bcx = rslt.bcx;

P
Patrick Walton 已提交
3364
            llvm.LLVMSetValueName(dst, _str.buf(id));
3365
            bcx.fcx.lllocals.insert(def_id, dst);
3366 3367
            bcx.cleanups +=
                vec(clean(bind drop_slot(_, dst, ty)));
P
Patrick Walton 已提交
3368

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

3374 3375 3376 3377 3378 3379 3380
            // Get the appropriate variant for this tag.
            auto vdef = option.get[ast.variant_def](vdef_opt);
            auto variant = tag_variant_with_id(cx.fcx.ccx, vdef._0, vdef._1);

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

3382 3383
            auto ty_param_substs = node_ann_ty_params(ann);

P
Patrick Walton 已提交
3384 3385 3386
            auto this_cx = cx;
            auto i = 0;
            for (@ast.pat subpat in subpats) {
3387 3388
                auto rslt = GEP_tag(this_cx, llblobptr, vdef._0, vdef._1,
                                    ty_param_substs, i);
3389 3390 3391
                this_cx = rslt.bcx;
                auto llsubvalptr = rslt.val;

3392
                auto llsubval = load_scalar_or_boxed(this_cx, llsubvalptr,
G
Graydon Hoare 已提交
3393
                                                     pat_ty(subpat));
P
Patrick Walton 已提交
3394 3395 3396
                auto subpat_res = trans_pat_binding(this_cx, subpat,
                                                    llsubval);
                this_cx = subpat_res.bcx;
3397
                i += 1;
P
Patrick Walton 已提交
3398 3399 3400 3401 3402 3403 3404
            }

            ret res(this_cx, llval);
        }
    }
}

3405 3406
fn trans_alt(@block_ctxt cx, @ast.expr expr, vec[ast.arm] arms)
    -> result {
P
Patrick Walton 已提交
3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439
    auto expr_res = trans_expr(cx, expr);

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

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

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

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

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

        this_cx = next_cx;
    }

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

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

3440
type generic_info = rec(@ty.t item_type,
3441 3442
                        vec[ValueRef] tydescs);

3443 3444
type lval_result = rec(result res,
                       bool is_mem,
3445
                       option.t[generic_info] generic,
3446 3447 3448 3449 3450
                       option.t[ValueRef] llobj);

fn lval_mem(@block_ctxt cx, ValueRef val) -> lval_result {
    ret rec(res=res(cx, val),
            is_mem=true,
3451
            generic=none[generic_info],
3452 3453 3454 3455 3456 3457
            llobj=none[ValueRef]);
}

fn lval_val(@block_ctxt cx, ValueRef val) -> lval_result {
    ret rec(res=res(cx, val),
            is_mem=false,
3458
            generic=none[generic_info],
3459 3460
            llobj=none[ValueRef]);
}
3461

3462 3463 3464 3465 3466 3467 3468 3469
fn lval_generic_fn(@block_ctxt cx,
                   ty.ty_params_and_ty tpt,
                   ast.def_id fn_id,
                   &ast.ann ann)
    -> lval_result {

    check (cx.fcx.ccx.fn_pairs.contains_key(fn_id));
    auto lv = lval_val(cx, cx.fcx.ccx.fn_pairs.get(fn_id));
3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482

    auto monoty;
    auto tys;
    alt (ann) {
        case (ast.ann_none) {
            cx.fcx.ccx.sess.bug("no type annotation for path!");
            fail;
        }
        case (ast.ann_type(?monoty_, ?tps)) {
            monoty = monoty_;
            tys = option.get[vec[@ty.t]](tps);
        }
    }
3483 3484 3485 3486 3487 3488 3489

    if (_vec.len[@ty.t](tys) != 0u) {
        auto bcx = cx;
        let vec[ValueRef] tydescs = vec();
        for (@ty.t t in tys) {
            auto td = get_tydesc(bcx, t);
            bcx = td.bcx;
3490
            _vec.push[ValueRef](tydescs, td.val);
3491 3492 3493 3494 3495 3496 3497 3498 3499 3500
        }
        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;
}

3501
fn trans_path(@block_ctxt cx, &ast.path p, &option.t[ast.def] dopt,
G
Graydon Hoare 已提交
3502
              &ast.ann ann) -> lval_result {
3503 3504 3505 3506
    alt (dopt) {
        case (some[ast.def](?def)) {
            alt (def) {
                case (ast.def_arg(?did)) {
3507 3508 3509 3510 3511 3512 3513 3514 3515
                    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);
                        }
                    }
3516 3517
                }
                case (ast.def_local(?did)) {
3518 3519 3520 3521 3522 3523 3524 3525 3526
                    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 已提交
3527
                }
P
Patrick Walton 已提交
3528 3529
                case (ast.def_binding(?did)) {
                    check (cx.fcx.lllocals.contains_key(did));
3530
                    ret lval_mem(cx, cx.fcx.lllocals.get(did));
P
Patrick Walton 已提交
3531
                }
3532 3533 3534 3535
                case (ast.def_obj_field(?did)) {
                    check (cx.fcx.llobjfields.contains_key(did));
                    ret lval_mem(cx, cx.fcx.llobjfields.get(did));
                }
3536
                case (ast.def_fn(?did)) {
3537
                    check (cx.fcx.ccx.items.contains_key(did));
3538
                    auto fn_item = cx.fcx.ccx.items.get(did);
3539
                    ret lval_generic_fn(cx, ty.item_ty(fn_item), did, ann);
3540
                }
3541
                case (ast.def_obj(?did)) {
3542 3543 3544
                    check (cx.fcx.ccx.items.contains_key(did));
                    auto fn_item = cx.fcx.ccx.items.get(did);
                    ret lval_generic_fn(cx, ty.item_ty(fn_item), did, ann);
3545
                }
3546
                case (ast.def_variant(?tid, ?vid)) {
3547
                    if (cx.fcx.ccx.fn_pairs.contains_key(vid)) {
3548 3549 3550
                        check (cx.fcx.ccx.items.contains_key(tid));
                        auto tag_item = cx.fcx.ccx.items.get(tid);
                        auto params = ty.item_ty(tag_item)._0;
3551
                        auto fty = plain_ty(ty.ty_nil);
3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562
                        alt (tag_item.node) {
                            case (ast.item_tag(_, ?variants, _, _)) {
                                for (ast.variant v in variants) {
                                    if (v.id == vid) {
                                        fty = node_ann_type(cx.fcx.ccx,
                                                            v.ann);
                                    }
                                }
                            }
                        }
                        ret lval_generic_fn(cx, tup(params, fty), vid, ann);
3563
                    } else {
3564 3565
                        // Nullary variant.
                        auto tag_ty = node_ann_type(cx.fcx.ccx, ann);
3566
                        auto lldiscrim_gv = cx.fcx.ccx.discrims.get(vid);
3567 3568 3569 3570
                        auto lldiscrim = cx.build.Load(lldiscrim_gv);

                        auto alloc_result = alloc_ty(cx, tag_ty);
                        auto lltagblob = alloc_result.val;
3571 3572 3573 3574 3575 3576 3577

                        auto lltagty;
                        if (ty.type_has_dynamic_size(tag_ty)) {
                            lltagty = T_opaque_tag(cx.fcx.ccx.tn);
                        } else {
                            lltagty = type_of(cx.fcx.ccx, tag_ty);
                        }
3578
                        auto lltagptr = alloc_result.bcx.build.PointerCast(
3579
                            lltagblob, T_ptr(lltagty));
3580 3581 3582 3583 3584 3585

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

                        ret lval_val(alloc_result.bcx, lltagptr);
3586
                    }
3587
                }
3588 3589 3590 3591
                case (ast.def_const(?did)) {
                    check (cx.fcx.ccx.consts.contains_key(did));
                    ret lval_mem(cx, cx.fcx.ccx.consts.get(did));
                }
3592 3593 3594 3595 3596 3597
                case (ast.def_native_fn(?did)) {
                    check (cx.fcx.ccx.native_items.contains_key(did));
                    auto fn_item = cx.fcx.ccx.native_items.get(did);
                    ret lval_generic_fn(cx, ty.native_item_ty(fn_item),
                                        did, ann);
                }
3598 3599
                case (_) {
                    cx.fcx.ccx.sess.unimpl("def variant in trans");
G
Graydon Hoare 已提交
3600 3601 3602
                }
            }
        }
3603
        case (none[ast.def]) {
3604
            cx.fcx.ccx.sess.err("unresolved expr_path in trans");
3605 3606 3607 3608 3609
        }
    }
    fail;
}

3610 3611
fn trans_field(@block_ctxt cx, &ast.span sp, @ast.expr base,
               &ast.ident field, &ast.ann ann) -> lval_result {
3612
    auto r = trans_expr(cx, base);
3613
    auto t = ty.expr_ty(base);
3614 3615
    r = autoderef(r.bcx, r.val, t);
    t = autoderefed_ty(t);
3616
    alt (t.struct) {
3617
        case (ty.ty_tup(_)) {
3618
            let uint ix = ty.field_num(cx.fcx.ccx.sess, sp, field);
3619
            auto v = GEP_tup_like(r.bcx, t, r.val, vec(0, ix as int));
3620
            ret lval_mem(v.bcx, v.val);
3621
        }
3622 3623
        case (ty.ty_rec(?fields)) {
            let uint ix = ty.field_idx(cx.fcx.ccx.sess, sp, field, fields);
3624
            auto v = GEP_tup_like(r.bcx, t, r.val, vec(0, ix as int));
3625
            ret lval_mem(v.bcx, v.val);
3626
        }
3627 3628
        case (ty.ty_obj(?methods)) {
            let uint ix = ty.method_idx(cx.fcx.ccx.sess, sp, field, methods);
3629 3630 3631 3632 3633 3634
            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)));
3635 3636 3637

            auto lvo = lval_mem(r.bcx, v);
            ret rec(llobj = some[ValueRef](r.val) with lvo);
3638
        }
3639
        case (_) { cx.fcx.ccx.sess.unimpl("field variant in trans_field"); }
3640 3641 3642 3643
    }
    fail;
}

3644 3645
fn trans_index(@block_ctxt cx, &ast.span sp, @ast.expr base,
               @ast.expr idx, &ast.ann ann) -> lval_result {
3646

G
Graydon Hoare 已提交
3647
    auto lv = trans_expr(cx, base);
3648
    lv = autoderef(lv.bcx, lv.val, ty.expr_ty(base));
G
Graydon Hoare 已提交
3649 3650
    auto ix = trans_expr(lv.bcx, idx);
    auto v = lv.val;
3651
    auto bcx = ix.bcx;
3652

3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664
    // Cast to an LLVM integer. Rust is less strict than LLVM in this regard.
    auto ix_val;
    auto ix_size = llsize_of_real(cx.fcx.ccx, val_ty(ix.val));
    auto int_size = llsize_of_real(cx.fcx.ccx, T_int());
    if (ix_size < int_size) {
        ix_val = bcx.build.ZExt(ix.val, T_int());
    } else if (ix_size > int_size) {
        ix_val = bcx.build.Trunc(ix.val, T_int());
    } else {
        ix_val = ix.val;
    }

3665 3666
    auto unit_sz = size_of(bcx, node_ann_type(cx.fcx.ccx, ann));
    bcx = unit_sz.bcx;
3667 3668

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

3670 3671
    auto lim = bcx.build.GEP(v, vec(C_int(0), C_int(abi.vec_elt_fill)));
    lim = bcx.build.Load(lim);
3672

3673 3674
    auto bounds_check = bcx.build.ICmp(lib.llvm.LLVMIntULT,
                                       scaled_ix, lim);
3675

3676 3677 3678
    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);
3679 3680

    // fail: bad bounds check.
B
Brian Anderson 已提交
3681
    auto fail_res = trans_fail(fail_cx, sp, "bounds check");
3682 3683 3684
    fail_res.bcx.build.Br(next_cx.llbb);

    auto body = next_cx.build.GEP(v, vec(C_int(0), C_int(abi.vec_elt_data)));
3685
    auto elt = next_cx.build.GEP(body, vec(C_int(0), ix_val));
3686
    ret lval_mem(next_cx, elt);
3687 3688
}

3689 3690 3691 3692
// 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).

3693
fn trans_lval(@block_ctxt cx, @ast.expr e) -> lval_result {
3694
    alt (e.node) {
3695 3696
        case (ast.expr_path(?p, ?dopt, ?ann)) {
            ret trans_path(cx, p, dopt, ann);
3697 3698 3699 3700
        }
        case (ast.expr_field(?base, ?ident, ?ann)) {
            ret trans_field(cx, e.span, base, ident, ann);
        }
3701 3702 3703
        case (ast.expr_index(?base, ?idx, ?ann)) {
            ret trans_index(cx, e.span, base, idx, ann);
        }
3704
        case (_) { cx.fcx.ccx.sess.unimpl("expr variant in trans_lval"); }
G
Graydon Hoare 已提交
3705 3706 3707 3708
    }
    fail;
}

3709
fn trans_cast(@block_ctxt cx, @ast.expr e, &ast.ann ann) -> result {
3710 3711 3712 3713
    auto e_res = trans_expr(cx, e);
    auto llsrctype = val_ty(e_res.val);
    auto t = node_ann_type(cx.fcx.ccx, ann);
    auto lldsttype = type_of(cx.fcx.ccx, t);
3714
    if (!ty.type_is_fp(t)) {
3715
        // TODO: native-to-native casts
3716 3717
        if (ty.type_is_native(ty.expr_ty(e))) {
            e_res.val = e_res.bcx.build.PtrToInt(e_res.val, lldsttype);
3718 3719
        } else if (ty.type_is_native(t)) {
            e_res.val = e_res.bcx.build.IntToPtr(e_res.val, lldsttype);
3720
        } else if (llvm.LLVMGetIntTypeWidth(lldsttype) >
3721
            llvm.LLVMGetIntTypeWidth(llsrctype)) {
3722
            if (ty.type_is_signed(t)) {
3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744
                // Widening signed cast.
                e_res.val =
                    e_res.bcx.build.SExtOrBitCast(e_res.val,
                                                  lldsttype);
            } else {
                // Widening unsigned cast.
                e_res.val =
                    e_res.bcx.build.ZExtOrBitCast(e_res.val,
                                                  lldsttype);
            }
        } else {
            // Narrowing cast.
            e_res.val =
                e_res.bcx.build.TruncOrBitCast(e_res.val,
                                               lldsttype);
        }
    } else {
        cx.fcx.ccx.sess.unimpl("fp cast");
    }
    ret e_res;
}

3745 3746 3747 3748
fn trans_bind_thunk(@crate_ctxt cx,
                    @ty.t incoming_fty,
                    @ty.t outgoing_fty,
                    vec[option.t[@ast.expr]] args,
3749
                    @ty.t closure_ty,
3750 3751
                    vec[@ty.t] bound_tys,
                    uint ty_param_count) -> ValueRef {
3752 3753 3754
    // Construct a thunk-call with signature incoming_fty, and that copies
    // args forward into a call to outgoing_fty.

3755
    let str s = cx.names.next("_rust_thunk") + sep() + cx.path;
3756 3757 3758
    let TypeRef llthunk_ty = get_pair_fn_ty(type_of(cx, incoming_fty));
    let ValueRef llthunk = decl_fastcall_fn(cx.llmod, s, llthunk_ty);

3759
    auto fcx = new_fn_ctxt(cx, llthunk);
3760 3761
    auto bcx = new_top_block_ctxt(fcx);

3762
    auto llclosure_ptr_ty = type_of(cx, ty.plain_box_ty(closure_ty));
3763
    auto llclosure = bcx.build.PointerCast(fcx.llenv, llclosure_ptr_ty);
3764

3765 3766 3767 3768 3769 3770
    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,
3771 3772 3773
                                         vec(C_int(0),
                                             C_int(abi.fn_field_box)));
    lltargetclosure = bcx.build.Load(lltargetclosure);
3774 3775

    auto outgoing_ret_ty = ty.ty_fn_ret(outgoing_fty);
3776
    auto outgoing_args = ty.ty_fn_args(outgoing_fty);
3777 3778 3779 3780 3781 3782 3783

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

    let vec[ValueRef] llargs = vec(llretptr,
3784
                                   fcx.lltaskptr,
3785
                                   lltargetclosure);
3786 3787 3788 3789 3790

    // Copy in the type parameters.
    let uint i = 0u;
    while (i < ty_param_count) {
        auto lltyparam_ptr =
3791 3792 3793 3794 3795 3796 3797
            GEP_tup_like(bcx, closure_ty, llclosure,
                         vec(0,
                             abi.box_rc_field_body,
                             abi.closure_elt_ty_params,
                             (i as int)));
        bcx = lltyparam_ptr.bcx;
        llargs += vec(bcx.build.Load(lltyparam_ptr.val));
3798 3799 3800
        i += 1u;
    }

3801
    let uint a = 3u;    // retptr, task ptr, env come first
3802
    let int b = 0;
3803
    let uint outgoing_arg_index = 0u;
3804 3805 3806
    let vec[TypeRef] llout_arg_tys =
        type_of_explicit_args(cx, outgoing_args);

3807
    for (option.t[@ast.expr] arg in args) {
3808 3809 3810 3811

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

3812 3813 3814 3815
        alt (arg) {

            // Arg provided at binding time; thunk copies it from closure.
            case (some[@ast.expr](_)) {
3816 3817 3818 3819 3820 3821
                auto bound_arg =
                    GEP_tup_like(bcx, closure_ty, llclosure,
                                 vec(0,
                                     abi.box_rc_field_body,
                                     abi.closure_elt_bindings,
                                     b));
3822

3823
                bcx = bound_arg.bcx;
3824 3825 3826 3827 3828 3829 3830 3831 3832
                auto val = bound_arg.val;

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

3833
                llargs += vec(val);
3834 3835 3836 3837 3838 3839
                b += 1;
            }

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

                if (ty.count_ty_params(out_arg.ty) > 0u) {
                    check (out_arg.mode == ast.alias);
3843
                    passed_arg = bcx.build.PointerCast(passed_arg,
3844
                                                       llout_arg_ty);
3845
                }
3846

3847
                llargs += vec(passed_arg);
3848 3849 3850
                a += 1u;
            }
        }
3851

3852
        outgoing_arg_index += 1u;
3853 3854 3855
    }

    // FIXME: turn this call + ret into a tail call.
3856
    auto lltargetfn = bcx.build.GEP(lltarget.val,
3857 3858
                                    vec(C_int(0),
                                        C_int(abi.fn_field_code)));
3859 3860 3861 3862 3863 3864 3865 3866 3867 3868

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

3869
    lltargetfn = bcx.build.Load(lltargetfn);
3870

3871
    auto r = bcx.build.FastCall(lltargetfn, llargs);
3872
    bcx.build.RetVoid();
3873 3874 3875 3876

    ret llthunk;
}

3877 3878 3879
fn trans_bind(@block_ctxt cx, @ast.expr f,
              vec[option.t[@ast.expr]] args,
              &ast.ann ann) -> result {
3880 3881 3882 3883
    auto f_res = trans_lval(cx, f);
    if (f_res.is_mem) {
        cx.fcx.ccx.sess.unimpl("re-binding existing function");
    } else {
3884 3885
        let vec[@ast.expr] bound = vec();

3886 3887 3888 3889 3890
        for (option.t[@ast.expr] argopt in args) {
            alt (argopt) {
                case (none[@ast.expr]) {
                }
                case (some[@ast.expr](?e)) {
3891
                    _vec.push[@ast.expr](bound, e);
3892 3893 3894
                }
            }
        }
3895 3896

        // Figure out which tydescs we need to pass, if any.
B
Brian Anderson 已提交
3897 3898
        let @ty.t outgoing_fty;
        let vec[ValueRef] lltydescs;
3899 3900 3901
        alt (f_res.generic) {
            case (none[generic_info]) {
                outgoing_fty = ty.expr_ty(f);
B
Brian Anderson 已提交
3902
                lltydescs = vec();
3903 3904 3905 3906 3907 3908 3909 3910 3911
            }
            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) {
3912 3913 3914 3915 3916 3917
            // Trivial 'binding': just return the static pair-ptr.
            ret f_res.res;
        } else {
            auto bcx = f_res.res.bcx;
            auto pair_t = node_type(cx.fcx.ccx, ann);
            auto pair_v = bcx.build.Alloca(pair_t);
3918 3919 3920 3921

            // Translate the bound expressions.
            let vec[@ty.t] bound_tys = vec();
            let vec[ValueRef] bound_vals = vec();
3922
            auto i = 0u;
3923 3924 3925
            for (@ast.expr e in bound) {
                auto arg = trans_expr(bcx, e);
                bcx = arg.bcx;
3926

3927 3928
                _vec.push[ValueRef](bound_vals, arg.val);
                _vec.push[@ty.t](bound_tys, ty.expr_ty(e));
3929 3930

                i += 1u;
3931 3932 3933
            }

            // Synthesize a closure type.
3934
            let @ty.t bindings_ty = ty.plain_tup_ty(bound_tys);
3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947

            // NB: keep this in sync with T_closure_ptr; we're making
            // a ty.t structure that has the same "shape" as the LLVM type
            // it constructs.
            let @ty.t tydesc_ty = plain_ty(ty.ty_type);

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

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

3950
            let @ty.t closure_ty = ty.plain_tup_ty(closure_tys);
3951 3952

            auto r = trans_malloc_boxed(bcx, closure_ty);
3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969
            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);
3970 3971
            bcx = bindings_tydesc.bcx;
            bcx.build.Store(bindings_tydesc.val, bound_tydesc);
3972

3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985
            // Determine the LLVM type for the outgoing function type. This
            // may be different from the type returned by trans_malloc_boxed()
            // since we have more information than that function does;
            // specifically, we know how many type descriptors the outgoing
            // function has, which type_of() doesn't, as only we know which
            // item the function refers to.
            auto llfnty = type_of_fn(bcx.fcx.ccx,
                                     ty.ty_fn_proto(outgoing_fty),
                                     ty.ty_fn_args(outgoing_fty),
                                     ty.ty_fn_ret(outgoing_fty),
                                     ty_param_count);
            auto llclosurety = T_ptr(T_fn_pair(bcx.fcx.ccx.tn, llfnty));

3986 3987
            // Store thunk-target.
            auto bound_target =
3988 3989
                bcx.build.GEP(closure,
                              vec(C_int(0),
3990
                                  C_int(abi.closure_elt_target)));
3991
            auto src = bcx.build.Load(f_res.res.val);
3992
            bound_target = bcx.build.PointerCast(bound_target, llclosurety);
3993
            bcx.build.Store(src, bound_target);
3994

3995
            // Copy expr values into boxed bindings.
3996
            i = 0u;
3997 3998 3999 4000
            auto bindings =
                bcx.build.GEP(closure,
                              vec(C_int(0),
                                  C_int(abi.closure_elt_bindings)));
4001 4002
            for (ValueRef v in bound_vals) {
                auto bound = bcx.build.GEP(bindings,
4003
                                           vec(C_int(0), C_int(i as int)));
4004
                bcx = copy_ty(r.bcx, INIT, bound, v, bound_tys.(i)).bcx;
4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024
                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;
                    }
4025 4026

                    outgoing_fty = ginfo.item_type;
4027
                }
4028 4029
            }

4030 4031 4032 4033
            // 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)));
4034 4035

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

4037
            let ValueRef llthunk =
4038
                trans_bind_thunk(cx.fcx.ccx, pair_ty, outgoing_fty,
4039
                                 args, closure_ty, bound_tys,
4040
                                 ty_param_count);
4041 4042 4043 4044 4045 4046 4047

            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)));
4048 4049 4050 4051 4052
            bcx.build.Store
                (bcx.build.PointerCast
                 (box,
                  T_opaque_closure_ptr(bcx.fcx.ccx.tn)),
                 pair_box);
4053

4054
            find_scope_cx(cx).cleanups +=
4055
                vec(clean(bind drop_slot(_, pair_v, pair_ty)));
4056

4057 4058
            ret res(bcx, pair_v);
        }
4059 4060 4061
    }
}

4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072
// 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,
4073
              option.t[ValueRef] lliterbody,
4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085
              &vec[@ast.expr] es,
              @ty.t fn_ty)
    -> tup(@block_ctxt, vec[ValueRef], ValueRef) {

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


    // Arg 0: Output pointer.
    auto retty = ty.ty_fn_ret(fn_ty);
4086 4087 4088 4089
    auto llretslot_res = alloc_ty(bcx, retty);
    bcx = llretslot_res.bcx;
    auto llretslot = llretslot_res.val;

4090 4091 4092 4093 4094 4095 4096 4097 4098 4099
    alt (gen) {
        case (some[generic_info](?g)) {
            lltydescs = g.tydescs;
            args = ty.ty_fn_args(g.item_type);
            retty = ty.ty_fn_ret(g.item_type);
        }
        case (_) {
        }
    }
    if (ty.type_has_dynamic_size(retty)) {
4100 4101
        llargs += vec(bcx.build.PointerCast(llretslot,
                                            T_typaram_ptr(cx.fcx.ccx.tn)));
4102 4103 4104 4105 4106 4107
    } else if (ty.count_ty_params(retty) != 0u) {
        // It's possible that the callee has some generic-ness somewhere in
        // its return value -- say a method signature within an obj or a fn
        // type deep in a structure -- which the caller has a concrete view
        // of. If so, cast the caller's view of the restlot to the callee's
        // view, for the sake of making a type-compatible call.
4108 4109 4110
        llargs +=
            vec(cx.build.PointerCast(llretslot,
                                     T_ptr(type_of(bcx.fcx.ccx, retty))));
4111
    } else {
4112
        llargs += vec(llretslot);
4113 4114 4115 4116
    }


    // Arg 1: Task pointer.
4117
    llargs += vec(bcx.fcx.lltaskptr);
4118 4119 4120 4121 4122 4123 4124

    // 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).
4125
            llargs += vec(bcx.build.Load(ob));
4126 4127
        }
        case (_) {
4128
            llargs += vec(llenv);
4129 4130 4131 4132 4133 4134
        }
    }

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

4135 4136 4137 4138
    // ... then possibly an lliterbody argument.
    alt (lliterbody) {
        case (none[ValueRef]) {}
        case (some[ValueRef](?lli)) {
4139
            llargs += vec(lli);
4140 4141 4142
        }
    }

4143
    // ... then explicit args.
4144 4145 4146 4147 4148 4149

    // First we figure out the caller's view of the types of the arguments.
    // This will be needed if this is a generic call, because the callee has
    // to cast her view of the arguments to the caller's view.
    auto arg_tys = type_of_explicit_args(cx.fcx.ccx, args);

4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185
    auto i = 0u;
    for (@ast.expr e in es) {
        auto mode = args.(i).mode;

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

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

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

4186 4187
        if (ty.count_ty_params(args.(i).ty) > 0u) {
            auto lldestty = arg_tys.(i);
4188 4189 4190 4191 4192 4193 4194
            if (mode == ast.val) {
                // FIXME: we'd prefer to use &&, but rustboot doesn't like it
                if (ty.type_is_structural(ty.expr_ty(e))) {
                    lldestty = T_ptr(lldestty);
                }
            }

4195
            val = bcx.build.PointerCast(val, lldestty);
4196 4197
        }

4198 4199 4200 4201 4202 4203 4204 4205 4206
        if (mode == ast.val) {
            // FIXME: we'd prefer to use &&, but rustboot doesn't like it
            if (ty.type_is_structural(ty.expr_ty(e))) {
                // Until here we've been treating structures by pointer;
                // we are now passing it as an arg, so need to load it.
                val = bcx.build.Load(val);
            }
        }

4207
        llargs += vec(val);
4208 4209 4210 4211 4212 4213
        i += 1u;
    }

    ret tup(bcx, llargs, llretslot);
}

4214
fn trans_call(@block_ctxt cx, @ast.expr f,
4215 4216 4217
              option.t[ValueRef] lliterbody,
              vec[@ast.expr] args,
              &ast.ann ann) -> result {
4218
    auto f_res = trans_lval(cx, f);
4219
    auto faddr = f_res.res.val;
4220
    auto llenv = C_null(T_opaque_closure_ptr(cx.fcx.ccx.tn));
4221 4222 4223 4224 4225 4226 4227 4228 4229

    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;
4230 4231
            auto pair = faddr;
            faddr = bcx.build.GEP(pair, vec(C_int(0),
G
Graydon Hoare 已提交
4232
                                            C_int(abi.fn_field_code)));
4233
            faddr = bcx.build.Load(faddr);
4234

4235 4236 4237 4238
            auto llclosure = bcx.build.GEP(pair,
                                           vec(C_int(0),
                                               C_int(abi.fn_field_box)));
            llenv = bcx.build.Load(llclosure);
4239
        }
4240
    }
4241 4242
    auto fn_ty = ty.expr_ty(f);
    auto ret_ty = ty.ann_to_type(ann);
G
Graydon Hoare 已提交
4243
    auto args_res = trans_args(f_res.res.bcx,
4244
                               llenv, f_res.llobj,
4245
                               f_res.generic,
4246
                               lliterbody,
4247
                               args, fn_ty);
G
Graydon Hoare 已提交
4248

4249
    auto bcx = args_res._0;
4250 4251 4252
    auto llargs = args_res._1;
    auto llretslot = args_res._2;

4253 4254 4255 4256 4257 4258 4259 4260
    /*
    log "calling: " + val_str(cx.fcx.ccx.tn, faddr);

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

4261 4262 4263 4264 4265 4266 4267 4268
    bcx.build.FastCall(faddr, llargs);
    auto retval = C_nil();

    if (!ty.type_is_nil(ret_ty)) {
        retval = load_scalar_or_boxed(bcx, llretslot, ret_ty);
        // Retval doesn't correspond to anything really tangible in the frame,
        // but it's a ref all the same, so we put a note here to drop it when
        // we're done in this scope.
4269 4270
        find_scope_cx(cx).cleanups +=
            vec(clean(bind drop_ty(_, retval, ret_ty)));
4271
    }
G
Graydon Hoare 已提交
4272

4273
    ret res(bcx, retval);
4274 4275
}

4276 4277
fn trans_tup(@block_ctxt cx, vec[ast.elt] elts,
             &ast.ann ann) -> result {
4278 4279 4280 4281 4282 4283
    auto bcx = cx;
    auto t = node_ann_type(bcx.fcx.ccx, ann);
    auto tup_res = alloc_ty(bcx, t);
    auto tup_val = tup_res.val;
    bcx = tup_res.bcx;

4284 4285
    find_scope_cx(cx).cleanups +=
        vec(clean(bind drop_ty(_, tup_val, t)));
G
Graydon Hoare 已提交
4286
    let int i = 0;
4287

4288
    for (ast.elt e in elts) {
4289 4290 4291 4292 4293 4294
        auto e_ty = ty.expr_ty(e.expr);
        auto src_res = trans_expr(bcx, e.expr);
        bcx = src_res.bcx;
        auto dst_res = GEP_tup_like(bcx, t, tup_val, vec(0, i));
        bcx = dst_res.bcx;
        bcx = copy_ty(src_res.bcx, INIT, dst_res.val, src_res.val, e_ty).bcx;
G
Graydon Hoare 已提交
4295 4296
        i += 1;
    }
4297
    ret res(bcx, tup_val);
G
Graydon Hoare 已提交
4298 4299
}

4300 4301
fn trans_vec(@block_ctxt cx, vec[@ast.expr] args,
             &ast.ann ann) -> result {
4302 4303 4304
    auto t = node_ann_type(cx.fcx.ccx, ann);
    auto unit_ty = t;
    alt (t.struct) {
4305 4306
        case (ty.ty_vec(?mt)) {
            unit_ty = mt.ty;
G
Graydon Hoare 已提交
4307 4308 4309 4310 4311 4312
        }
        case (_) {
            cx.fcx.ccx.sess.bug("non-vec type in trans_vec");
        }
    }

4313 4314 4315
    auto bcx = cx;
    auto unit_sz = size_of(bcx, unit_ty);
    bcx = unit_sz.bcx;
4316 4317
    auto data_sz = bcx.build.Mul(C_int(_vec.len[@ast.expr](args) as int),
                                 unit_sz.val);
G
Graydon Hoare 已提交
4318 4319

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

4323
    auto llty = type_of(bcx.fcx.ccx, t);
4324
    auto vec_val = vi2p(bcx, sub.val, llty);
4325 4326
    find_scope_cx(bcx).cleanups +=
        vec(clean(bind drop_ty(_, vec_val, t)));
G
Graydon Hoare 已提交
4327

4328 4329 4330 4331
    auto body = bcx.build.GEP(vec_val, vec(C_int(0),
                                           C_int(abi.vec_elt_data)));

    auto pseudo_tup_ty =
4332 4333
        ty.plain_tup_ty(_vec.init_elt[@ty.t](unit_ty,
                                             _vec.len[@ast.expr](args)));
G
Graydon Hoare 已提交
4334
    let int i = 0;
4335

G
Graydon Hoare 已提交
4336
    for (@ast.expr e in args) {
4337 4338 4339 4340
        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;
4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355

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

        auto dst_val;
        if (!ty.type_has_dynamic_size(unit_ty)) {
4356
            auto llunit_ty = type_of(cx.fcx.ccx, unit_ty);
4357 4358 4359 4360 4361 4362
            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 已提交
4363 4364
        i += 1;
    }
4365 4366 4367
    auto fill = bcx.build.GEP(vec_val,
                              vec(C_int(0), C_int(abi.vec_elt_fill)));
    bcx.build.Store(data_sz, fill);
4368

4369
    ret res(bcx, vec_val);
G
Graydon Hoare 已提交
4370 4371
}

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

4375 4376 4377 4378 4379 4380 4381
    auto bcx = cx;
    auto t = node_ann_type(bcx.fcx.ccx, ann);
    auto llty = type_of(bcx.fcx.ccx, t);
    auto rec_res = alloc_ty(bcx, t);
    auto rec_val = rec_res.val;
    bcx = rec_res.bcx;

4382 4383
    find_scope_cx(cx).cleanups +=
        vec(clean(bind drop_ty(_, rec_val, t)));
4384
    let int i = 0;
4385

G
Graydon Hoare 已提交
4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402
    auto base_val = C_nil();

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

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

    for (ty.field tf in ty_fields) {
4403
        auto e_ty = tf.mt.ty;
4404 4405
        auto dst_res = GEP_tup_like(bcx, t, rec_val, vec(0, i));
        bcx = dst_res.bcx;
G
Graydon Hoare 已提交
4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423

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

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

        bcx = src_res.bcx;
        bcx = copy_ty(bcx, INIT, dst_res.val, src_res.val, e_ty).bcx;
4424 4425
        i += 1;
    }
4426
    ret res(bcx, rec_val);
4427 4428
}

G
Graydon Hoare 已提交
4429

G
Graydon Hoare 已提交
4430

4431
fn trans_expr(@block_ctxt cx, @ast.expr e) -> result {
4432
    alt (e.node) {
4433
        case (ast.expr_lit(?lit, ?ann)) {
4434
            ret res(cx, trans_lit(cx.fcx.ccx, *lit, ann));
4435 4436
        }

4437
        case (ast.expr_unary(?op, ?x, ?ann)) {
4438
            ret trans_unary(cx, op, x, ann);
4439 4440
        }

P
Patrick Walton 已提交
4441
        case (ast.expr_binary(?op, ?x, ?y, _)) {
4442
            ret trans_binary(cx, op, x, y);
4443
        }
4444

P
Patrick Walton 已提交
4445
        case (ast.expr_if(?cond, ?thn, ?els, _)) {
4446
            ret trans_if(cx, cond, thn, els);
4447 4448
        }

G
Graydon Hoare 已提交
4449 4450 4451 4452
        case (ast.expr_for(?decl, ?seq, ?body, _)) {
            ret trans_for(cx, decl, seq, body);
        }

4453 4454 4455 4456
        case (ast.expr_for_each(?decl, ?seq, ?body, _)) {
            ret trans_for_each(cx, decl, seq, body);
        }

4457
        case (ast.expr_while(?cond, ?body, _)) {
4458
            ret trans_while(cx, cond, body);
4459 4460
        }

4461
        case (ast.expr_do_while(?body, ?cond, _)) {
4462
            ret trans_do_while(cx, body, cond);
4463 4464
        }

P
Patrick Walton 已提交
4465 4466 4467 4468
        case (ast.expr_alt(?expr, ?arms, _)) {
            ret trans_alt(cx, expr, arms);
        }

P
Patrick Walton 已提交
4469
        case (ast.expr_block(?blk, _)) {
4470
            ret trans_block(cx, blk);
4471
        }
4472

4473
        case (ast.expr_assign(?dst, ?src, ?ann)) {
4474
            auto lhs_res = trans_lval(cx, dst);
4475 4476
            check (lhs_res.is_mem);
            auto rhs_res = trans_expr(lhs_res.res.bcx, src);
4477
            auto t = node_ann_type(cx.fcx.ccx, ann);
G
Graydon Hoare 已提交
4478
            // FIXME: calculate copy init-ness in typestate.
4479 4480
            ret copy_ty(rhs_res.bcx, DROP_EXISTING,
                        lhs_res.res.val, rhs_res.val, t);
4481
        }
G
Graydon Hoare 已提交
4482

4483 4484 4485
        case (ast.expr_assign_op(?op, ?dst, ?src, ?ann)) {
            auto t = node_ann_type(cx.fcx.ccx, ann);
            auto lhs_res = trans_lval(cx, dst);
4486
            check (lhs_res.is_mem);
4487
            auto lhs_val = load_scalar_or_boxed(lhs_res.res.bcx,
G
Graydon Hoare 已提交
4488
                                                lhs_res.res.val, t);
4489
            auto rhs_res = trans_expr(lhs_res.res.bcx, src);
4490 4491
            auto v = trans_eager_binop(rhs_res.bcx, op, t,
                                       lhs_val, rhs_res.val);
4492
            // FIXME: calculate copy init-ness in typestate.
4493 4494
            ret copy_ty(v.bcx, DROP_EXISTING,
                        lhs_res.res.val, v.val, t);
4495 4496
        }

4497 4498 4499 4500
        case (ast.expr_bind(?f, ?args, ?ann)) {
            ret trans_bind(cx, f, args, ann);
        }

G
Graydon Hoare 已提交
4501
        case (ast.expr_call(?f, ?args, ?ann)) {
4502
            ret trans_call(cx, f, none[ValueRef], args, ann);
4503 4504
        }

4505
        case (ast.expr_cast(?e, _, ?ann)) {
4506
            ret trans_cast(cx, e, ann);
4507
        }
G
Graydon Hoare 已提交
4508

4509
        case (ast.expr_vec(?args, _, ?ann)) {
G
Graydon Hoare 已提交
4510 4511 4512
            ret trans_vec(cx, args, ann);
        }

G
Graydon Hoare 已提交
4513 4514 4515
        case (ast.expr_tup(?args, ?ann)) {
            ret trans_tup(cx, args, ann);
        }
G
Graydon Hoare 已提交
4516

4517 4518
        case (ast.expr_rec(?args, ?base, ?ann)) {
            ret trans_rec(cx, args, base, ann);
4519 4520
        }

4521
        case (ast.expr_ext(_, _, _, ?expanded, _)) {
4522
            ret trans_expr(cx, expanded);
4523 4524
        }

4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540
        case (ast.expr_fail) {
            ret trans_fail(cx, e.span, "explicit failure");
        }

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

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

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

4541
        case (ast.expr_put(?e)) {
4542 4543 4544
            ret trans_put(cx, e);
        }

4545 4546 4547 4548
        case (ast.expr_be(?e)) {
            ret trans_be(cx, e);
        }

B
Brian Anderson 已提交
4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564
        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);
        }

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

4568
        case (_) {
4569
            auto t = ty.expr_ty(e);
4570
            auto sub = trans_lval(cx, e);
4571
            ret res(sub.res.bcx,
4572
                    load_scalar_or_boxed(sub.res.bcx, sub.res.val, t));
4573
        }
4574
    }
4575
    cx.fcx.ccx.sess.unimpl("expr variant in trans_expr");
4576 4577 4578
    fail;
}

4579
// We pass structural values around the compiler "by pointer" and
4580 4581
// non-structural values (scalars and boxes) "by value". This function selects
// whether to load a pointer or pass it.
4582

4583 4584 4585
fn load_scalar_or_boxed(@block_ctxt cx,
                        ValueRef v,
                        @ty.t t) -> ValueRef {
4586
    if (ty.type_is_scalar(t) || ty.type_is_boxed(t) || ty.type_is_native(t)) {
4587
        ret cx.build.Load(v);
4588 4589
    } else {
        ret v;
4590 4591 4592
    }
}

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

4595
    auto sub = trans_expr(cx, e);
4596
    auto e_ty = ty.expr_ty(e);
4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617
    if (ty.type_is_fp(e_ty)) {
        let TypeRef tr;
        let bool is32bit = false;
        alt (e_ty.struct) {
            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) {
            ret trans_upcall(sub.bcx,
                             "upcall_log_float",
                             vec(sub.val));
        } else {
            auto tmp = sub.bcx.build.Alloca(tr);
4618
            sub.bcx.build.Store(sub.val, tmp);
4619 4620 4621 4622
            auto v = vp2i(sub.bcx, tmp);
            ret trans_upcall(sub.bcx,
                             "upcall_log_double",
                             vec(v));
4623 4624 4625
        }
    }

4626
    alt (e_ty.struct) {
4627
        case (ty.ty_str) {
4628
            auto v = vp2i(sub.bcx, sub.val);
4629 4630 4631
            ret trans_upcall(sub.bcx,
                             "upcall_log_str",
                             vec(v));
4632 4633
        }
        case (_) {
4634 4635 4636
            ret trans_upcall(sub.bcx,
                             "upcall_log_int",
                             vec(sub.val));
4637 4638
        }
    }
4639
    fail;
4640 4641
}

4642
fn trans_check_expr(@block_ctxt cx, @ast.expr e) -> result {
4643 4644 4645
    auto cond_res = trans_expr(cx, e);

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

4650
    auto next_cx = new_sub_block_ctxt(cx, "next");
4651 4652 4653 4654 4655 4656 4657
    fail_res.bcx.build.Br(next_cx.llbb);
    cond_res.bcx.build.CondBr(cond_res.val,
                              next_cx.llbb,
                              fail_cx.llbb);
    ret res(next_cx, C_nil());
}

B
Brian Anderson 已提交
4658 4659 4660 4661 4662 4663 4664 4665 4666
fn trans_fail(@block_ctxt cx, common.span sp, str fail_str) -> result {
    auto V_fail_str = p2i(C_cstr(cx.fcx.ccx, fail_str));
    auto V_filename = p2i(C_cstr(cx.fcx.ccx, sp.filename));
    auto V_line = sp.lo.line as int;
    auto args = vec(V_fail_str, V_filename, C_int(V_line));

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

4667
fn trans_put(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691
    auto llcallee = C_nil();
    auto llenv = C_nil();

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

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

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

            auto llarg = r.val;
4694
            bcx = r.bcx;
4695 4696 4697 4698 4699 4700
            if (ty.type_is_structural(ty.expr_ty(x))) {
                // Until here we've been treating structures by pointer; we
                // are now passing it as an arg, so need to load it.
                llarg = bcx.build.Load(llarg);
            }

4701
            llargs += vec(llarg);
4702 4703
        }
    }
4704

4705
    ret res(bcx, bcx.build.FastCall(llcallee, llargs));
4706 4707
}

4708 4709 4710 4711
fn trans_ret(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
    auto bcx = cx;
    auto val = C_nil();

4712 4713
    alt (e) {
        case (some[@ast.expr](?x)) {
4714
            auto t = ty.expr_ty(x);
4715 4716 4717
            auto r = trans_expr(cx, x);
            bcx = r.bcx;
            val = r.val;
4718
            bcx = copy_ty(bcx, INIT, cx.fcx.llretptr, val, t).bcx;
4719
        }
4720
        case (_) { /* fall through */  }
4721 4722
    }

4723 4724
    // Run all cleanups and back out.
    let bool more_cleanups = true;
4725
    auto cleanup_cx = cx;
4726
    while (more_cleanups) {
4727
        bcx = trans_block_cleanups(bcx, cleanup_cx);
4728
        alt (cleanup_cx.parent) {
4729
            case (parent_some(?b)) {
4730
                cleanup_cx = b;
4731 4732 4733 4734 4735 4736 4737
            }
            case (parent_none) {
                more_cleanups = false;
            }
        }
    }

4738 4739
    bcx.build.RetVoid();
    ret res(bcx, C_nil());
4740 4741
}

4742
fn trans_be(@block_ctxt cx, @ast.expr e) -> result {
4743
    // FIXME: This should be a typestate precondition
4744
    check (ast.is_call_expr(e));
4745 4746
    // FIXME: Turn this into a real tail call once
    // calling convention issues are settled
4747 4748 4749
    ret trans_ret(cx, some(e));
}

B
Brian Anderson 已提交
4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799
fn trans_port(@block_ctxt cx, ast.ann ann) -> result {

    auto t = node_ann_type(cx.fcx.ccx, ann);
    auto unit_ty;
    alt (t.struct) {
        case (ty.ty_port(?t)) {
            unit_ty = t;
        }
        case (_) {
            cx.fcx.ccx.sess.bug("non-port type in trans_port");
            fail;
        }
    }

    auto llunit_ty = type_of(cx.fcx.ccx, unit_ty);

    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;
    auto llty = type_of(cx.fcx.ccx, t);
    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;

    auto chan_ty = node_ann_type(bcx.fcx.ccx, ann);
    auto chan_llty = type_of(bcx.fcx.ccx, chan_ty);
    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 {
4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818

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

    auto chan_ty = node_ann_type(cx.fcx.ccx, ann);
    auto unit_ty;
    alt (chan_ty.struct) {
        case (ty.ty_chan(?t)) {
            unit_ty = t;
        }
        case (_) {
            bcx.fcx.ccx.sess.bug("non-chan type in trans_send");
            fail;
        }
    }

4819 4820 4821 4822
    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;
4823

4824 4825
    find_scope_cx(bcx).cleanups +=
        vec(clean(bind drop_ty(_, data_alloc.val, unit_ty)));
4826

4827 4828 4829
    auto sub = trans_upcall(bcx, "upcall_send",
                            vec(vp2i(bcx, chn.val),
                                vp2i(bcx, data_alloc.val)));
4830 4831
    bcx = sub.bcx;

4832
    ret res(bcx, chn.val);
B
Brian Anderson 已提交
4833 4834 4835 4836
}

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

    auto bcx = cx;
B
Brian Anderson 已提交
4839 4840 4841
    auto data = trans_lval(bcx, lhs);
    check (data.is_mem);
    bcx = data.res.bcx;
4842 4843 4844 4845 4846 4847 4848 4849 4850 4851
    auto unit_ty = node_ann_type(bcx.fcx.ccx, ann);

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

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

    auto bcx = cx;
4852 4853
    auto prt = trans_expr(bcx, rhs);
    bcx = prt.bcx;
B
Brian Anderson 已提交
4854

4855
    auto sub = trans_upcall(bcx, "upcall_recv",
4856
                            vec(vp2i(bcx, lhs),
4857 4858 4859
                                vp2i(bcx, prt.val)));
    bcx = sub.bcx;

4860 4861
    auto data_load = load_scalar_or_boxed(bcx, lhs, unit_ty);
    auto cp = copy_ty(bcx, action, lhs, data_load, unit_ty);
4862
    bcx = cp.bcx;
B
Brian Anderson 已提交
4863

4864
    // TODO: Any cleanup need to be done here?
4865

4866
    ret res(bcx, lhs);
B
Brian Anderson 已提交
4867 4868
}

4869 4870 4871 4872 4873 4874 4875 4876 4877
fn init_local(@block_ctxt cx, @ast.local local) -> result {

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

    find_scope_cx(cx).cleanups +=
4878
        vec(clean(bind drop_slot(_, llptr, ty)));
4879 4880

    alt (local.init) {
4881
        case (some[ast.initializer](?init)) {
4882 4883 4884 4885 4886 4887 4888 4889 4890
            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;
                }
            }
4891 4892 4893
        }
        case (_) {
            if (middle.ty.type_has_dynamic_size(ty)) {
4894 4895
                auto llsz = size_of(bcx, ty);
                bcx = call_bzero(llsz.bcx, llptr, llsz.val).bcx;
4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908

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

fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
    auto bcx = cx;
4909
    alt (s.node) {
4910
        case (ast.stmt_expr(?e)) {
4911
            bcx = trans_expr(cx, e).bcx;
4912
        }
4913

4914 4915 4916
        case (ast.stmt_decl(?d)) {
            alt (d.node) {
                case (ast.decl_local(?local)) {
4917
                    bcx = init_local(bcx, local).bcx;
4918
                }
G
Graydon Hoare 已提交
4919 4920 4921
                case (ast.decl_item(?i)) {
                    trans_item(cx.fcx.ccx, *i);
                }
4922 4923
            }
        }
4924
        case (_) {
4925
            cx.fcx.ccx.sess.unimpl("stmt variant");
4926 4927
        }
    }
4928
    ret res(bcx, C_nil());
4929 4930
}

4931
fn new_builder(BasicBlockRef llbb) -> builder {
4932 4933 4934 4935 4936
    let BuilderRef llbuild = llvm.LLVMCreateBuilder();
    llvm.LLVMPositionBuilderAtEnd(llbuild, llbb);
    ret builder(llbuild);
}

4937 4938
// You probably don't want to use this one. See the
// next three functions instead.
4939
fn new_block_ctxt(@fn_ctxt cx, block_parent parent,
4940
                  block_kind kind,
4941
                  str name) -> @block_ctxt {
4942
    let vec[cleanup] cleanups = vec();
4943
    let BasicBlockRef llbb =
4944
        llvm.LLVMAppendBasicBlock(cx.llfn,
4945
                                  _str.buf(cx.ccx.names.next(name)));
4946

4947
    ret @rec(llbb=llbb,
4948
             build=new_builder(llbb),
4949
             parent=parent,
4950
             kind=kind,
4951
             mutable cleanups=cleanups,
4952 4953 4954
             fcx=cx);
}

4955 4956
// 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 {
4957 4958 4959 4960 4961 4962 4963
    auto cx = new_block_ctxt(fcx, parent_none, SCOPE_BLOCK,
                             "function top level");

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

4966 4967
// 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 {
4968
    ret new_block_ctxt(bcx.fcx, parent_some(bcx), SCOPE_BLOCK, n);
4969 4970
}

4971
// Use this when you're making a general CFG BB within a scope.
4972
fn new_sub_block_ctxt(@block_ctxt bcx, str n) -> @block_ctxt {
4973
    ret new_block_ctxt(bcx.fcx, parent_some(bcx), NON_SCOPE_BLOCK, n);
4974
}
4975

4976

4977 4978
fn trans_block_cleanups(@block_ctxt cx,
                        @block_ctxt cleanup_cx) -> @block_ctxt {
4979
    auto bcx = cx;
4980

4981
    if (cleanup_cx.kind != SCOPE_BLOCK) {
4982 4983 4984
        check (_vec.len[cleanup](cleanup_cx.cleanups) == 0u);
    }

4985 4986 4987 4988
    auto i = _vec.len[cleanup](cleanup_cx.cleanups);
    while (i > 0u) {
        i -= 1u;
        auto c = cleanup_cx.cleanups.(i);
4989
        alt (c) {
4990
            case (clean(?cfn)) {
4991
                bcx = cfn(bcx).bcx;
4992 4993 4994
            }
        }
    }
4995 4996 4997
    ret bcx;
}

4998 4999 5000 5001 5002 5003 5004 5005 5006 5007
iter block_locals(&ast.block b) -> @ast.local {
    // FIXME: putting from inside an iter block doesn't work, so we can't
    // use the index here.
    for (@ast.stmt s in b.node.stmts) {
        alt (s.node) {
            case (ast.stmt_decl(?d)) {
                alt (d.node) {
                    case (ast.decl_local(?local)) {
                        put local;
                    }
5008
                    case (_) { /* fall through */ }
5009 5010
                }
            }
5011
            case (_) { /* fall through */ }
5012 5013 5014 5015
        }
    }
}

5016
fn alloc_ty(@block_ctxt cx, @ty.t t) -> result {
5017
    auto val = C_int(0);
5018
    auto bcx = cx;
5019
    if (ty.type_has_dynamic_size(t)) {
5020 5021 5022
        auto n = size_of(bcx, t);
        bcx = n.bcx;
        val = bcx.build.ArrayAlloca(T_i8(), n.val);
5023
    } else {
5024
        val = bcx.build.Alloca(type_of(cx.fcx.ccx, t));
5025
    }
5026
    ret res(bcx, val);
5027 5028
}

5029 5030 5031 5032 5033 5034 5035
fn alloc_local(@block_ctxt cx, @ast.local local) -> result {
    auto t = node_ann_type(cx.fcx.ccx, local.ann);
    auto r = alloc_ty(cx, t);
    r.bcx.fcx.lllocals.insert(local.id, r.val);
    ret r;
}

5036
fn trans_block(@block_ctxt cx, &ast.block b) -> result {
5037 5038
    auto bcx = cx;

5039
    for each (@ast.local local in block_locals(b)) {
5040
        bcx = alloc_local(bcx, local).bcx;
5041
    }
5042
    auto r = res(bcx, C_nil());
5043

5044
    for (@ast.stmt s in b.node.stmts) {
5045 5046
        r = trans_stmt(bcx, *s);
        bcx = r.bcx;
5047 5048 5049 5050 5051
        // 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;
        }
5052
    }
5053

5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066
    alt (b.node.expr) {
        case (some[@ast.expr](?e)) {
            r = trans_expr(bcx, e);
            bcx = r.bcx;
            if (is_terminated(bcx)) {
                ret r;
            }
        }
        case (none[@ast.expr]) {
            r = res(bcx, C_nil());
        }
    }

5067
    bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
5068
    ret res(bcx, r.val);
5069 5070
}

5071 5072 5073 5074 5075 5076 5077
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args

5078
fn new_fn_ctxt(@crate_ctxt cx,
5079
               ValueRef llfndecl) -> @fn_ctxt {
5080

5081 5082 5083
    let ValueRef llretptr = llvm.LLVMGetParam(llfndecl, 0u);
    let ValueRef lltaskptr = llvm.LLVMGetParam(llfndecl, 1u);
    let ValueRef llenv = llvm.LLVMGetParam(llfndecl, 2u);
5084 5085

    let hashmap[ast.def_id, ValueRef] llargs = new_def_hash[ValueRef]();
5086 5087
    let hashmap[ast.def_id, ValueRef] llobjfields = new_def_hash[ValueRef]();
    let hashmap[ast.def_id, ValueRef] lllocals = new_def_hash[ValueRef]();
5088
    let hashmap[ast.def_id, ValueRef] llupvars = new_def_hash[ValueRef]();
5089
    let hashmap[ast.def_id, ValueRef] lltydescs = new_def_hash[ValueRef]();
5090

5091
    ret @rec(llfn=llfndecl,
5092
             lltaskptr=lltaskptr,
5093 5094
             llenv=llenv,
             llretptr=llretptr,
5095
             mutable llself=none[ValueRef],
5096
             mutable lliterbody=none[ValueRef],
5097
             llargs=llargs,
5098
             llobjfields=llobjfields,
5099
             lllocals=lllocals,
5100
             llupvars=llupvars,
5101
             lltydescs=lltydescs,
5102
             ccx=cx);
5103 5104
}

5105 5106 5107 5108 5109 5110 5111
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args

5112
fn create_llargs_for_fn_args(&@fn_ctxt cx,
5113
                             ast.proto proto,
5114
                             option.t[TypeRef] ty_self,
5115
                             @ty.t ret_ty,
5116
                             &vec[ast.arg] args,
5117
                             &vec[ast.ty_param] ty_params) {
5118 5119 5120 5121 5122 5123 5124 5125 5126 5127

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

    auto arg_n = 3u;
5128

5129 5130 5131 5132 5133 5134 5135
    if (ty_self == none[TypeRef]) {
        for (ast.ty_param tp in ty_params) {
            auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n);
            check (llarg as int != 0);
            cx.lltydescs.insert(tp.id, llarg);
            arg_n += 1u;
        }
5136 5137
    }

5138
    if (proto == ast.proto_iter) {
5139 5140 5141 5142 5143
        auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n);
        check (llarg as int != 0);
        cx.lliterbody = some[ValueRef](llarg);
        arg_n += 1u;
    }
5144

5145 5146 5147 5148 5149 5150 5151 5152
    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;
    }
}

5153 5154 5155 5156
// 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.

5157 5158 5159 5160
fn copy_args_to_allocas(@block_ctxt cx,
                        option.t[TypeRef] ty_self,
                        vec[ast.arg] args,
                        vec[ty.arg] arg_tys) {
5161 5162 5163

    let uint arg_n = 0u;

5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177
    alt (cx.fcx.llself) {
        case (some[ValueRef](?self_v)) {
            alt (ty_self) {
                case (some[TypeRef](?self_t)) {
                    auto alloca = cx.build.Alloca(self_t);
                    cx.build.Store(self_v, alloca);
                    cx.fcx.llself = some[ValueRef](alloca);
                }
            }
        }
        case (_) {
        }
    }

5178
    for (ast.arg aarg in args) {
5179 5180 5181 5182 5183 5184 5185 5186 5187
        if (aarg.mode != ast.alias) {
            auto arg_t = type_of_arg(cx.fcx.ccx, arg_tys.(arg_n));
            auto alloca = cx.build.Alloca(arg_t);
            auto argval = cx.fcx.llargs.get(aarg.id);
            cx.build.Store(argval, alloca);
            // Overwrite the llargs entry for this arg with its alloca.
            cx.fcx.llargs.insert(aarg.id, alloca);
        }

5188 5189 5190 5191
        arg_n += 1u;
    }
}

5192 5193 5194 5195 5196
fn is_terminated(@block_ctxt cx) -> bool {
    auto inst = llvm.LLVMGetLastInstruction(cx.llbb);
    ret llvm.LLVMIsATerminatorInst(inst) as int != 0;
}

5197 5198
fn arg_tys_of_fn(ast.ann ann) -> vec[ty.arg] {
    alt (ty.ann_to_type(ann).struct) {
5199
        case (ty.ty_fn(_, ?arg_tys, _)) {
5200 5201 5202 5203 5204 5205
            ret arg_tys;
        }
    }
    fail;
}

5206 5207
fn ret_ty_of_fn_ty(@ty.t t) -> @ty.t {
    alt (t.struct) {
5208
        case (ty.ty_fn(_, _, ?ret_ty)) {
5209 5210 5211 5212 5213 5214
            ret ret_ty;
        }
    }
    fail;
}

5215 5216 5217 5218 5219

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

5220 5221
fn populate_fn_ctxt_from_llself(@block_ctxt cx, ValueRef llself) -> result {
    auto bcx = cx;
5222

5223
    let vec[@ty.t] field_tys = vec();
5224

5225 5226
    for (ast.obj_field f in bcx.fcx.ccx.obj_fields) {
        field_tys += vec(node_ann_type(bcx.fcx.ccx, f.ann));
5227 5228
    }

5229 5230
    // Synthesize a tuple type for the fields so that GEP_tup_like() can work
    // its magic.
5231
    auto fields_tup_ty = ty.plain_tup_ty(field_tys);
5232 5233 5234

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

    auto box_cell =
5237 5238 5239
        bcx.build.GEP(llself,
                      vec(C_int(0),
                          C_int(abi.obj_field_box)));
5240

5241
    auto box_ptr = bcx.build.Load(box_cell);
5242

5243
    box_ptr = bcx.build.PointerCast(box_ptr, llobj_box_ty);
5244

5245
    auto obj_typarams = bcx.build.GEP(box_ptr,
5246 5247 5248 5249
                                     vec(C_int(0),
                                         C_int(abi.box_rc_field_body),
                                         C_int(abi.obj_body_elt_typarams)));

5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264
    // The object fields immediately follow the type parameters, so we skip
    // over them to get the pointer.
    auto obj_fields = bcx.build.Add(vp2i(bcx, obj_typarams),
        llsize_of(llvm.LLVMGetElementType(val_ty(obj_typarams))));

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

5265 5266

    let int i = 0;
5267

5268 5269 5270 5271 5272 5273
    for (ast.ty_param p in bcx.fcx.ccx.obj_typarams) {
        let ValueRef lltyparam = bcx.build.GEP(obj_typarams,
                                               vec(C_int(0),
                                                   C_int(i)));
        lltyparam = bcx.build.Load(lltyparam);
        bcx.fcx.lltydescs.insert(p.id, lltyparam);
5274 5275 5276 5277
        i += 1;
    }

    i = 0;
5278 5279 5280 5281
    for (ast.obj_field f in bcx.fcx.ccx.obj_fields) {
        auto rslt = GEP_tup_like(bcx, fields_tup_ty, obj_fields, vec(0, i));
        bcx = rslt.bcx;
        auto llfield = rslt.val;
5282 5283 5284
        cx.fcx.llobjfields.insert(f.id, llfield);
        i += 1;
    }
5285 5286

    ret res(bcx, C_nil());
5287 5288
}

5289 5290 5291
fn trans_fn(@crate_ctxt cx, &ast._fn f, ast.def_id fid,
            option.t[TypeRef] ty_self,
            &vec[ast.ty_param] ty_params, &ast.ann ann) {
5292

5293 5294 5295
    auto llfndecl = cx.item_ids.get(fid);
    cx.item_names.insert(cx.path, llfndecl);

5296
    auto fcx = new_fn_ctxt(cx, llfndecl);
5297
    create_llargs_for_fn_args(fcx, f.proto,
5298
                              ty_self, ret_ty_of_fn(ann),
5299
                              f.decl.inputs, ty_params);
5300
    auto bcx = new_top_block_ctxt(fcx);
5301

5302
    copy_args_to_allocas(bcx, ty_self, f.decl.inputs,
5303 5304 5305 5306
                         arg_tys_of_fn(ann));

    alt (fcx.llself) {
        case (some[ValueRef](?llself)) {
5307
            bcx = populate_fn_ctxt_from_llself(bcx, llself).bcx;
5308 5309 5310 5311
        }
        case (_) {
        }
    }
5312

5313 5314
    auto res = trans_block(bcx, f.body);
    if (!is_terminated(res.bcx)) {
5315 5316
        // FIXME: until LLVM has a unit type, we are moving around
        // C_nil values rather than their void type.
5317
        res.bcx.build.RetVoid();
5318
    }
5319 5320
}

5321 5322 5323
fn trans_vtbl(@crate_ctxt cx, TypeRef self_ty,
              &ast._obj ob,
              &vec[ast.ty_param] ty_params) -> ValueRef {
G
Graydon Hoare 已提交
5324
    let vec[ValueRef] methods = vec();
5325 5326 5327 5328 5329 5330 5331 5332 5333

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

5335 5336
        auto llfnty = T_nil();
        alt (node_ann_type(cx, m.node.ann).struct) {
5337 5338
            case (ty.ty_fn(?proto, ?inputs, ?output)) {
                llfnty = type_of_fn_full(cx, proto,
5339
                                         some[TypeRef](self_ty),
5340 5341
                                         inputs, output,
                                         _vec.len[ast.ty_param](ty_params));
5342 5343 5344
            }
        }

5345
        let @crate_ctxt mcx = @rec(path=cx.path + sep() + m.node.ident
5346 5347
                                   with *cx);

5348
        let str s = cx.names.next("_rust_method") + sep() + mcx.path;
5349 5350
        let ValueRef llfn = decl_fastcall_fn(cx.llmod, s, llfnty);
        cx.item_ids.insert(m.node.id, llfn);
P
Patrick Walton 已提交
5351
        cx.item_symbols.insert(m.node.id, s);
5352

5353 5354
        trans_fn(mcx, m.node.meth, m.node.id, some[TypeRef](self_ty),
                 ty_params, m.node.ann);
5355
        methods += vec(llfn);
G
Graydon Hoare 已提交
5356
    }
5357 5358 5359
    auto vtbl = C_struct(methods);
    auto gvar = llvm.LLVMAddGlobal(cx.llmod,
                                   val_ty(vtbl),
5360
                                   _str.buf("_rust_vtbl" + sep() + cx.path));
5361 5362
    llvm.LLVMSetInitializer(gvar, vtbl);
    llvm.LLVMSetGlobalConstant(gvar, True);
5363 5364
    llvm.LLVMSetLinkage(gvar, lib.llvm.LLVMPrivateLinkage
                        as llvm.Linkage);
5365
    ret gvar;
G
Graydon Hoare 已提交
5366 5367
}

5368 5369
fn trans_obj(@crate_ctxt cx, &ast._obj ob, ast.def_id oid,
             &vec[ast.ty_param] ty_params, &ast.ann ann) {
5370 5371 5372 5373

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

5374
    // Translate obj ctor args to function arguments.
5375 5376 5377 5378 5379 5380 5381 5382
    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));
    }

5383
    auto fcx = new_fn_ctxt(cx, llctor_decl);
5384
    create_llargs_for_fn_args(fcx, ast.proto_fn,
5385
                              none[TypeRef], ret_ty_of_fn(ann),
5386
                              fn_args, ty_params);
5387 5388 5389

    auto bcx = new_top_block_ctxt(fcx);

5390
    let vec[ty.arg] arg_tys = arg_tys_of_fn(ann);
5391
    copy_args_to_allocas(bcx, none[TypeRef], fn_args, arg_tys);
5392

5393
    auto llself_ty = type_of(cx, ret_ty_of_fn(ann));
5394
    auto pair = bcx.fcx.llretptr;
5395
    auto vtbl = trans_vtbl(cx, llself_ty, ob, ty_params);
5396 5397 5398
    auto pair_vtbl = bcx.build.GEP(pair,
                                   vec(C_int(0),
                                       C_int(abi.obj_field_vtbl)));
5399 5400 5401
    auto pair_box = bcx.build.GEP(pair,
                                  vec(C_int(0),
                                      C_int(abi.obj_field_box)));
5402
    bcx.build.Store(vtbl, pair_vtbl);
5403

5404
    let TypeRef llbox_ty = T_opaque_obj_ptr(cx.tn);
5405 5406 5407 5408

    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.
5409 5410 5411 5412 5413
        bcx.build.Store(C_null(llbox_ty), pair_box);
    } else {
        // Malloc a box for the body and copy args in.
        let vec[@ty.t] obj_fields = vec();
        for (ty.arg a in arg_tys) {
5414
            _vec.push[@ty.t](obj_fields, a.ty);
5415
        }
5416 5417

        // Synthesize an obj body type.
5418 5419 5420
        auto tydesc_ty = plain_ty(ty.ty_type);
        let vec[@ty.t] tps = vec();
        for (ast.ty_param tp in ty_params) {
5421
            _vec.push[@ty.t](tps, tydesc_ty);
5422 5423
        }

5424 5425 5426 5427 5428 5429
        let @ty.t typarams_ty = ty.plain_tup_ty(tps);
        let @ty.t fields_ty = ty.plain_tup_ty(obj_fields);
        let @ty.t body_ty = ty.plain_tup_ty(vec(tydesc_ty,
                                                typarams_ty,
                                                fields_ty));
        let @ty.t boxed_body_ty = ty.plain_box_ty(body_ty);
5430

5431
        // Malloc a box for the body.
5432
        auto box = trans_malloc_boxed(bcx, body_ty);
5433 5434 5435 5436 5437 5438 5439 5440
        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);
5441

5442 5443
        // Store body tydesc.
        auto body_tydesc =
5444 5445 5446
            GEP_tup_like(bcx, body_ty, body.val,
                         vec(0, abi.obj_body_elt_tydesc));
        bcx = body_tydesc.bcx;
5447

5448 5449 5450
        auto body_td = get_tydesc(bcx, body_ty);
        bcx = body_td.bcx;
        bcx.build.Store(body_td.val, body_tydesc.val);
5451

5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466
        // Copy typarams into captured typarams.
        auto body_typarams =
            GEP_tup_like(bcx, body_ty, body.val,
                         vec(0, abi.obj_body_elt_typarams));
        bcx = body_typarams.bcx;
        let int i = 0;
        for (ast.ty_param tp in ty_params) {
            auto typaram = bcx.fcx.lltydescs.get(tp.id);
            auto capture = GEP_tup_like(bcx, typarams_ty, body_typarams.val,
                                        vec(0, i));
            bcx = capture.bcx;
            bcx = copy_ty(bcx, INIT, capture.val, typaram, tydesc_ty).bcx;
            i += 1;
        }

5467 5468
        // Copy args into body fields.
        auto body_fields =
5469 5470 5471
            GEP_tup_like(bcx, body_ty, body.val,
                         vec(0, abi.obj_body_elt_fields));
        bcx = body_fields.bcx;
5472

5473
        i = 0;
5474
        for (ast.obj_field f in ob.fields) {
5475 5476
            auto arg = bcx.fcx.llargs.get(f.id);
            arg = load_scalar_or_boxed(bcx, arg, arg_tys.(i).ty);
5477 5478 5479 5480
            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;
5481 5482 5483
            i += 1;
        }
        // Store box ptr in outer pair.
5484
        auto p = bcx.build.PointerCast(box.val, llbox_ty);
5485
        bcx.build.Store(p, pair_box);
5486
    }
5487
    bcx.build.RetVoid();
5488 5489
}

5490
fn trans_tag_variant(@crate_ctxt cx, ast.def_id tag_id,
5491 5492
                     &ast.variant variant, int index,
                     &vec[ast.ty_param] ty_params) {
5493
    if (_vec.len[ast.variant_arg](variant.args) == 0u) {
5494 5495 5496
        ret;    // nullary constructors are just constants
    }

5497 5498 5499 5500 5501 5502 5503 5504 5505 5506
    // Translate variant arguments to function arguments.
    let vec[ast.arg] fn_args = vec();
    auto i = 0u;
    for (ast.variant_arg varg in variant.args) {
        fn_args += vec(rec(mode=ast.alias,
                           ty=varg.ty,
                           ident="arg" + _uint.to_str(i, 10u),
                           id=varg.id));
    }

5507
    check (cx.item_ids.contains_key(variant.id));
5508 5509
    let ValueRef llfndecl = cx.item_ids.get(variant.id);

5510
    auto fcx = new_fn_ctxt(cx, llfndecl);
5511
    create_llargs_for_fn_args(fcx, ast.proto_fn,
5512
                              none[TypeRef], ret_ty_of_fn(variant.ann),
5513
                              fn_args, ty_params);
5514

5515 5516 5517 5518 5519
    let vec[@ty.t] ty_param_substs = vec();
    for (ast.ty_param tp in ty_params) {
        ty_param_substs += vec(plain_ty(ty.ty_param(tp.id)));
    }

5520 5521 5522
    auto bcx = new_top_block_ctxt(fcx);

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

5525 5526 5527 5528 5529
    // Cast the tag to a type we can GEP into.
    auto lltagptr = bcx.build.PointerCast(fcx.llretptr,
                                          T_opaque_tag_ptr(fcx.ccx.tn));

    auto lldiscrimptr = bcx.build.GEP(lltagptr,
5530
                                      vec(C_int(0), C_int(0)));
5531 5532
    bcx.build.Store(C_int(index), lldiscrimptr);

5533
    auto llblobptr = bcx.build.GEP(lltagptr,
5534
                                   vec(C_int(0), C_int(1)));
5535 5536 5537

    i = 0u;
    for (ast.variant_arg va in variant.args) {
5538 5539
        auto rslt = GEP_tag(bcx, llblobptr, tag_id, variant.id,
                            ty_param_substs, i as int);
5540 5541
        bcx = rslt.bcx;
        auto lldestptr = rslt.val;
5542

5543 5544 5545 5546 5547 5548
        // If this argument to this function is a tag, it'll have come in to
        // this function as an opaque blob due to the way that type_of()
        // works. So we have to cast to the destination's view of the type.
        auto llargptr = bcx.build.PointerCast(fcx.llargs.get(va.id),
            val_ty(lldestptr));

5549 5550
        auto arg_ty = arg_tys.(i).ty;
        auto llargval;
5551 5552
        if (ty.type_is_structural(arg_ty) ||
                ty.type_has_dynamic_size(arg_ty)) {
5553 5554 5555 5556 5557 5558 5559 5560
            llargval = llargptr;
        } else {
            llargval = bcx.build.Load(llargptr);
        }

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

5561 5562 5563 5564
        i += 1u;
    }

    bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
5565
    bcx.build.RetVoid();
5566 5567
}

5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583
// 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);
5584 5585 5586 5587 5588 5589

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

5592
fn trans_item(@crate_ctxt cx, &ast.item item) {
5593
    alt (item.node) {
5594
        case (ast.item_fn(?name, ?f, ?tps, ?fid, ?ann)) {
5595
            auto sub_cx = @rec(path=cx.path + sep() + name with *cx);
5596
            trans_fn(sub_cx, f, fid, none[TypeRef], tps, ann);
5597
        }
5598
        case (ast.item_obj(?name, ?ob, ?tps, ?oid, ?ann)) {
5599
            auto sub_cx = @rec(path=cx.path + sep() + name,
5600
                               obj_typarams=tps,
5601
                               obj_fields=ob.fields with *cx);
5602
            trans_obj(sub_cx, ob, oid, tps, ann);
5603
        }
5604
        case (ast.item_mod(?name, ?m, _)) {
5605
            auto sub_cx = @rec(path=cx.path + sep() + name with *cx);
5606
            trans_mod(sub_cx, m);
5607
        }
5608
        case (ast.item_tag(?name, ?variants, ?tps, ?tag_id)) {
5609
            auto sub_cx = @rec(path=cx.path + sep() + name with *cx);
5610
            auto i = 0;
5611
            for (ast.variant variant in variants) {
5612
                trans_tag_variant(sub_cx, tag_id, variant, i, tps);
5613
                i += 1;
5614 5615
            }
        }
5616
        case (ast.item_const(?name, _, ?expr, ?cid, ?ann)) {
5617
            auto sub_cx = @rec(path=cx.path + sep() + name with *cx);
5618 5619
            trans_const(sub_cx, expr, cid, ann);
        }
5620
        case (_) { /* fall through */ }
5621 5622 5623
    }
}

5624
fn trans_mod(@crate_ctxt cx, &ast._mod m) {
5625 5626
    for (@ast.item item in m.items) {
        trans_item(cx, *item);
5627 5628 5629
    }
}

5630 5631 5632 5633 5634 5635 5636 5637
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));
}

5638 5639 5640
fn decl_fn_and_pair(@crate_ctxt cx,
                    str kind,
                    str name,
5641
                    vec[ast.ty_param] ty_params,
5642 5643 5644
                    &ast.ann ann,
                    ast.def_id id) {

5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657
    auto llfty;
    auto llpairty;
    alt (node_ann_type(cx, ann).struct) {
        case (ty.ty_fn(?proto, ?inputs, ?output)) {
            llfty = type_of_fn(cx, proto, inputs, output,
                               _vec.len[ast.ty_param](ty_params));
            llpairty = T_fn_pair(cx.tn, llfty);
        }
        case (_) {
            cx.sess.bug("decl_fn_and_pair(): fn item doesn't have fn type?!");
            fail;
        }
    }
5658 5659

    // Declare the function itself.
5660
    let str s = cx.names.next("_rust_" + kind) + sep() + name;
5661 5662 5663
    let ValueRef llfn = decl_fastcall_fn(cx.llmod, s, llfty);

    // Declare the global constant pair that points to it.
5664
    let str ps = cx.names.next("_rust_" + kind + "_pair") + sep() + name;
5665 5666 5667 5668 5669 5670

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

fn register_fn_pair(@crate_ctxt cx, str ps, TypeRef llpairty, ValueRef llfn,
                    ast.def_id id) {
5671 5672 5673
    let ValueRef gvar = llvm.LLVMAddGlobal(cx.llmod, llpairty,
                                           _str.buf(ps));
    auto pair = C_struct(vec(llfn,
5674
                             C_null(T_opaque_closure_ptr(cx.tn))));
5675 5676 5677 5678 5679 5680 5681 5682

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

    cx.item_ids.insert(id, llfn);
P
Patrick Walton 已提交
5683
    cx.item_symbols.insert(id, ps);
5684 5685 5686
    cx.fn_pairs.insert(id, gvar);
}

5687 5688 5689 5690 5691 5692 5693 5694 5695 5696
// 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;
        }
5697
        case (ast.native_item_fn(_, _, _, ?tps, _, _)) {
5698 5699 5700 5701 5702 5703 5704 5705
            count = _vec.len[ast.ty_param](tps);
        }
    }
    ret count;
}

fn native_fn_wrapper_type(@crate_ctxt cx, uint ty_param_count, &ast.ann ann)
        -> TypeRef {
5706 5707 5708
    auto x = node_ann_type(cx, ann);
    alt (x.struct) {
        case (ty.ty_native_fn(?abi, ?args, ?out)) {
5709
            ret type_of_fn(cx, ast.proto_fn, args, out, ty_param_count);
5710 5711 5712 5713 5714
        }
    }
    fail;
}

5715 5716 5717 5718
fn decl_native_fn_and_pair(@crate_ctxt cx,
                           str name,
                           &ast.ann ann,
                           ast.def_id id) {
5719 5720
    auto num_ty_param = native_fn_ty_param_count(cx, id);

5721
    // Declare the wrapper.
5722
    auto wrapper_type = native_fn_wrapper_type(cx, num_ty_param, ann);
5723 5724
    let str s = cx.names.next("_rust_wrapper") + sep() + name;
    let ValueRef wrapper_fn = decl_fastcall_fn(cx.llmod, s, wrapper_type);
5725 5726
    llvm.LLVMSetLinkage(wrapper_fn, lib.llvm.LLVMPrivateLinkage
                        as llvm.Linkage);
5727

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

5732 5733
    register_fn_pair(cx, ps, wrapper_pair_type, wrapper_fn, id);

5734 5735 5736 5737
    // Build the wrapper.
    auto fcx = new_fn_ctxt(cx, wrapper_fn);
    auto bcx = new_top_block_ctxt(fcx);

5738 5739 5740 5741
    // Declare the function itself.
    auto item = cx.native_items.get(id);
    auto fn_type = node_ann_type(cx, ann);  // NB: has no type params

5742
    auto abi = ty.ty_fn_abi(fn_type);
5743 5744
    auto llfnty = type_of_native_fn(cx, abi, ty.ty_fn_args(fn_type),
                                    ty.ty_fn_ret(fn_type), num_ty_param);
5745

5746
    let vec[ValueRef] call_args = vec();
5747
    auto arg_n = 3u;
5748 5749
    auto pass_task;

5750
    auto lltaskptr = bcx.build.PtrToInt(fcx.lltaskptr, T_int());
5751 5752
    alt (abi) {
        case (ast.native_abi_rust) {
5753
            pass_task = true;
5754
            call_args += vec(lltaskptr);
5755 5756 5757
            for each (uint i in _uint.range(0u, num_ty_param)) {
                auto llarg = llvm.LLVMGetParam(fcx.llfn, arg_n);
                check (llarg as int != 0);
5758
                call_args += vec(bcx.build.PointerCast(llarg, T_i32()));
5759 5760 5761 5762
                arg_n += 1u;
            }
        }
        case (ast.native_abi_cdecl) {
5763
            pass_task = false;
5764 5765 5766 5767 5768 5769
        }
    }
    auto args = ty.ty_fn_args(fn_type);
    for (ty.arg arg in args) {
        auto llarg = llvm.LLVMGetParam(fcx.llfn, arg_n);
        check (llarg as int != 0);
5770
        call_args += vec(bcx.build.PointerCast(llarg, T_i32()));
5771 5772
        arg_n += 1u;
    }
5773

5774 5775
    auto r = trans_upcall2(bcx.build, cx.glues, lltaskptr, cx.upcalls, cx.tn,
                           cx.llmod, name, pass_task, call_args);
5776 5777
    auto rptr = bcx.build.BitCast(fcx.llretptr, T_ptr(T_i32()));
    bcx.build.Store(r, rptr);
5778
    bcx.build.RetVoid();
5779 5780
}

5781 5782
fn collect_native_item(&@crate_ctxt cx, @ast.native_item i) -> @crate_ctxt {
    alt (i.node) {
5783
        case (ast.native_item_fn(?name, _, _, _, ?fid, ?ann)) {
5784 5785
            cx.native_items.insert(fid, i);
            if (! cx.obj_methods.contains_key(fid)) {
5786
                decl_native_fn_and_pair(cx, name, ann, fid);
5787 5788 5789 5790 5791 5792
            }
        }
        case (_) { /* fall through */ }
    }
    ret cx;
}
5793

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

5796
    alt (i.node) {
5797 5798 5799 5800 5801 5802
        case (ast.item_const(?name, _, _, ?cid, ?ann)) {
            auto typ = node_ann_type(cx, ann);
            auto g = llvm.LLVMAddGlobal(cx.llmod, type_of(cx, typ),
                                        _str.buf(cx.names.next(name)));
            llvm.LLVMSetLinkage(g, lib.llvm.LLVMPrivateLinkage
                                as llvm.Linkage);
5803
            cx.items.insert(cid, i);
5804
            cx.consts.insert(cid, g);
5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820
        }

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

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

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

fn collect_item_pass2(&@crate_ctxt cx, @ast.item i) -> @crate_ctxt {
5821
    alt (i.node) {
5822
        case (ast.item_fn(?name, ?f, ?tps, ?fid, ?ann)) {
5823
            cx.items.insert(fid, i);
5824
            if (! cx.obj_methods.contains_key(fid)) {
5825
                decl_fn_and_pair(cx, "fn", name, tps, ann, fid);
5826
            }
5827 5828
        }

5829
        case (ast.item_obj(?name, ?ob, ?tps, ?oid, ?ann)) {
5830
            cx.items.insert(oid, i);
5831
            decl_fn_and_pair(cx, "obj_ctor", name, tps, ann, oid);
5832 5833 5834
            for (@ast.method m in ob.methods) {
                cx.obj_methods.insert(m.node.id, ());
            }
5835 5836
        }

5837
        case (_) { /* fall through */ }
5838 5839 5840 5841 5842
    }
    ret cx;
}


5843
fn collect_items(@crate_ctxt cx, @ast.crate crate) {
5844

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

5848 5849
    // FIXME: It might be better to use a worklist for this. An item
    // would be added to it if it depends on a not yet seen tag for example.
5850 5851 5852 5853 5854 5855 5856 5857 5858 5859

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

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

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

5861
    fold.fold_crate[@crate_ctxt](cx, fld2, crate);
5862 5863
}

5864 5865 5866 5867
fn collect_tag_ctor(&@crate_ctxt cx, @ast.item i) -> @crate_ctxt {

    alt (i.node) {

5868
        case (ast.item_tag(_, ?variants, ?tps, _)) {
5869 5870 5871
            for (ast.variant variant in variants) {
                if (_vec.len[ast.variant_arg](variant.args) != 0u) {
                    decl_fn_and_pair(cx, "tag", variant.name,
5872
                                     tps, variant.ann, variant.id);
5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893
                }
            }
        }

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

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

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

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

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


5894 5895 5896 5897 5898 5899
// The constant translation pass.

fn trans_constant(&@crate_ctxt cx, @ast.item it) -> @crate_ctxt {
    alt (it.node) {
        case (ast.item_tag(_, ?variants, _, ?tag_id)) {
            auto i = 0u;
5900 5901 5902
            auto n_variants = _vec.len[ast.variant](variants);
            while (i < n_variants) {
                auto variant = variants.(i);
5903 5904 5905 5906

                auto discrim_val = C_int(i as int);

                // FIXME: better name.
P
Patrick Walton 已提交
5907
                auto s = cx.names.next("_rust_tag_discrim");
5908
                auto discrim_gvar = llvm.LLVMAddGlobal(cx.llmod, T_int(),
P
Patrick Walton 已提交
5909
                                                       _str.buf(s));
5910 5911 5912 5913 5914 5915 5916 5917

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

5918
                cx.discrims.insert(variant.id, discrim_gvar);
P
Patrick Walton 已提交
5919
                cx.discrim_symbols.insert(variant.id, s);
5920 5921 5922 5923

                i += 1u;
            }
        }
5924 5925 5926 5927 5928 5929

        case (ast.item_const(?name, _, ?expr, ?cid, ?ann)) {
            // FIXME: The whole expr-translation system needs cloning to deal
            // with consts.
            auto v = C_int(1);
            cx.item_ids.insert(cid, v);
P
Patrick Walton 已提交
5930 5931
            auto s = cx.names.next("_rust_const") + sep() + name;
            cx.item_symbols.insert(cid, s);
5932 5933
        }

5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950
        case (_) {
            // empty
        }
    }

    ret cx;
}

fn trans_constants(@crate_ctxt cx, @ast.crate crate) {
    let fold.ast_fold[@crate_ctxt] fld =
        fold.new_identity_fold[@crate_ctxt]();

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

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

5951 5952 5953 5954 5955 5956 5957 5958 5959 5960

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

5961 5962 5963 5964
fn p2i(ValueRef v) -> ValueRef {
    ret llvm.LLVMConstPtrToInt(v, T_int());
}

5965 5966 5967 5968
fn i2p(ValueRef v, TypeRef t) -> ValueRef {
    ret llvm.LLVMConstIntToPtr(v, t);
}

5969 5970 5971
fn trans_exit_task_glue(@glue_fns glues,
                        &hashmap[str, ValueRef] upcalls,
                        type_names tn, ModuleRef llmod) {
5972 5973 5974
    let vec[TypeRef] T_args = vec();
    let vec[ValueRef] V_args = vec();

5975
    auto llfn = glues.exit_task_glue;
5976
    let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 3u);
5977

5978 5979
    auto entrybb = llvm.LLVMAppendBasicBlock(llfn, _str.buf("entry"));
    auto build = new_builder(entrybb);
5980
    auto tptr = build.PtrToInt(lltaskptr, T_int());
5981
    auto V_args2 = vec(tptr) + V_args;
5982 5983
    trans_upcall2(build, glues, lltaskptr,
                  upcalls, tn, llmod, "upcall_exit", true, V_args2);
5984
    build.RetVoid();
5985 5986
}

5987
fn create_typedefs(@crate_ctxt cx) {
5988 5989 5990
    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));
5991 5992
}

5993
fn create_crate_constant(ValueRef crate_ptr, @glue_fns glues) {
5994

5995
    let ValueRef crate_addr = p2i(crate_ptr);
5996 5997

    let ValueRef activate_glue_off =
5998
        llvm.LLVMConstSub(p2i(glues.activate_glue), crate_addr);
5999 6000

    let ValueRef yield_glue_off =
6001
        llvm.LLVMConstSub(p2i(glues.yield_glue), crate_addr);
6002

6003
    let ValueRef exit_task_glue_off =
6004
        llvm.LLVMConstSub(p2i(glues.exit_task_glue), crate_addr);
6005 6006 6007

    let ValueRef crate_val =
        C_struct(vec(C_null(T_int()),     // ptrdiff_t image_base_off
6008
                     p2i(crate_ptr),   // uintptr_t self_addr
6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019
                     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
6020 6021
                     C_null(T_int()),     // int n_libs
                     C_int(abi.abi_x86_rustc_fastcall) // uintptr_t abi_tag
6022 6023
                     ));

6024
    llvm.LLVMSetInitializer(crate_ptr, crate_val);
6025 6026
}

6027 6028 6029 6030
fn find_main_fn(@crate_ctxt cx) -> ValueRef {
    auto e = sep() + "main";
    let ValueRef v = C_nil();
    let uint n = 0u;
6031
    for each (@tup(str,ValueRef) i in cx.item_names.items()) {
6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050
        if (_str.ends_with(i._0, e)) {
            n += 1u;
            v = i._1;
        }
    }
    alt (n) {
        case (0u) {
            cx.sess.err("main fn not found");
        }
        case (1u) {
            ret v;
        }
        case (_) {
            cx.sess.err("multiple main fns found");
        }
    }
    fail;
}

6051
fn trans_main_fn(@crate_ctxt cx, ValueRef llcrate) {
6052 6053 6054
    auto T_main_args = vec(T_int(), T_int());
    auto T_rust_start_args = vec(T_int(), T_int(), T_int(), T_int());

6055 6056 6057 6058 6059 6060 6061
    auto main_name;
    if (_str.eq(std.os.target_os(), "win32")) {
        main_name = "WinMain@16";
    } else {
        main_name = "main";
    }

6062
    auto llmain =
6063
        decl_cdecl_fn(cx.llmod, main_name, T_fn(T_main_args, T_int()));
6064

6065 6066
    auto llrust_start = decl_cdecl_fn(cx.llmod, "rust_start",
                                      T_fn(T_rust_start_args, T_int()));
6067 6068 6069

    auto llargc = llvm.LLVMGetParam(llmain, 0u);
    auto llargv = llvm.LLVMGetParam(llmain, 1u);
6070
    auto llrust_main = find_main_fn(cx);
6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081

    //
    // 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(""));
6082
    auto b = new_builder(llbb);
6083 6084 6085 6086 6087 6088

    auto start_args = vec(p2i(llrust_main), p2i(llcrate), llargc, llargv);

    b.Ret(b.Call(llrust_start, start_args));
}

6089 6090
fn declare_intrinsics(ModuleRef llmod) -> hashmap[str,ValueRef] {

6091
    let vec[TypeRef] T_trap_args = vec();
6092 6093 6094 6095 6096 6097
    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;
6098 6099
}

6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117

fn trace_str(@block_ctxt cx, str s) {
    trans_upcall(cx, "upcall_trace_str", vec(p2i(C_cstr(cx.fcx.ccx, s))));
}

fn trace_word(@block_ctxt cx, ValueRef v) {
    trans_upcall(cx, "upcall_trace_word", vec(v));
}

fn trace_ptr(@block_ctxt cx, ValueRef v) {
    trace_word(cx, cx.build.PtrToInt(v, T_int()));
}

fn trap(@block_ctxt bcx) {
    let vec[ValueRef] v = vec();
    bcx.build.Call(bcx.fcx.ccx.intrinsics.get("llvm.trap"), v);
}

6118 6119 6120 6121 6122 6123 6124 6125
fn check_module(ModuleRef llmod) {
    auto pm = mk_pass_manager();
    llvm.LLVMAddVerifierPass(pm.llpm);
    llvm.LLVMRunPassManager(pm.llpm, llmod);

    // TODO: run the linter here also, once there are llvm-c bindings for it.
}

6126
fn decl_no_op_type_glue(ModuleRef llmod, type_names tn) -> ValueRef {
6127
    auto ty = T_fn(vec(T_taskptr(tn), T_ptr(T_i8())), T_void());
6128 6129 6130 6131
    ret decl_fastcall_fn(llmod, abi.no_op_type_glue_name(), ty);
}

fn make_no_op_type_glue(ValueRef fun) {
6132 6133
    auto bb_name = _str.buf("_rust_no_op_type_glue_bb");
    auto llbb = llvm.LLVMAppendBasicBlock(fun, bb_name);
6134
    new_builder(llbb).RetVoid();
6135 6136
}

6137
fn decl_memcpy_glue(ModuleRef llmod) -> ValueRef {
6138 6139 6140
    auto p8 = T_ptr(T_i8());

    auto ty = T_fn(vec(p8, p8, T_int()), T_void());
6141 6142
    ret decl_fastcall_fn(llmod, abi.memcpy_glue_name(), ty);
}
6143

6144 6145 6146 6147
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.
6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180
    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();
}

6181
fn decl_bzero_glue(ModuleRef llmod) -> ValueRef {
6182 6183 6184
    auto p8 = T_ptr(T_i8());

    auto ty = T_fn(vec(p8, T_int()), T_void());
6185 6186
    ret decl_fastcall_fn(llmod, abi.bzero_glue_name(), ty);
}
6187

6188 6189 6190
fn make_bzero_glue(ModuleRef llmod) -> ValueRef {
    // We're not using the LLVM memset intrinsic. Same as with memcpy.
    auto fun = decl_bzero_glue(llmod);
6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222
    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;
}

6223
fn make_vec_append_glue(ModuleRef llmod, type_names tn) -> ValueRef {
6224
    /*
6225
     * Args to vec_append_glue:
6226 6227 6228 6229 6230 6231 6232 6233 6234 6235
     *
     *   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.
     *
6236
     *   3. Dst vec ptr (i.e. ptr to ptr to rust_vec).
6237 6238
     *
     *   4. Src vec (i.e. ptr to rust_vec).
6239
     *
6240
     *   5. Flag indicating whether to skip trailing null on dst.
6241 6242 6243 6244 6245 6246
     *
     */

    auto ty = T_fn(vec(T_taskptr(tn),
                       T_ptr(T_tydesc(tn)),
                       T_ptr(T_tydesc(tn)),
6247 6248 6249
                       T_ptr(T_opaque_vec_ptr()),
                       T_opaque_vec_ptr(), T_bool()),
                   T_void());
6250

6251
    auto llfn = decl_fastcall_fn(llmod, abi.vec_append_glue_name(), ty);
6252 6253 6254
    ret llfn;
}

6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293

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

6294
fn trans_vec_append_glue(@crate_ctxt cx) {
6295

6296
    auto llfn = cx.glues.vec_append_glue;
6297 6298 6299 6300

    let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 0u);
    let ValueRef llvec_tydesc = llvm.LLVMGetParam(llfn, 1u);
    let ValueRef llelt_tydesc = llvm.LLVMGetParam(llfn, 2u);
6301 6302 6303
    let ValueRef lldst_vec_ptr = llvm.LLVMGetParam(llfn, 3u);
    let ValueRef llsrc_vec = llvm.LLVMGetParam(llfn, 4u);
    let ValueRef llskipnull = llvm.LLVMGetParam(llfn, 5u);
6304 6305 6306 6307 6308 6309 6310 6311 6312 6313

    auto fcx = @rec(llfn=llfn,
                    lltaskptr=lltaskptr,
                    llenv=C_null(T_ptr(T_nil())),
                    llretptr=C_null(T_ptr(T_nil())),
                    mutable llself=none[ValueRef],
                    mutable lliterbody=none[ValueRef],
                    llargs=new_def_hash[ValueRef](),
                    llobjfields=new_def_hash[ValueRef](),
                    lllocals=new_def_hash[ValueRef](),
6314
                    llupvars=new_def_hash[ValueRef](),
6315 6316 6317 6318 6319
                    lltydescs=new_def_hash[ValueRef](),
                    ccx=cx);

    auto bcx = new_top_block_ctxt(fcx);

6320 6321
    auto lldst_vec = bcx.build.Load(lldst_vec_ptr);

6322 6323
    // 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.
6324

6325
    auto llcopy_dst_ptr = bcx.build.Alloca(T_int());
6326 6327
    auto llnew_vec_res =
        trans_upcall(bcx, "upcall_vec_grow",
6328 6329 6330
                     vec(vp2i(bcx, lldst_vec),
                         vec_fill_adjusted(bcx, llsrc_vec, llskipnull),
                         vp2i(bcx, llcopy_dst_ptr),
6331 6332 6333
                         vp2i(bcx, llvec_tydesc)));

    bcx = llnew_vec_res.bcx;
6334 6335
    auto llnew_vec = vi2p(bcx, llnew_vec_res.val,
                          T_opaque_vec_ptr());
6336

6337
    put_vec_fill(bcx, llnew_vec, C_int(0));
6338

6339 6340
    auto copy_dst_cx = new_sub_block_ctxt(bcx, "copy new <- dst");
    auto copy_src_cx = new_sub_block_ctxt(bcx, "copy new <- src");
6341

6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365
    auto pp0 = bcx.build.Alloca(T_ptr(T_i8()));
    bcx.build.Store(vec_p0(bcx, llnew_vec), pp0);

    bcx.build.CondBr(bcx.build.TruncOrBitCast
                     (bcx.build.Load(llcopy_dst_ptr),
                      T_i1()),
                     copy_dst_cx.llbb,
                     copy_src_cx.llbb);


    fn copy_elts(@block_ctxt cx,
                 ValueRef elt_tydesc,
                 ValueRef dst,
                 ValueRef src,
                 ValueRef n_bytes) -> result {

        auto src_lim = cx.build.GEP(src, vec(n_bytes));

        auto elt_llsz =
            cx.build.Load(cx.build.GEP(elt_tydesc,
                                       vec(C_int(0),
                                           C_int(abi.tydesc_field_size))));

        fn take_one(ValueRef elt_tydesc,
6366 6367 6368
                    @block_ctxt cx,
                    ValueRef dst, ValueRef src) -> result {
            call_tydesc_glue_full(cx, src,
6369 6370
                                  elt_tydesc,
                                  abi.tydesc_field_take_glue_off);
6371
            ret res(cx, src);
6372 6373
        }

6374
        auto bcx = iter_sequence_raw(cx, dst, src, src_lim,
6375
                                     elt_llsz, bind take_one(elt_tydesc,
6376
                                                             _, _, _)).bcx;
6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389

        ret call_memcpy(bcx, dst, src, n_bytes);
    }

    // Copy any dst elements in, omitting null if doing str.
    auto n_bytes = vec_fill_adjusted(copy_dst_cx, lldst_vec, llskipnull);
    copy_dst_cx = copy_elts(copy_dst_cx,
                            llelt_tydesc,
                            copy_dst_cx.build.Load(pp0),
                            vec_p0(copy_dst_cx, lldst_vec),
                            n_bytes).bcx;

    put_vec_fill(copy_dst_cx, llnew_vec, n_bytes);
6390
    copy_dst_cx.build.Store(vec_p1(copy_dst_cx, llnew_vec), pp0);
6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409
    copy_dst_cx.build.Br(copy_src_cx.llbb);


    // Copy any src elements in, carrying along null if doing str.
    n_bytes = vec_fill(copy_src_cx, llsrc_vec);
    copy_src_cx = copy_elts(copy_src_cx,
                            llelt_tydesc,
                            copy_src_cx.build.Load(pp0),
                            vec_p0(copy_src_cx, llsrc_vec),
                            n_bytes).bcx;

    put_vec_fill(copy_src_cx, llnew_vec,
                 copy_src_cx.build.Add(vec_fill(copy_src_cx,
                                                llnew_vec),
                                        n_bytes));

    // Write new_vec back through the alias we were given.
    copy_src_cx.build.Store(llnew_vec, lldst_vec_ptr);
    copy_src_cx.build.RetVoid();
6410 6411 6412
}


6413 6414 6415
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()),
6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426
             /*
              * Note: the signature passed to decl_cdecl_fn here looks unusual
              * because it is. It corresponds neither to an upcall signature
              * nor a normal rust-ABI signature. In fact it is a fake
              * signature, that exists solely to acquire the task pointer as
              * an argument to the upcall. It so happens that the runtime sets
              * up the task pointer as the sole incoming argument to the frame
              * that we return into when returning to the exit task glue. So
              * this is the signature required to retrieve it.
              */
             exit_task_glue = decl_cdecl_fn(llmod, abi.exit_task_glue_name(),
6427 6428 6429 6430
                                            T_fn(vec(T_int(),
                                                     T_int(),
                                                     T_int(),
                                                     T_taskptr(tn)),
6431
                                                 T_void())),
6432

6433 6434 6435 6436 6437 6438 6439
             upcall_glues_rust =
             _vec.init_fn[ValueRef](bind decl_upcall_glue(llmod, tn, true,
                                                          _),
                                    abi.n_upcall_glues + 1 as uint),
             upcall_glues_cdecl =
             _vec.init_fn[ValueRef](bind decl_upcall_glue(llmod, tn, false,
                                                          _),
6440
                                    abi.n_upcall_glues + 1 as uint),
6441 6442 6443
             no_op_type_glue = decl_no_op_type_glue(llmod, tn),
             memcpy_glue = decl_memcpy_glue(llmod),
             bzero_glue = decl_bzero_glue(llmod),
6444
             vec_append_glue = make_vec_append_glue(llmod, tn));
6445 6446
}

6447 6448 6449 6450
fn make_common_glue(str output) {
    // FIXME: part of this is repetitive and is probably a good idea
    // to autogen it, but things like the memcpy implementation are not
    // and it might be better to just check in a .ll file.
6451 6452 6453 6454
    auto llmod =
        llvm.LLVMModuleCreateWithNameInContext(_str.buf("rust_out"),
                                               llvm.LLVMGetGlobalContext());

6455 6456
    llvm.LLVMSetDataLayout(llmod, _str.buf(x86.get_data_layout()));
    llvm.LLVMSetTarget(llmod, _str.buf(x86.get_target_triple()));
6457
    auto td = mk_target_data(x86.get_data_layout());
6458
    auto tn = mk_type_names();
6459
    let ValueRef crate_ptr =
6460
        llvm.LLVMAddGlobal(llmod, T_crate(tn), _str.buf("rust_crate"));
6461

6462 6463
    auto intrinsics = declare_intrinsics(llmod);

6464
    llvm.LLVMSetModuleInlineAsm(llmod, _str.buf(x86.get_module_asm()));
6465

6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490
    auto glues = make_glues(llmod, tn);
    create_crate_constant(crate_ptr, glues);
    make_memcpy_glue(glues.memcpy_glue);

    trans_exit_task_glue(glues, new_str_hash[ValueRef](), tn, llmod);

    check_module(llmod);

    llvm.LLVMWriteBitcodeToFile(llmod, _str.buf(output));
    llvm.LLVMDisposeModule(llmod);
}

fn trans_crate(session.session sess, @ast.crate crate, str output,
               bool shared) {
    auto llmod =
        llvm.LLVMModuleCreateWithNameInContext(_str.buf("rust_out"),
                                               llvm.LLVMGetGlobalContext());

    llvm.LLVMSetDataLayout(llmod, _str.buf(x86.get_data_layout()));
    llvm.LLVMSetTarget(llmod, _str.buf(x86.get_target_triple()));
    auto td = mk_target_data(x86.get_data_layout());
    auto tn = mk_type_names();
    let ValueRef crate_ptr =
        llvm.LLVMAddGlobal(llmod, T_crate(tn), _str.buf("rust_crate"));

6491
    auto intrinsics = declare_intrinsics(llmod);
6492

6493
    auto glues = make_glues(llmod, tn);
6494 6495
    auto hasher = ty.hash_ty;
    auto eqer = ty.eq_ty;
6496
    auto tag_sizes = map.mk_hashmap[@ty.t,uint](hasher, eqer);
6497
    auto tydescs = map.mk_hashmap[@ty.t,@tydesc_info](hasher, eqer);
6498
    let vec[ast.ty_param] obj_typarams = vec();
6499
    let vec[ast.obj_field] obj_fields = vec();
6500

6501 6502
    auto cx = @rec(sess = sess,
                   llmod = llmod,
6503
                   td = td,
6504
                   tn = tn,
6505
                   crate_ptr = crate_ptr,
6506
                   upcalls = new_str_hash[ValueRef](),
6507
                   intrinsics = intrinsics,
6508 6509
                   item_names = new_str_hash[ValueRef](),
                   item_ids = new_def_hash[ValueRef](),
6510
                   items = new_def_hash[@ast.item](),
6511
                   native_items = new_def_hash[@ast.native_item](),
P
Patrick Walton 已提交
6512
                   item_symbols = new_def_hash[str](),
6513
                   tag_sizes = tag_sizes,
6514
                   discrims = new_def_hash[ValueRef](),
P
Patrick Walton 已提交
6515
                   discrim_symbols = new_def_hash[str](),
6516
                   fn_pairs = new_def_hash[ValueRef](),
6517
                   consts = new_def_hash[ValueRef](),
6518
                   obj_methods = new_def_hash[()](),
6519
                   tydescs = tydescs,
6520
                   obj_typarams = obj_typarams,
6521
                   obj_fields = obj_fields,
6522
                   glues = glues,
6523
                   names = namegen(0),
6524
                   path = "_rust");
6525

6526 6527
    create_typedefs(cx);

6528
    collect_items(cx, crate);
6529
    collect_tag_ctors(cx, crate);
6530
    trans_constants(cx, crate);
6531
    trans_mod(cx, crate.node.module);
6532
    trans_vec_append_glue(cx);
6533
    if (!shared) {
6534
        trans_main_fn(cx, cx.crate_ptr);
6535
    }
6536

6537 6538 6539
    // Translate the metadata.
    middle.metadata.write_metadata(cx, crate);

6540 6541
    check_module(llmod);

6542
    llvm.LLVMWriteBitcodeToFile(llmod, _str.buf(output));
6543 6544 6545 6546 6547 6548 6549 6550 6551 6552
    llvm.LLVMDisposeModule(llmod);
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
6553
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
6554 6555
// End:
//