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

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

113 114
state type fn_ctxt = rec(ValueRef llfn,
                         ValueRef lltaskptr,
115 116
                         ValueRef llenv,
                         ValueRef llretptr,
117
                         mutable option.t[ValueRef] llself,
118
                         mutable option.t[ValueRef] lliterbody,
119
                         hashmap[ast.def_id, ValueRef] llargs,
120
                         hashmap[ast.def_id, ValueRef] llobjfields,
121
                         hashmap[ast.def_id, ValueRef] lllocals,
122
                         hashmap[ast.def_id, ValueRef] llupvars,
123
                         hashmap[ast.def_id, ValueRef] lltydescs,
124
                         @crate_ctxt ccx);
125

126
tag cleanup {
127
    clean(fn(@block_ctxt cx) -> result);
128 129
}

130 131 132 133 134 135

tag block_kind {
    SCOPE_BLOCK;
    NON_SCOPE_BLOCK;
}

136 137
state type block_ctxt = rec(BasicBlockRef llbb,
                            builder build,
138
                            block_parent parent,
139
                            block_kind kind,
140 141 142
                            mutable vec[cleanup] cleanups,
                            @fn_ctxt fcx);

143 144 145 146 147 148 149 150
// 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);
}

151

152 153 154
state type result = rec(mutable @block_ctxt bcx,
                        mutable ValueRef val);

155 156 157 158
fn sep() -> str {
    ret "_";
}

159 160 161 162 163 164 165 166 167 168 169 170 171 172
fn extend_path(@crate_ctxt cx, str name) -> @crate_ctxt {
  ret @rec(path = cx.path + vec(name) with *cx);
}

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


fn mangle_name_by_type(@crate_ctxt cx, @ty.t t) -> str {
    cx.sha.reset();
    auto f = metadata.def_to_str;
    cx.sha.input_str(metadata.ty_str(t, f));
    ret sep() + "rust" + sep()
173
        + _str.substr(cx.sha.result_str(), 0u, 16u) + sep()
174 175 176 177 178 179 180 181 182
        + path_name(cx.path);
}

fn mangle_name_by_seq(@crate_ctxt cx, str flav) -> str {
    ret sep() + "rust" + sep()
        + cx.names.next(flav) + sep()
        + path_name(cx.path);
}

183 184 185 186 187
fn res(@block_ctxt bcx, ValueRef val) -> result {
    ret rec(mutable bcx = bcx,
            mutable val = val);
}

188 189
fn ty_str(type_names tn, TypeRef t) -> str {
    ret lib.llvm.type_to_str(tn, t);
190 191 192 193 194 195
}

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

196 197
fn val_str(type_names tn, ValueRef v) -> str {
    ret ty_str(tn, val_ty(v));
198
}
199 200 201 202


// LLVM type constructors.

203 204 205 206 207 208 209 210 211 212 213
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.
214 215 216
    ret llvm.LLVMVoidType();
}

217 218 219 220 221
fn T_nil() -> TypeRef {
    // NB: See above in T_void().
    ret llvm.LLVMInt1Type();
}

222 223 224 225
fn T_i1() -> TypeRef {
    ret llvm.LLVMInt1Type();
}

226 227 228 229 230 231 232 233 234
fn T_i8() -> TypeRef {
    ret llvm.LLVMInt8Type();
}

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

fn T_i32() -> TypeRef {
235 236 237
    ret llvm.LLVMInt32Type();
}

238 239 240 241
fn T_i64() -> TypeRef {
    ret llvm.LLVMInt64Type();
}

242 243 244 245 246 247 248 249
fn T_f32() -> TypeRef {
    ret llvm.LLVMFloatType();
}

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

250 251 252 253
fn T_bool() -> TypeRef {
    ret T_i1();
}

254 255 256 257 258
fn T_int() -> TypeRef {
    // FIXME: switch on target type.
    ret T_i32();
}

259 260 261 262 263
fn T_float() -> TypeRef {
    // FIXME: switch on target type.
    ret T_f64();
}

264 265 266 267
fn T_char() -> TypeRef {
    ret T_i32();
}

268 269 270 271
fn T_fn(vec[TypeRef] inputs, TypeRef output) -> TypeRef {
    ret llvm.LLVMFunctionType(output,
                              _vec.buf[TypeRef](inputs),
                              _vec.len[TypeRef](inputs),
272 273 274
                              False);
}

275
fn T_fn_pair(type_names tn, TypeRef tfn) -> TypeRef {
276
    ret T_struct(vec(T_ptr(tfn),
277
                     T_opaque_closure_ptr(tn)));
278 279
}

280 281 282 283 284 285 286 287 288 289 290 291 292 293
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();
}

294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
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;
311 312
}

313 314 315 316 317 318
fn T_glue_fn(type_names tn) -> TypeRef {
    auto s = "glue_fn";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }

319 320
    // Bit of a kludge: pick the fn typeref out of the tydesc..
    let vec[TypeRef] tydesc_elts = _vec.init_elt[TypeRef](T_nil(), 10u);
321
    llvm.LLVMGetStructElementTypes(T_tydesc(tn),
322
                                   _vec.buf[TypeRef](tydesc_elts));
323 324 325 326 327
    auto t =
        llvm.LLVMGetElementType
        (tydesc_elts.(abi.tydesc_field_drop_glue_off));
    tn.associate(s, t);
    ret t;
328 329
}

330 331 332 333 334 335
fn T_tydesc(type_names tn) -> TypeRef {

    auto s = "tydesc";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }
336 337 338

    auto th = mk_type_handle();
    auto abs_tydesc = llvm.LLVMResolveTypeHandle(th.llth);
339
    auto tydescpp = T_ptr(T_ptr(abs_tydesc));
340
    auto pvoid = T_ptr(T_i8());
341
    auto glue_fn_ty = T_ptr(T_fn(vec(T_ptr(T_nil()),
342
                                     T_taskptr(tn),
343
                                     T_ptr(T_nil()),
344
                                     tydescpp,
345
                                     pvoid), T_void()));
346
    auto tydesc = T_struct(vec(tydescpp,          // first_param
347 348 349 350 351 352 353 354 355 356 357
                               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);
358 359 360
    auto t = llvm.LLVMResolveTypeHandle(th.llth);
    tn.associate(s, t);
    ret t;
361 362
}

363 364 365 366
fn T_array(TypeRef t, uint n) -> TypeRef {
    ret llvm.LLVMArrayType(t, n);
}

367 368 369 370 371
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
372 373 374
                     ));
}

375 376 377 378
fn T_opaque_vec_ptr() -> TypeRef {
    ret T_ptr(T_vec(T_int()));
}

379 380
fn T_str() -> TypeRef {
    ret T_vec(T_i8());
381 382
}

383 384 385 386
fn T_box(TypeRef t) -> TypeRef {
    ret T_struct(vec(T_int(), t));
}

B
Brian Anderson 已提交
387 388 389 390 391 392 393 394
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
}

395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
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
414 415
                          T_int(),      // int n_libs
                          T_int()       // uintptr_t abi_tag
416 417 418
                          ));
    tn.associate(s, t);
    ret t;
419 420
}

421 422
fn T_taskptr(type_names tn) -> TypeRef {
    ret T_ptr(T_task(tn));
423 424
}

425 426
// This type must never be used directly; it must always be cast away.
fn T_typaram(type_names tn) -> TypeRef {
427 428 429 430 431
    auto s = "typaram";
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }

432
    auto t = T_i8();
433 434
    tn.associate(s, t);
    ret t;
435 436
}

437 438 439 440
fn T_typaram_ptr(type_names tn) -> TypeRef {
    ret T_ptr(T_typaram(tn));
}

441 442
fn T_closure_ptr(type_names tn,
                 TypeRef lltarget_ty,
443 444
                 TypeRef llbindings_ty,
                 uint n_ty_params) -> TypeRef {
445 446 447 448

    // 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.
449
    ret T_ptr(T_box(T_struct(vec(T_ptr(T_tydesc(tn)),
450
                                 lltarget_ty,
451 452
                                 llbindings_ty,
                                 T_captured_tydescs(tn, n_ty_params))
453 454 455
                             )));
}

456 457 458 459 460 461 462
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()))),
463 464
                           T_nil(),
                           0u);
465 466
    tn.associate(s, t);
    ret t;
467 468
}

469 470 471 472 473 474 475 476 477 478 479 480
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";
481 482 483
    if (tn.name_has_type(s)) {
        ret tn.get_type(s);
    }
484
    auto t = T_struct(vec(T_int(), T_i8()));
485 486 487 488
    tn.associate(s, t);
    ret t;
}

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

493 494
fn T_captured_tydescs(type_names tn, uint n) -> TypeRef {
    ret T_struct(_vec.init_elt[TypeRef](T_ptr(T_tydesc(tn)), n));
495 496
}

497 498 499 500 501 502 503
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)));
    }
504

505
    ret T_ptr(T_box(T_obj(tn, n_captured_tydescs)));
506 507
}

508
fn T_opaque_obj_ptr(type_names tn) -> TypeRef {
509
    ret T_obj_ptr(tn, 0u);
510 511
}

512

513 514 515 516
// 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.
517
fn type_of(@crate_ctxt cx, @ty.t t) -> TypeRef {
518 519 520 521 522 523
    if (ty.type_has_dynamic_size(t)) {
        log "type_of() called on a type with dynamic size: " +
            ty.ty_to_str(t);
        fail;
    }

524
    ret type_of_inner(cx, t, false);
525 526
}

527 528 529 530 531 532
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);
533
            atys += vec(T_typaram_ptr(cx.tn));
534
        } else {
535
            let TypeRef t;
536 537
            alt (arg.mode) {
                case (ast.alias) {
538 539 540 541
                    t = T_ptr(type_of_inner(cx, arg.ty, true));
                }
                case (_) {
                    t = type_of_inner(cx, arg.ty, false);
542 543
                }
            }
544
            atys += vec(t);
545 546 547 548
        }
    }
    ret atys;
}
549 550 551 552 553 554 555 556

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

557
fn type_of_fn_full(@crate_ctxt cx,
558
                   ast.proto proto,
559 560
                   option.t[TypeRef] obj_self,
                   vec[ty.arg] inputs,
561 562
                   @ty.t output,
                   uint ty_param_count) -> TypeRef {
563
    let vec[TypeRef] atys = vec();
564

565
    // Arg 0: Output pointer.
566
    if (ty.type_has_dynamic_size(output)) {
567
        atys += vec(T_typaram_ptr(cx.tn));
568
    } else {
569
        atys += vec(T_ptr(type_of_inner(cx, output, false)));
570 571
    }

572
    // Arg 1: Task pointer.
573
    atys += vec(T_taskptr(cx.tn));
574 575

    // Arg 2: Env (closure-bindings / self-obj)
576 577 578
    alt (obj_self) {
        case (some[TypeRef](?t)) {
            check (t as int != 0);
579
            atys += vec(t);
580
        }
581
        case (_) {
582
            atys += vec(T_opaque_closure_ptr(cx.tn));
583
        }
584 585
    }

586 587 588 589
    // Args >3: ty params, if not acquired via capture...
    if (obj_self == none[TypeRef]) {
        auto i = 0u;
        while (i < ty_param_count) {
590
            atys += vec(T_ptr(T_tydesc(cx.tn)));
591 592
            i += 1u;
        }
593 594
    }

595
    if (proto == ast.proto_iter) {
596 597 598
        // 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.
599 600
        atys +=
            vec(T_fn_pair(cx.tn,
601
                          type_of_fn_full(cx, ast.proto_fn, none[TypeRef],
602
                                          vec(rec(mode=ast.val, ty=output)),
603
                                          plain_ty(ty.ty_nil), 0u)));
604 605
    }

606
    // ... then explicit args.
607
    atys += type_of_explicit_args(cx, inputs);
608

609
    ret T_fn(atys, llvm.LLVMVoidType());
610 611
}

612
fn type_of_fn(@crate_ctxt cx,
613
              ast.proto proto,
614 615 616 617 618
              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);
619 620
}

621 622
fn type_of_native_fn(@crate_ctxt cx, ast.native_abi abi,
                     vec[ty.arg] inputs,
623 624
                     @ty.t output,
                     uint ty_param_count) -> TypeRef {
625 626
    let vec[TypeRef] atys = vec();
    if (abi == ast.native_abi_rust) {
627
        atys += vec(T_taskptr(cx.tn));
628 629 630
        auto t = ty.ty_native_fn(abi, inputs, output);
        auto i = 0u;
        while (i < ty_param_count) {
631
            atys += vec(T_ptr(T_tydesc(cx.tn)));
632 633 634 635
            i += 1u;
        }
    }
    atys += type_of_explicit_args(cx, inputs);
636
    ret T_fn(atys, type_of_inner(cx, output, false));
637 638
}

639
fn type_of_inner(@crate_ctxt cx, @ty.t t, bool boxed) -> TypeRef {
640 641
    let TypeRef llty = 0 as TypeRef;

642
    alt (t.struct) {
643 644 645 646
        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(); }
647
        case (ty.ty_float) { llty = T_float(); }
648
        case (ty.ty_uint) { llty = T_int(); }
649
        case (ty.ty_machine(?tm)) {
650
            alt (tm) {
651 652 653 654 655 656 657 658 659 660
                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(); }
661 662
            }
        }
663 664
        case (ty.ty_char) { llty = T_char(); }
        case (ty.ty_str) { llty = T_ptr(T_str()); }
665 666 667 668 669 670 671
        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);
            }
672
        }
673 674
        case (ty.ty_box(?mt)) {
            llty = T_ptr(T_box(type_of_inner(cx, mt.ty, true)));
675
        }
676 677
        case (ty.ty_vec(?mt)) {
            llty = T_ptr(T_vec(type_of_inner(cx, mt.ty, true)));
678
        }
B
Brian Anderson 已提交
679 680 681 682 683 684
        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)));
        }
685
        case (ty.ty_tup(?elts)) {
686
            let vec[TypeRef] tys = vec();
687 688
            for (ty.mt elt in elts) {
                tys += vec(type_of_inner(cx, elt.ty, boxed));
689
            }
690
            llty = T_struct(tys);
691
        }
692
        case (ty.ty_rec(?fields)) {
693
            let vec[TypeRef] tys = vec();
694
            for (ty.field f in fields) {
695
                tys += vec(type_of_inner(cx, f.mt.ty, boxed));
696
            }
697
            llty = T_struct(tys);
698
        }
699
        case (ty.ty_fn(?proto, ?args, ?out)) {
700
            llty = T_fn_pair(cx.tn, type_of_fn(cx, proto, args, out, 0u));
701
        }
702
        case (ty.ty_native_fn(?abi, ?args, ?out)) {
703 704
            auto nft = type_of_native_fn(cx, abi, args, out, 0u);
            llty = T_fn_pair(cx.tn, nft);
705
        }
706
        case (ty.ty_obj(?meths)) {
707 708 709
            auto th = mk_type_handle();
            auto self_ty = llvm.LLVMResolveTypeHandle(th.llth);

710
            let vec[TypeRef] mtys = vec();
711
            for (ty.method m in meths) {
712
                let TypeRef mty =
713
                    type_of_fn_full(cx, m.proto,
714
                                    some[TypeRef](self_ty),
715
                                    m.inputs, m.output, 0u);
716
                mtys += vec(T_ptr(mty));
717
            }
718
            let TypeRef vtbl = T_struct(mtys);
719
            let TypeRef pair = T_struct(vec(T_ptr(vtbl),
720
                                            T_opaque_obj_ptr(cx.tn)));
721

722 723 724
            auto abs_pair = llvm.LLVMResolveTypeHandle(th.llth);
            llvm.LLVMRefineType(abs_pair, pair);
            abs_pair = llvm.LLVMResolveTypeHandle(th.llth);
725
            llty = abs_pair;
726
        }
727
        case (ty.ty_var(_)) {
728
            log "ty_var in trans.type_of";
729 730
            fail;
        }
731
        case (ty.ty_param(_)) {
732
            llty = T_i8();
733
        }
734
        case (ty.ty_type) { llty = T_ptr(T_tydesc(cx.tn)); }
735
    }
736 737 738 739

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

742
fn type_of_arg(@crate_ctxt cx, &ty.arg arg) -> TypeRef {
743 744 745 746 747 748 749 750 751 752 753
    alt (arg.ty.struct) {
        case (ty.ty_param(_)) {
            if (arg.mode == ast.alias) {
                ret T_typaram_ptr(cx.tn);
            }
        }
        case (_) {
            // fall through
        }
    }

754
    auto typ;
755
    if (arg.mode == ast.alias) {
756 757 758
        typ = T_ptr(type_of_inner(cx, arg.ty, true));
    } else {
        typ = type_of_inner(cx, arg.ty, false);
759
    }
760
    ret typ;
761 762
}

763 764 765 766 767 768 769 770 771
// 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 {
772 773 774 775 776 777 778
            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 已提交
779 780
                        c != (' ' as u8) && c != ('\t' as u8) &&
                        c != (';' as u8)) {
781 782 783 784 785
                        auto v = vec(c);
                        result += _str.from_bytes(v);
                    }
                }
            }
786 787 788 789 790
        }
    }
    ret result;
}

791 792 793 794 795 796
// LLVM constant constructors.

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

797
fn C_integral(int i, TypeRef t) -> ValueRef {
798 799 800 801 802 803
    // 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);
    //
804 805 806
    ret llvm.LLVMConstIntOfString(t, _str.buf(istr(i)), 10);
}

807 808 809 810
fn C_float(str s) -> ValueRef {
    ret llvm.LLVMConstRealOfString(T_float(), _str.buf(s));
}

811 812 813 814
fn C_floating(str s, TypeRef t) -> ValueRef {
    ret llvm.LLVMConstRealOfString(t, _str.buf(s));
}

815 816 817 818 819
fn C_nil() -> ValueRef {
    // NB: See comment above in T_void().
    ret C_integral(0, T_i1());
}

820 821
fn C_bool(bool b) -> ValueRef {
    if (b) {
822
        ret C_integral(1, T_bool());
823
    } else {
824
        ret C_integral(0, T_bool());
825 826 827
    }
}

828 829
fn C_int(int i) -> ValueRef {
    ret C_integral(i, T_int());
830 831
}

832 833 834
// 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 {
835
    auto sc = llvm.LLVMConstString(_str.buf(s), _str.byte_len(s), False);
836
    auto g = llvm.LLVMAddGlobal(cx.llmod, val_ty(sc),
837 838
                                _str.buf(cx.names.next("str")));
    llvm.LLVMSetInitializer(g, sc);
839
    llvm.LLVMSetGlobalConstant(g, True);
840 841
    llvm.LLVMSetLinkage(g, lib.llvm.LLVMPrivateLinkage
                        as llvm.Linkage);
842
    ret g;
843 844
}

845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
// 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()));
}

862 863 864 865 866 867 868 869 870 871 872
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));
}

873 874 875 876 877 878
fn C_struct(vec[ValueRef] elts) -> ValueRef {
    ret llvm.LLVMConstStruct(_vec.buf[ValueRef](elts),
                             _vec.len[ValueRef](elts),
                             False);
}

879
fn decl_fn(ModuleRef llmod, str name, uint cc, TypeRef llty) -> ValueRef {
880 881
    let ValueRef llfn =
        llvm.LLVMAddFunction(llmod, _str.buf(name), llty);
882
    llvm.LLVMSetFunctionCallConv(llfn, cc);
883 884 885
    ret llfn;
}

886 887
fn decl_cdecl_fn(ModuleRef llmod, str name, TypeRef llty) -> ValueRef {
    ret decl_fn(llmod, name, lib.llvm.LLVMCCallConv, llty);
888 889
}

890 891
fn decl_fastcall_fn(ModuleRef llmod, str name, TypeRef llty) -> ValueRef {
    ret decl_fn(llmod, name, lib.llvm.LLVMFastCallConv, llty);
892 893
}

894 895 896 897 898 899 900
fn decl_private_fastcall_fn(ModuleRef llmod,
                            str name, TypeRef llty) -> ValueRef {
    auto llfn = decl_fn(llmod, name, lib.llvm.LLVMFastCallConv, llty);
    llvm.LLVMSetLinkage(llfn, lib.llvm.LLVMPrivateLinkage as llvm.Linkage);
    ret llfn;
}

901 902
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()));
903 904
}

905
fn decl_native_glue(ModuleRef llmod, type_names tn,
906
                    bool pass_task, uint _n) -> ValueRef {
907
    // It doesn't actually matter what type we come up with here, at the
908 909
    // moment, as we cast the native function pointers to int before passing
    // them to the indirect native-invocation glue.  But eventually we'd like
910
    // to call them directly, once we have a calling convention worked out.
911
    let int n = _n as int;
912
    let str s = abi.native_glue_name(n, pass_task);
913
    let vec[TypeRef] args = vec(T_int()); // callee
914 915
    if (!pass_task) {
        args += vec(T_int()); // taskptr, will not be passed
916 917
    }
    args += _vec.init_elt[TypeRef](T_int(), n as uint);
918

919
    ret decl_fastcall_fn(llmod, s, T_fn(args, T_int()));
920 921
}

922 923 924
fn get_extern_fn(&hashmap[str, ValueRef] externs,
                 ModuleRef llmod, str name,
                 uint cc, TypeRef ty) -> ValueRef {
925 926
    if (externs.contains_key(name)) {
        ret externs.get(name);
927
    }
928
    auto f = decl_fn(llmod, name, cc, ty);
929
    externs.insert(name, f);
930 931 932
    ret f;
}

933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950
fn get_extern_const(&hashmap[str, ValueRef] externs,
                    ModuleRef llmod, str name, TypeRef ty) -> ValueRef {
    if (externs.contains_key(name)) {
        ret externs.get(name);
    }
    auto c = llvm.LLVMAddGlobal(llmod, ty, _str.buf(name));
    externs.insert(name, c);
    ret c;
}

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

951
fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args) -> result {
952
    auto cxx = cx.fcx.ccx;
953 954
    auto lltaskptr = cx.build.PtrToInt(cx.fcx.lltaskptr, T_int());
    auto args2 = vec(lltaskptr) + args;
955 956
    auto t = trans_native(cx.build, cxx.glues, lltaskptr,
                          cxx.externs, cxx.tn, cxx.llmod, name, true, args2);
957 958 959
    ret res(cx, t);
}

960 961 962 963
fn trans_native(builder b, @glue_fns glues, ValueRef lltaskptr,
                &hashmap[str, ValueRef] externs,
                type_names tn, ModuleRef llmod, str name,
                bool pass_task, vec[ValueRef] args) -> ValueRef {
964
    let int n = (_vec.len[ValueRef](args) as int);
965
    let ValueRef llnative = get_simple_extern_fn(externs, llmod, name, n);
966
    llnative = llvm.LLVMConstPointerCast(llnative, T_int());
967

968 969
    let ValueRef llglue;
    if (pass_task) {
970
        llglue = glues.native_glues_rust.(n);
971
    } else {
972
        llglue = glues.native_glues_cdecl.(n);
973
    }
974
    let vec[ValueRef] call_args = vec(llnative);
975

976 977 978
    if (!pass_task) {
        call_args += vec(lltaskptr);
    }
979

980
    for (ValueRef a in args) {
981
        call_args += vec(b.ZExtOrBitCast(a, T_int()));
982
    }
983

984
    ret b.FastCall(llglue, call_args);
985 986
}

987
fn trans_non_gc_free(@block_ctxt cx, ValueRef v) -> result {
988
    ret trans_upcall(cx, "upcall_free", vec(vp2i(cx, v),
989
                                            C_int(0)));
990 991
}

992
fn find_scope_cx(@block_ctxt cx) -> @block_ctxt {
993
    if (cx.kind == SCOPE_BLOCK) {
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
        ret cx;
    }
    alt (cx.parent) {
        case (parent_some(?b)) {
            be find_scope_cx(b);
        }
        case (parent_none) {
            fail;
        }
    }
}

1006 1007 1008 1009 1010
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);
}

1011 1012 1013 1014 1015
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);
}

1016 1017 1018 1019 1020 1021
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));
}

1022 1023 1024 1025 1026
// 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);
}

1027
fn llsize_of(TypeRef t) -> ValueRef {
1028 1029 1030
    ret llvm.LLVMConstIntCast(lib.llvm.llvm.LLVMSizeOf(t), T_int(), False);
}

1031
fn llalign_of(TypeRef t) -> ValueRef {
1032 1033 1034
    ret llvm.LLVMConstIntCast(lib.llvm.llvm.LLVMAlignOf(t), T_int(), False);
}

1035
fn size_of(@block_ctxt cx, @ty.t t) -> result {
1036
    if (!ty.type_has_dynamic_size(t)) {
1037
        ret res(cx, llsize_of(type_of(cx.fcx.ccx, t)));
1038 1039 1040 1041
    }
    ret dynamic_size_of(cx, t);
}

1042
fn align_of(@block_ctxt cx, @ty.t t) -> result {
1043
    if (!ty.type_has_dynamic_size(t)) {
1044
        ret res(cx, llalign_of(type_of(cx.fcx.ccx, t)));
1045 1046 1047 1048
    }
    ret dynamic_align_of(cx, t);
}

1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059
// 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 已提交
1060 1061
    auto tid;
    let vec[@ty.t] subtys;
1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
    alt (t.struct) {
        case (ty.ty_tag(?tid_, ?subtys_)) {
            tid = tid_;
            subtys = subtys_;
        }
        case (_) {
            log "non-tag passed to static_size_of_tag()";
            fail;
        }
    }

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

1076 1077 1078 1079
    // Compute max(variant sizes).
    auto max_size = 0u;
    auto variants = tag_variants(cx, tid);
    for (ast.variant variant in variants) {
1080
        auto tup_ty = ty.plain_tup_ty(variant_types(cx, variant));
1081

1082 1083 1084
        // Perform any type parameter substitutions.
        tup_ty = ty.substitute_ty_params(ty_params, subtys, tup_ty);

1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096
        // 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;
}

1097
fn dynamic_size_of(@block_ctxt cx, @ty.t t) -> result {
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122
    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);
    }

1123 1124 1125
    alt (t.struct) {
        case (ty.ty_param(?p)) {
            auto szptr = field_of_tydesc(cx, t, abi.tydesc_field_size);
1126
            ret res(szptr.bcx, szptr.bcx.build.Load(szptr.val));
1127 1128
        }
        case (ty.ty_tup(?elts)) {
1129 1130 1131 1132 1133
            let vec[@ty.t] tys = vec();
            for (ty.mt mt in elts) {
                tys += vec(mt.ty);
            }
            ret align_elements(cx, tys);
1134 1135
        }
        case (ty.ty_rec(?flds)) {
1136
            let vec[@ty.t] tys = vec();
1137
            for (ty.field f in flds) {
1138
                tys += vec(f.mt.ty);
1139
            }
1140
            ret align_elements(cx, tys);
1141
        }
1142 1143 1144 1145 1146 1147 1148
        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);

1149
            auto ty_params = tag_ty_params(bcx.fcx.ccx, tid);
1150 1151
            auto variants = tag_variants(bcx.fcx.ccx, tid);
            for (ast.variant variant in variants) {
1152 1153 1154 1155 1156 1157 1158 1159
                // 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);
                }

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

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

1175
fn dynamic_align_of(@block_ctxt cx, @ty.t t) -> result {
1176 1177 1178
    alt (t.struct) {
        case (ty.ty_param(?p)) {
            auto aptr = field_of_tydesc(cx, t, abi.tydesc_field_align);
1179
            ret res(aptr.bcx, aptr.bcx.build.Load(aptr.val));
1180 1181 1182
        }
        case (ty.ty_tup(?elts)) {
            auto a = C_int(1);
1183
            auto bcx = cx;
1184 1185
            for (ty.mt e in elts) {
                auto align = align_of(bcx, e.ty);
1186 1187
                bcx = align.bcx;
                a = umax(bcx, a, align.val);
1188
            }
1189
            ret res(bcx, a);
1190 1191 1192
        }
        case (ty.ty_rec(?flds)) {
            auto a = C_int(1);
1193
            auto bcx = cx;
1194
            for (ty.field f in flds) {
1195
                auto align = align_of(bcx, f.mt.ty);
1196 1197
                bcx = align.bcx;
                a = umax(bcx, a, align.val);
1198
            }
1199
            ret res(bcx, a);
1200
        }
1201 1202 1203
        case (ty.ty_tag(_, _)) {
            ret res(cx, C_int(1)); // FIXME: stub
        }
1204 1205 1206
    }
}

1207
// Replacement for the LLVM 'GEP' instruction when field-indexing into a
1208 1209 1210 1211
// 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.
1212 1213

fn GEP_tup_like(@block_ctxt cx, @ty.t t,
1214
                ValueRef base, vec[int] ixs) -> result {
1215 1216 1217 1218 1219 1220 1221 1222

    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) {
1223
            v += vec(C_int(i));
1224
        }
1225
        ret res(cx, cx.build.GEP(base, v));
1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269
    }

    // 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) {
1270 1271
            _vec.push[@ty.t](prefix, ty.get_element_type(t, i as uint));
            i += 1 ;
1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294
        }

        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);
1295
    auto prefix_ty = ty.plain_tup_ty(s.prefix);
1296 1297 1298 1299 1300
    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));
1301 1302 1303

    if (ty.type_has_dynamic_size(s.target)) {
        ret res(bcx, bumped);
1304
    }
1305 1306 1307

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

1310 1311 1312 1313
// 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.
1314 1315 1316 1317 1318 1319
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)
1320
        -> result {
1321 1322 1323
    auto ty_params = tag_ty_params(cx.fcx.ccx, tag_id);
    auto variant = tag_variant_with_id(cx.fcx.ccx, tag_id, variant_id);

1324 1325 1326 1327 1328 1329 1330
    // 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) {
1331 1332
        auto arg_ty = ty.substitute_ty_params(ty_params, ty_substs, a.ty);
        true_arg_tys += vec(arg_ty);
1333
        if (i == ix) {
1334
            elem_ty = arg_ty;
1335 1336 1337 1338
        }

        i += 1;
    }
1339 1340

    auto tup_ty = ty.plain_tup_ty(true_arg_tys);
1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366

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

1367

1368 1369
fn trans_raw_malloc(@block_ctxt cx, TypeRef llptr_ty, ValueRef llsize)
        -> result {
1370 1371
    // FIXME: need a table to collect tydesc globals.
    auto tydesc = C_int(0);
1372 1373 1374 1375 1376
    auto rslt = trans_upcall(cx, "upcall_malloc", vec(llsize, tydesc));
    rslt = res(rslt.bcx, vi2p(cx, rslt.val, llptr_ty));
    ret rslt;
}

1377 1378 1379
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.
1380 1381
    auto boxed_body = ty.plain_tup_ty(vec(plain_ty(ty.ty_int), t));
    auto box_ptr = ty.plain_box_ty(t);
1382 1383 1384
    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);
1385 1386 1387
}


1388 1389 1390 1391 1392
// 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.
1393
fn field_of_tydesc(@block_ctxt cx, @ty.t t, int field) -> result {
1394
    auto tydesc = get_tydesc(cx, t);
1395 1396
    ret res(tydesc.bcx,
            tydesc.bcx.build.GEP(tydesc.val, vec(C_int(0), C_int(field))));
1397
}
1398

1399 1400 1401 1402 1403 1404 1405 1406 1407
// 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,
1408 1409
                  mutable vec[ValueRef] vals,
                  mutable vec[ast.def_id] defs);
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421

    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) {
1422 1423
                        r.vals += vec(r.cx.fcx.lltydescs.get(pid));
                        r.defs += vec(pid);
1424 1425
                    }
                }
1426
                case (_) { }
1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441
            }
            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);
}

1442
fn get_tydesc(&@block_ctxt cx, @ty.t t) -> result {
1443
    // Is the supplied type a type param? If so, return the passed-in tydesc.
1444
    alt (ty.type_param(t)) {
1445
        case (some[ast.def_id](?id)) {
1446
            check (cx.fcx.lltydescs.contains_key(id));
1447 1448
            ret res(cx, cx.fcx.lltydescs.get(id));
        }
1449
        case (none[ast.def_id])      { /* fall through */ }
1450
    }
1451 1452

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

1455
    if (ty.count_ty_params(t) > 0u) {
1456
        auto tys = linearize_ty_params(cx, t);
1457

1458 1459 1460
        check (n_params == _vec.len[ast.def_id](tys._0));
        check (n_params == _vec.len[ValueRef](tys._1));

1461
        if (!cx.fcx.ccx.tydescs.contains_key(t)) {
1462 1463
            declare_tydesc(cx.fcx.ccx, t);
            define_tydesc(cx.fcx.ccx, t, tys._0);
1464 1465
        }

1466
        auto root = cx.fcx.ccx.tydescs.get(t).tydesc;
1467

1468 1469
        auto tydescs = cx.build.Alloca(T_array(T_ptr(T_tydesc(cx.fcx.ccx.tn)),
                                               n_params));
1470

1471
        auto i = 0;
1472 1473 1474
        auto tdp = cx.build.GEP(tydescs, vec(C_int(0), C_int(i)));
        cx.build.Store(root, tdp);
        i += 1;
1475 1476
        for (ValueRef td in tys._1) {
            auto tdp = cx.build.GEP(tydescs, vec(C_int(0), C_int(i)));
1477
            cx.build.Store(td, tdp);
1478
            i += 1;
1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490
        }

        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,
1491
                                  C_int((1u + n_params) as int),
1492
                                  vp2i(bcx, tydescs)));
1493

1494 1495
        ret res(v.bcx, vi2p(v.bcx, v.val,
                            T_ptr(T_tydesc(cx.fcx.ccx.tn))));
1496 1497 1498
    }

    // Otherwise, generate a tydesc if necessary, and return it.
1499
    if (!cx.fcx.ccx.tydescs.contains_key(t)) {
1500
        let vec[ast.def_id] defs = vec();
1501 1502
        declare_tydesc(cx.fcx.ccx, t);
        define_tydesc(cx.fcx.ccx, t, defs);
1503
    }
1504
    ret res(cx, cx.fcx.ccx.tydescs.get(t).tydesc);
1505 1506
}

1507 1508 1509 1510 1511 1512
// 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");
1513

1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526
    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);
    }

1527
    auto glue_fn_ty = T_ptr(T_glue_fn(cx.tn));
1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539

    // 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)));
1540 1541 1542
    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)))),
1543 1544
                               llsize,
                               llalign,
1545 1546
                               off(gvar, take_glue),  // take_glue_off
                               off(gvar, drop_glue),  // drop_glue_off
1547 1548 1549 1550 1551 1552 1553 1554
                               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);
1555 1556
    llvm.LLVMSetLinkage(gvar, lib.llvm.LLVMPrivateLinkage
                        as llvm.Linkage);
1557 1558 1559 1560 1561 1562 1563 1564

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

    cx.tydescs.insert(t, @info);
1565 1566
}

1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580
// 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 {
1581
    auto llfnty = T_glue_fn(cx.tn);
1582

1583 1584
    auto gcx = @rec(path=vec("glue", name) with *cx);
    auto fn_name = mangle_name_by_type(gcx, t);
1585
    fn_name = sanitize(fn_name);
1586
    auto llfn = decl_private_fastcall_fn(cx.llmod, fn_name, llfnty);
1587
    ret llfn;
1588
}
1589

1590 1591 1592
fn make_generic_glue(@crate_ctxt cx, @ty.t t, ValueRef llfn,
                     val_and_ty_fn helper,
                     vec[ast.def_id] typaram_defs) -> ValueRef {
1593
    auto fcx = new_fn_ctxt(cx, llfn);
1594 1595
    auto bcx = new_top_block_ctxt(fcx);

1596
    auto re;
1597
    if (!ty.type_is_scalar(t)) {
1598
        auto llty;
1599 1600 1601
        if (ty.type_has_dynamic_size(t)) {
            llty = T_ptr(T_i8());
        } else if (ty.type_is_structural(t)) {
1602 1603 1604 1605
            llty = T_ptr(type_of(cx, t));
        } else {
            llty = type_of(cx, t);
        }
1606

1607
        auto lltyparams = llvm.LLVMGetParam(llfn, 3u);
1608 1609 1610 1611 1612 1613 1614 1615
        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;
        }

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

1619 1620 1621 1622
        re = helper(bcx, llval, t);
    } else {
        re = res(bcx, C_nil());
    }
1623

1624
    re.bcx.build.RetVoid();
1625 1626 1627
    ret llfn;
}

1628 1629
fn make_take_glue(@block_ctxt cx, ValueRef v, @ty.t t) -> result {
    if (ty.type_is_boxed(t)) {
1630 1631
        ret incr_refcnt_of_boxed(cx, v);

1632
    } else if (ty.type_is_structural(t)) {
1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657
        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());
}

1658
fn make_drop_glue(@block_ctxt cx, ValueRef v, @ty.t t) -> result {
1659
    alt (t.struct) {
1660
        case (ty.ty_str) {
G
Graydon Hoare 已提交
1661 1662 1663 1664
            ret decr_refcnt_and_if_zero
                (cx, v, bind trans_non_gc_free(_, v),
                 "free string",
                 T_int(), C_int(0));
1665 1666
        }

1667
        case (ty.ty_vec(_)) {
G
Graydon Hoare 已提交
1668 1669 1670 1671
            fn hit_zero(@block_ctxt cx, ValueRef v,
                        @ty.t t) -> result {
                auto res = iter_sequence(cx, v, t,
                                         bind drop_ty(_,_,_));
1672 1673 1674 1675 1676 1677 1678 1679 1680
                // 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));
        }

1681
        case (ty.ty_box(?body_mt)) {
G
Graydon Hoare 已提交
1682 1683
            fn hit_zero(@block_ctxt cx, ValueRef v,
                        @ty.t body_ty) -> result {
1684 1685 1686 1687
                auto body = cx.build.GEP(v,
                                         vec(C_int(0),
                                             C_int(abi.box_rc_field_body)));

1688
                auto body_val = load_scalar_or_boxed(cx, body, body_ty);
1689 1690 1691 1692 1693
                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,
1694
                                        bind hit_zero(_, v, body_mt.ty),
1695 1696 1697 1698
                                        "free box",
                                        T_int(), C_int(0));
        }

B
Brian Anderson 已提交
1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720
        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));
        }

1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733
        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)));
1734

1735
                call_tydesc_glue_full(cx, body, cx.build.Load(tydescptr),
1736
                                      abi.tydesc_field_drop_glue_off);
1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754

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

1755
        case (ty.ty_fn(_,_,_)) {
1756 1757 1758 1759 1760 1761 1762
            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)));
1763 1764 1765 1766
                auto bindings =
                    cx.build.GEP(body,
                                 vec(C_int(0),
                                     C_int(abi.closure_elt_bindings)));
1767 1768 1769 1770 1771

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

1773
                call_tydesc_glue_full(cx, bindings, cx.build.Load(tydescptr),
1774 1775
                                      abi.tydesc_field_drop_glue_off);

1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793

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

1794
        case (_) {
1795
            if (ty.type_is_structural(t)) {
1796 1797 1798
                ret iter_structural_ty(cx, v, t,
                                       bind drop_ty(_, _, _));

1799
            } else if (ty.type_is_scalar(t) ||
1800
                       ty.type_is_native(t) ||
1801
                       ty.type_is_nil(t)) {
1802 1803 1804 1805
                ret res(cx, C_nil());
            }
        }
    }
1806
    cx.fcx.ccx.sess.bug("bad type in trans.make_drop_glue_inner: " +
1807
                        ty.ty_to_str(t));
1808 1809 1810
    fail;
}

1811 1812
fn decr_refcnt_and_if_zero(@block_ctxt cx,
                           ValueRef box_ptr,
1813
                           fn(@block_ctxt cx) -> result inner,
1814
                           str inner_name,
1815
                           TypeRef t_else, ValueRef v_else) -> result {
1816

1817
    auto load_rc_cx = new_sub_block_ctxt(cx, "load rc");
1818 1819 1820 1821
    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");

1822 1823
    auto null_test = cx.build.IsNull(box_ptr);
    cx.build.CondBr(null_test, next_cx.llbb, load_rc_cx.llbb);
1824

1825 1826 1827 1828 1829 1830 1831 1832 1833 1834

    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);
1835 1836 1837 1838

    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);
1839 1840 1841 1842
    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);
1843

1844
    auto phi = next_cx.build.Phi(t_else,
1845
                                 vec(v_else, v_else, v_else, inner_res.val),
1846
                                 vec(cx.llbb,
1847
                                     load_rc_cx.llbb,
1848
                                     rc_adj_cx.llbb,
1849 1850
                                     inner_res.bcx.llbb));

1851
    ret res(next_cx, phi);
1852 1853
}

1854 1855
// Tag information

1856 1857
fn variant_types(@crate_ctxt cx, &ast.variant v) -> vec[@ty.t] {
    let vec[@ty.t] tys = vec();
1858
    alt (ty.ann_to_type(v.ann).struct) {
1859
        case (ty.ty_fn(_, ?args, _)) {
1860
            for (ty.arg arg in args) {
1861
                tys += vec(arg.ty);
1862 1863
            }
        }
1864
        case (ty.ty_tag(_, _)) { /* nothing */ }
1865
        case (_) { fail; }
1866
    }
1867 1868 1869
    ret tys;
}

1870 1871 1872 1873 1874 1875 1876 1877 1878
// 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
}

1879 1880
// Returns the variants in a tag.
fn tag_variants(@crate_ctxt cx, ast.def_id id) -> vec[ast.variant] {
1881 1882
    check (cx.items.contains_key(id));
    alt (cx.items.get(id).node) {
1883
        case (ast.item_tag(_, ?variants, _, _)) { ret variants; }
1884 1885 1886 1887
    }
    fail;   // not reached
}

1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906
// 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;
}

1907 1908 1909 1910 1911 1912 1913 1914
// 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));
}


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

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

1919 1920 1921
type val_pair_and_ty_fn =
    fn(@block_ctxt cx, ValueRef av, ValueRef bv, @ty.t t) -> result;

1922
// Iterates through the elements of a structural type.
1923 1924
fn iter_structural_ty(@block_ctxt cx,
                      ValueRef v,
1925
                      @ty.t t,
1926 1927
                      val_and_ty_fn f)
    -> result {
1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945
    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 {
1946
    let result r = res(cx, C_nil());
1947

1948
    fn iter_boxpp(@block_ctxt cx,
1949 1950 1951 1952 1953
                  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);
1954
        auto tnil = plain_ty(ty.ty_nil);
1955
        auto tbox = ty.plain_box_ty(tnil);
1956 1957 1958

        auto inner_cx = new_sub_block_ctxt(cx, "iter box");
        auto next_cx = new_sub_block_ctxt(cx, "next");
1959
        auto null_test = cx.build.IsNull(box_a_ptr);
1960 1961
        cx.build.CondBr(null_test, next_cx.llbb, inner_cx.llbb);

1962
        auto r = f(inner_cx, box_a_ptr, box_b_ptr, tbox);
1963 1964 1965 1966
        r.bcx.build.Br(next_cx.llbb);
        ret res(next_cx, r.val);
    }

1967
    alt (t.struct) {
1968
        case (ty.ty_tup(?args)) {
1969
            let int i = 0;
1970
            for (ty.mt arg in args) {
1971 1972 1973 1974
                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;
1975
                r = f(r.bcx,
1976 1977 1978
                      load_scalar_or_boxed(r.bcx, elt_a, arg.ty),
                      load_scalar_or_boxed(r.bcx, elt_b, arg.ty),
                      arg.ty);
1979 1980 1981
                i += 1;
            }
        }
1982
        case (ty.ty_rec(?fields)) {
1983
            let int i = 0;
1984
            for (ty.field fld in fields) {
1985 1986 1987 1988
                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;
1989
                r = f(r.bcx,
1990 1991 1992
                      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);
1993 1994 1995
                i += 1;
            }
        }
1996
        case (ty.ty_tag(?tid, ?tps)) {
1997 1998
            auto variants = tag_variants(cx.fcx.ccx, tid);
            auto n_variants = _vec.len[ast.variant](variants);
1999

2000 2001 2002 2003 2004 2005 2006 2007 2008
            // 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)));
2009 2010
            auto lldiscrim_a = cx.build.Load(lldiscrim_a_ptr);

2011 2012 2013 2014
            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)));
2015
            auto lldiscrim_b = cx.build.Load(lldiscrim_b_ptr);
G
Graydon Hoare 已提交
2016

2017 2018 2019 2020 2021 2022 2023
            // 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");
2024 2025
            unr_cx.build.Unreachable();

2026
            auto llswitch = bcx.build.Switch(lldiscrim_a, unr_cx.llbb,
2027
                                             n_variants);
G
Graydon Hoare 已提交
2028

2029
            auto next_cx = new_sub_block_ctxt(bcx, "tag-iter-next");
2030

2031 2032
            auto ty_params = tag_ty_params(bcx.fcx.ccx, tid);

2033
            auto i = 0u;
2034
            for (ast.variant variant in variants) {
2035
                auto variant_cx = new_sub_block_ctxt(bcx,
2036
                                                     "tag-iter-variant-" +
2037 2038 2039
                                                     _uint.to_str(i, 10u));
                llvm.LLVMAddCase(llswitch, C_int(i as int), variant_cx.llbb);

2040 2041 2042 2043 2044
                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, _)) {
2045
                            auto j = 0;
2046 2047
                            for (ty.arg a in args) {
                                auto v = vec(C_int(0), C_int(j as int));
2048

2049 2050 2051 2052
                                auto rslt = GEP_tag(variant_cx, llunion_a_ptr,
                                    tid, variants.(i).id, tps, j);
                                auto llfldp_a = rslt.val;
                                variant_cx = rslt.bcx;
2053

2054 2055 2056 2057
                                rslt = GEP_tag(variant_cx, llunion_b_ptr, tid,
                                    variants.(i).id, tps, j);
                                auto llfldp_b = rslt.val;
                                variant_cx = rslt.bcx;
2058 2059

                                auto ty_subst = ty.substitute_ty_params(
2060
                                    ty_params, tps, a.ty);
2061

2062
                                auto llfld_a =
2063
                                    load_scalar_or_boxed(variant_cx,
2064
                                                         llfldp_a,
2065 2066
                                                         ty_subst);

2067 2068 2069 2070 2071 2072 2073
                                auto llfld_b =
                                    load_scalar_or_boxed(variant_cx,
                                                         llfldp_b,
                                                         ty_subst);

                                auto res = f(variant_cx,
                                             llfld_a, llfld_b, ty_subst);
2074
                                variant_cx = res.bcx;
2075
                                j += 1;
2076 2077
                            }
                        }
2078
                        case (_) { fail; }
2079
                    }
2080 2081 2082 2083 2084

                    variant_cx.build.Br(next_cx.llbb);
                } else {
                    // Nullary variant; nothing to do.
                    variant_cx.build.Br(next_cx.llbb);
2085 2086 2087 2088 2089 2090 2091
                }

                i += 1u;
            }

            ret res(next_cx, C_nil());
        }
2092
        case (ty.ty_fn(_,_,_)) {
2093 2094 2095 2096 2097 2098
            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,
2099 2100
                             vec(C_int(0),
                                 C_int(abi.fn_field_box)));
2101
            ret iter_boxpp(cx, box_cell_a, box_cell_b, f);
2102
        }
2103
        case (ty.ty_obj(_)) {
2104 2105 2106 2107 2108 2109
            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,
2110 2111
                             vec(C_int(0),
                                 C_int(abi.obj_field_box)));
2112
            ret iter_boxpp(cx, box_cell_a, box_cell_b, f);
2113
        }
2114
        case (_) {
2115
            cx.fcx.ccx.sess.unimpl("type in iter_structural_ty_full");
2116
        }
2117
    }
2118
    ret r;
2119 2120
}

2121 2122
// Iterates through a pointer range, until the src* hits the src_lim*.
fn iter_sequence_raw(@block_ctxt cx,
2123
                     ValueRef dst,     // elt*
2124 2125 2126
                     ValueRef src,     // elt*
                     ValueRef src_lim, // elt*
                     ValueRef elt_sz,
2127
                     val_pair_fn f) -> result {
2128 2129 2130

    auto bcx = cx;

2131
    let ValueRef dst_int = vp2i(bcx, dst);
2132 2133 2134 2135 2136 2137 2138 2139 2140
    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);

2141 2142
    let ValueRef dst_curr = cond_cx.build.Phi(T_int(),
                                              vec(dst_int), vec(bcx.llbb));
2143 2144 2145
    let ValueRef src_curr = cond_cx.build.Phi(T_int(),
                                              vec(src_int), vec(bcx.llbb));

2146
    auto end_test = cond_cx.build.ICmp(lib.llvm.LLVMIntULT,
2147 2148 2149 2150
                                       src_curr, src_lim_int);

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

2151
    auto dst_curr_ptr = vi2p(body_cx, dst_curr, T_ptr(T_i8()));
2152
    auto src_curr_ptr = vi2p(body_cx, src_curr, T_ptr(T_i8()));
2153

2154
    auto body_res = f(body_cx, dst_curr_ptr, src_curr_ptr);
2155 2156
    body_cx = body_res.bcx;

2157
    auto dst_next = body_cx.build.Add(dst_curr, elt_sz);
2158
    auto src_next = body_cx.build.Add(src_curr, elt_sz);
2159 2160
    body_cx.build.Br(cond_cx.llbb);

2161 2162
    cond_cx.build.AddIncomingToPhi(dst_curr, vec(dst_next),
                                   vec(body_cx.llbb));
2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175
    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,
2176
                  @ty.t elt_ty,
2177
                  @block_ctxt cx,
2178 2179
                  ValueRef dst,
                  ValueRef src) -> result {
2180 2181 2182 2183 2184 2185 2186 2187 2188
        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);
2189
        ret f(cx, load_scalar_or_boxed(cx, p, elt_ty), elt_ty);
2190 2191
    }

2192
    auto elt_sz = size_of(cx, elt_ty);
2193 2194
    be iter_sequence_raw(elt_sz.bcx, src, src, src_lim, elt_sz.val,
                         bind adaptor_fn(f, elt_ty, _, _, _));
2195 2196 2197
}


2198 2199 2200
// Iterates through the elements of a vec or str.
fn iter_sequence(@block_ctxt cx,
                 ValueRef v,
2201
                 @ty.t t,
2202 2203 2204 2205
                 val_and_ty_fn f) -> result {

    fn iter_sequence_body(@block_ctxt cx,
                          ValueRef v,
2206
                          @ty.t elt_ty,
2207 2208 2209 2210 2211 2212 2213
                          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)));
2214

2215 2216 2217 2218 2219 2220 2221
        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);
        }

2222
        auto bcx = cx;
2223

2224
        auto len = bcx.build.Load(lenptr);
2225
        if (trailing_null) {
2226 2227
            auto unit_sz = size_of(bcx, elt_ty);
            bcx = unit_sz.bcx;
2228
            len = bcx.build.Sub(len, unit_sz.val);
2229 2230
        }

2231 2232
        auto p1 = vi2p(bcx, bcx.build.Add(vp2i(bcx, p0), len),
                       T_ptr(llunit_ty));
2233

2234
        ret iter_sequence_inner(cx, p0, p1, elt_ty, f);
2235 2236
    }

2237
    alt (t.struct) {
2238 2239
        case (ty.ty_vec(?elt)) {
            ret iter_sequence_body(cx, v, elt.ty, f, false);
2240
        }
2241
        case (ty.ty_str) {
2242
            auto et = plain_ty(ty.ty_machine(common.ty_u8));
2243
            ret iter_sequence_body(cx, v, et, f, true);
2244
        }
2245
        case (_) { fail; }
2246
    }
2247 2248 2249 2250
    cx.fcx.ccx.sess.bug("bad type in trans.iter_sequence");
    fail;
}

2251 2252 2253 2254 2255 2256 2257 2258 2259
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);
2260 2261 2262 2263 2264

    // 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.
2265 2266 2267
    llfn = vi2p(cx, cx.build.Add(vp2i(cx, llfn),
                                 vp2i(cx, tydesc)),
                val_ty(llfn));
2268

2269 2270 2271 2272 2273
    cx.build.FastCall(llfn, vec(C_null(T_ptr(T_nil())),
                                cx.fcx.lltaskptr,
                                C_null(T_ptr(T_nil())),
                                lltydescs,
                                llrawptr));
2274 2275 2276
}

fn call_tydesc_glue(@block_ctxt cx, ValueRef v, @ty.t t, int field) {
2277 2278
    auto td = get_tydesc(cx, t);
    call_tydesc_glue_full(td.bcx, v, td.val, field);
2279 2280
}

2281 2282
fn incr_all_refcnts(@block_ctxt cx,
                    ValueRef v,
2283 2284
                    @ty.t t) -> result {
    if (!ty.type_is_scalar(t)) {
2285
        call_tydesc_glue(cx, v, t, abi.tydesc_field_take_glue_off);
2286
    }
2287
    ret res(cx, C_nil());
2288 2289
}

2290 2291
fn drop_slot(@block_ctxt cx,
             ValueRef slot,
2292
             @ty.t t) -> result {
2293
    auto llptr = load_scalar_or_boxed(cx, slot, t);
2294 2295 2296 2297 2298 2299
    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;
2300 2301
}

2302 2303
fn drop_ty(@block_ctxt cx,
           ValueRef v,
2304
           @ty.t t) -> result {
2305

2306
    if (!ty.type_is_scalar(t)) {
2307
        call_tydesc_glue(cx, v, t, abi.tydesc_field_drop_glue_off);
2308
    }
2309
    ret res(cx, C_nil());
2310 2311
}

2312 2313 2314 2315
fn call_memcpy(@block_ctxt cx,
               ValueRef dst,
               ValueRef src,
               ValueRef n_bytes) -> result {
2316 2317
    auto src_ptr = cx.build.PointerCast(src, T_ptr(T_i8()));
    auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
2318 2319 2320
    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)));
2321 2322
}

2323 2324 2325 2326 2327 2328 2329 2330 2331
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)));
}

2332 2333 2334 2335 2336 2337
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);
2338 2339
        auto llsz = llszptr.bcx.build.Load(llszptr.val);
        ret call_memcpy(llszptr.bcx, dst, src, llsz);
2340 2341 2342 2343 2344 2345

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

2346 2347 2348 2349 2350
tag copy_action {
    INIT;
    DROP_EXISTING;
}

2351
fn copy_ty(@block_ctxt cx,
2352
           copy_action action,
2353 2354
           ValueRef dst,
           ValueRef src,
2355
           @ty.t t) -> result {
2356
    if (ty.type_is_scalar(t) || ty.type_is_native(t)) {
2357 2358
        ret res(cx, cx.build.Store(src, dst));

2359
    } else if (ty.type_is_nil(t)) {
2360 2361
        ret res(cx, C_nil());

2362
    } else if (ty.type_is_boxed(t)) {
2363
        auto r = incr_all_refcnts(cx, src, t);
2364
        if (action == DROP_EXISTING) {
2365
            r = drop_ty(r.bcx, r.bcx.build.Load(dst), t);
2366 2367 2368
        }
        ret res(r.bcx, r.bcx.build.Store(src, dst));

2369 2370
    } else if (ty.type_is_structural(t) ||
               ty.type_has_dynamic_size(t)) {
2371
        auto r = incr_all_refcnts(cx, src, t);
2372
        if (action == DROP_EXISTING) {
2373 2374
            r = drop_ty(r.bcx, dst, t);
        }
2375
        ret memcpy_ty(r.bcx, dst, src, t);
2376 2377 2378
    }

    cx.fcx.ccx.sess.bug("unexpected type in trans.copy_ty: " +
2379
                        ty.ty_to_str(t));
2380 2381 2382
    fail;
}

2383
fn trans_lit(@crate_ctxt cx, &ast.lit lit, &ast.ann ann) -> ValueRef {
2384
    alt (lit.node) {
2385
        case (ast.lit_int(?i)) {
2386
            ret C_int(i);
2387 2388
        }
        case (ast.lit_uint(?u)) {
2389
            ret C_int(u as int);
2390
        }
2391 2392 2393 2394 2395 2396
        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 已提交
2397 2398 2399 2400 2401 2402 2403 2404 2405
                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(); }
2406
            }
2407
            ret C_integral(i, t);
2408
        }
2409 2410 2411
        case(ast.lit_float(?fs)) {
            ret C_float(fs);
        }
2412 2413 2414 2415 2416 2417 2418 2419
        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);
        }
2420
        case (ast.lit_char(?c)) {
2421
            ret C_integral(c as int, T_char());
2422 2423
        }
        case (ast.lit_bool(?b)) {
2424
            ret C_bool(b);
2425 2426
        }
        case (ast.lit_nil) {
2427
            ret C_nil();
2428 2429
        }
        case (ast.lit_str(?s)) {
2430
            ret C_str(cx, s);
2431 2432 2433 2434
        }
    }
}

2435
fn target_type(@crate_ctxt cx, @ty.t t) -> @ty.t {
2436
    alt (t.struct) {
2437 2438
        case (ty.ty_int) {
            auto tm = ty.ty_machine(cx.sess.get_targ_cfg().int_type);
2439 2440
            ret @rec(struct=tm with *t);
        }
2441 2442
        case (ty.ty_uint) {
            auto tm = ty.ty_machine(cx.sess.get_targ_cfg().uint_type);
2443 2444
            ret @rec(struct=tm with *t);
        }
2445
        case (_) { /* fall through */ }
2446 2447 2448 2449
    }
    ret t;
}

2450
fn node_ann_type(@crate_ctxt cx, &ast.ann a) -> @ty.t {
2451 2452
    alt (a) {
        case (ast.ann_none) {
2453
            cx.sess.bug("missing type annotation");
2454
        }
2455
        case (ast.ann_type(?t, _)) {
2456
            ret target_type(cx, t);
2457 2458 2459 2460
        }
    }
}

2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478
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; }
            }
        }
    }
}

2479 2480 2481 2482
fn node_type(@crate_ctxt cx, &ast.ann a) -> TypeRef {
    ret type_of(cx, node_ann_type(cx, a));
}

2483 2484
fn trans_unary(@block_ctxt cx, ast.unop op,
               @ast.expr e, &ast.ann a) -> result {
2485 2486

    auto sub = trans_expr(cx, e);
2487
    auto e_ty = ty.expr_ty(e);
2488

2489 2490
    alt (op) {
        case (ast.bitnot) {
2491
            sub = autoderef(sub.bcx, sub.val, ty.expr_ty(e));
2492
            ret res(sub.bcx, sub.bcx.build.Not(sub.val));
2493 2494
        }
        case (ast.not) {
2495
            sub = autoderef(sub.bcx, sub.val, ty.expr_ty(e));
2496
            ret res(sub.bcx, sub.bcx.build.Not(sub.val));
2497 2498
        }
        case (ast.neg) {
2499
            sub = autoderef(sub.bcx, sub.val, ty.expr_ty(e));
2500 2501 2502 2503 2504 2505
            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));
            }
2506
        }
2507
        case (ast.box) {
2508
            auto e_ty = ty.expr_ty(e);
2509
            auto e_val = sub.val;
2510 2511 2512
            auto box_ty = node_ann_type(sub.bcx.fcx.ccx, a);
            sub = trans_malloc_boxed(sub.bcx, e_ty);
            find_scope_cx(cx).cleanups +=
2513
                vec(clean(bind drop_ty(_, sub.val, box_ty)));
2514

2515 2516
            auto box = sub.val;
            auto rc = sub.bcx.build.GEP(box,
2517 2518
                                        vec(C_int(0),
                                            C_int(abi.box_rc_field_refcnt)));
2519 2520 2521 2522
            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);
2523 2524 2525 2526 2527 2528 2529 2530 2531

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

2532
            sub = copy_ty(sub.bcx, INIT, body, e_val, e_ty);
2533
            ret res(sub.bcx, box);
2534
        }
2535
        case (ast.deref) {
2536 2537 2538
            auto val = sub.bcx.build.GEP(sub.val,
                                         vec(C_int(0),
                                             C_int(abi.box_rc_field_body)));
2539
            auto e_ty = node_ann_type(sub.bcx.fcx.ccx, a);
2540 2541
            if (ty.type_is_scalar(e_ty) ||
                ty.type_is_nil(e_ty)) {
2542
                val = sub.bcx.build.Load(val);
2543
            }
2544
            ret res(sub.bcx, val);
2545
        }
2546 2547 2548 2549
    }
    fail;
}

2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563
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);
2564 2565 2566 2567

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

2568 2569 2570
    } else if (ty.type_is_structural(t)
               || ty.type_is_sequence(t)) {

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

2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598
        /*
         * 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.
         */

2599 2600
        auto flag = scx.build.Alloca(T_i1());

2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624
        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);
                }

2625 2626
            }
        }
2627

2628
        fn inner(@block_ctxt last_cx,
2629
                 bool load_inner,
2630 2631 2632
                 ValueRef flag,
                 ast.binop op,
                 @block_ctxt cx,
2633 2634
                 ValueRef av0,
                 ValueRef bv0,
2635
                 @ty.t t) -> result {
2636

2637 2638 2639
            auto cnt_cx = new_sub_block_ctxt(cx, "continue comparison");
            auto stop_cx = new_sub_block_ctxt(cx, "stop comparison");

2640 2641 2642 2643 2644 2645 2646
            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);
            }

2647 2648 2649
            // 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);
2650

2651 2652 2653 2654
            // 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);
2655 2656 2657
            ret res(cnt_cx, C_nil());
        }

2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675
        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));
        }
2676

2677 2678
        r.bcx.build.Br(next.llbb);
        auto v = next.build.Load(flag);
2679 2680
        ret res(next, v);

2681

2682
    } else {
2683
        // FIXME: compare obj, fn by pointer?
2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699
        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 {
2700

2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717
    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 {
2718 2719 2720 2721 2722
    auto cmp = lib.llvm.LLVMIntEQ;
    alt (op) {
        case (ast.eq) { cmp = lib.llvm.LLVMIntEQ; }
        case (ast.ne) { cmp = lib.llvm.LLVMIntNE; }

2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750
        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;
            }
        }
2751 2752 2753 2754
    }
    ret cx.build.ICmp(cmp, lhs, rhs);
}

2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773
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;

2774 2775 2776 2777 2778 2779 2780 2781
    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)));
2782 2783
}

2784 2785
fn trans_vec_add(@block_ctxt cx, @ty.t t,
                 ValueRef lhs, ValueRef rhs) -> result {
2786
    auto r = alloc_ty(cx, t);
2787 2788
    auto tmp = r.val;
    r = copy_ty(r.bcx, INIT, tmp, lhs, t);
2789
    auto bcx = trans_vec_append(r.bcx, t, tmp, rhs).bcx;
2790
    tmp = load_scalar_or_boxed(bcx, tmp, t);
2791 2792
    find_scope_cx(cx).cleanups +=
        vec(clean(bind drop_ty(_, tmp, t)));
2793
    ret res(bcx, tmp);
2794 2795 2796
}


2797
fn trans_eager_binop(@block_ctxt cx, ast.binop op, @ty.t intype,
2798
                     ValueRef lhs, ValueRef rhs) -> result {
2799

2800
    auto is_float = false;
2801
    alt (intype.struct) {
2802 2803 2804 2805 2806 2807 2808
        case (ty.ty_float) {
            is_float = true;
        }
        case (_) {
            is_float = false;
        }
    }
2809

2810
    alt (op) {
2811 2812
        case (ast.add) {
            if (ty.type_is_sequence(intype)) {
2813
                ret trans_vec_add(cx, intype, lhs, rhs);
2814
            }
2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830
            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));
            }
        }

2831
        case (ast.mul) {
2832 2833 2834 2835 2836 2837
            if (is_float) {
                ret res(cx, cx.build.FMul(lhs, rhs));
            }
            else {
                ret res(cx, cx.build.Mul(lhs, rhs));
            }
2838
        }
2839

2840
        case (ast.div) {
2841 2842 2843
            if (is_float) {
                ret res(cx, cx.build.FDiv(lhs, rhs));
            }
2844
            if (ty.type_is_signed(intype)) {
2845
                ret res(cx, cx.build.SDiv(lhs, rhs));
2846
            } else {
2847
                ret res(cx, cx.build.UDiv(lhs, rhs));
2848 2849 2850
            }
        }
        case (ast.rem) {
2851 2852 2853
            if (is_float) {
                ret res(cx, cx.build.FRem(lhs, rhs));
            }
2854
            if (ty.type_is_signed(intype)) {
2855
                ret res(cx, cx.build.SRem(lhs, rhs));
2856
            } else {
2857
                ret res(cx, cx.build.URem(lhs, rhs));
2858 2859
            }
        }
2860

2861 2862 2863 2864 2865 2866
        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)); }
2867
        case (_) {
2868
            ret trans_compare(cx, op, intype, lhs, rhs);
2869 2870 2871 2872 2873
        }
    }
    fail;
}

2874 2875 2876 2877 2878 2879
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) {
2880
            case (ty.ty_box(?mt)) {
2881 2882 2883
                auto body = cx.build.GEP(v1,
                                         vec(C_int(0),
                                             C_int(abi.box_rc_field_body)));
2884 2885
                t1 = mt.ty;
                v1 = load_scalar_or_boxed(cx, body, t1);
2886 2887 2888 2889 2890 2891 2892 2893
            }
            case (_) {
                ret res(cx, v1);
            }
        }
    }
}

2894 2895 2896 2897 2898
fn autoderefed_ty(@ty.t t) -> @ty.t {
    let @ty.t t1 = t;

    while (true) {
        alt (t1.struct) {
2899 2900
            case (ty.ty_box(?mt)) {
                t1 = mt.ty;
2901 2902 2903 2904 2905 2906 2907 2908
            }
            case (_) {
                ret t1;
            }
        }
    }
}

2909 2910
fn trans_binary(@block_ctxt cx, ast.binop op,
                @ast.expr a, @ast.expr b) -> result {
2911

2912 2913 2914 2915 2916 2917
    // First couple cases are lazy:

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

2920
            auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
2921
            auto rhs_res = trans_expr(rhs_cx, b);
2922
            rhs_res = autoderef(rhs_res.bcx, rhs_res.val, ty.expr_ty(b));
2923

2924
            auto lhs_false_cx = new_scope_block_ctxt(cx, "lhs false");
2925
            auto lhs_false_res = res(lhs_false_cx, C_bool(false));
2926 2927 2928

            lhs_res.bcx.build.CondBr(lhs_res.val,
                                     rhs_cx.llbb,
2929 2930 2931 2932
                                     lhs_false_cx.llbb);

            ret join_results(cx, T_bool(),
                             vec(lhs_false_res, rhs_res));
2933 2934 2935 2936 2937
        }

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

2940
            auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
2941
            auto rhs_res = trans_expr(rhs_cx, b);
2942
            rhs_res = autoderef(rhs_res.bcx, rhs_res.val, ty.expr_ty(b));
2943

2944
            auto lhs_true_cx = new_scope_block_ctxt(cx, "lhs true");
2945
            auto lhs_true_res = res(lhs_true_cx, C_bool(true));
2946 2947

            lhs_res.bcx.build.CondBr(lhs_res.val,
2948
                                     lhs_true_cx.llbb,
2949
                                     rhs_cx.llbb);
2950 2951 2952

            ret join_results(cx, T_bool(),
                             vec(lhs_true_res, rhs_res));
2953
        }
2954 2955

        case (_) {
2956 2957
            // Remaining cases are eager:
            auto lhs = trans_expr(cx, a);
2958 2959
            auto lhty = ty.expr_ty(a);
            lhs = autoderef(lhs.bcx, lhs.val, lhty);
2960
            auto rhs = trans_expr(lhs.bcx, b);
2961 2962
            auto rhty = ty.expr_ty(b);
            rhs = autoderef(rhs.bcx, rhs.val, rhty);
2963 2964 2965
            ret trans_eager_binop(rhs.bcx, op,
                                  autoderefed_ty(lhty),
                                  lhs.val, rhs.val);
2966
        }
2967 2968 2969 2970
    }
    fail;
}

2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981
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)) {
2982 2983 2984
            live += vec(r);
            vals += vec(r.val);
            bbs += vec(r.bcx.llbb);
2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001
        }
    }

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

        case (_) { /* fall through */ }
3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014
    }

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

3015
fn trans_if(@block_ctxt cx, @ast.expr cond,
3016
            &ast.block thn, &option.t[@ast.expr] els) -> result {
3017 3018 3019

    auto cond_res = trans_expr(cx, cond);

3020
    auto then_cx = new_scope_block_ctxt(cx, "then");
3021 3022
    auto then_res = trans_block(then_cx, thn);

3023
    auto else_cx = new_scope_block_ctxt(cx, "else");
3024
    auto else_res = res(else_cx, C_nil());
3025 3026

    alt (els) {
3027
        case (some[@ast.expr](?elexpr)) {
3028
            else_res = trans_expr(else_cx, elexpr);
3029
        }
3030
        case (_) { /* fall through */ }
3031 3032
    }

3033
    cond_res.bcx.build.CondBr(cond_res.val,
3034 3035
                              then_cx.llbb,
                              else_cx.llbb);
3036 3037 3038 3039

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

G
Graydon Hoare 已提交
3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055
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);
3056
        auto bcx = copy_ty(local_res.bcx, INIT, local_res.val, curr, t).bcx;
3057 3058
        scope_cx.cleanups +=
            vec(clean(bind drop_slot(_, local_res.val, t)));
3059
        bcx = trans_block(bcx, body).bcx;
G
Graydon Hoare 已提交
3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077
        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));
}

3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133

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

3134 3135 3136 3137
fn trans_for_each(@block_ctxt cx,
                  @ast.decl decl,
                  @ast.expr seq,
                  &ast.block body) -> result {
3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166

    /*
     * 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);
3167
    auto decl_id;
3168 3169 3170
    alt (decl.node) {
        case (ast.decl_local(?local)) {
            decl_ty = node_ann_type(cx.fcx.ccx, local.ann);
3171
            decl_id = local.id;
3172 3173 3174
        }
    }

3175
    auto upvars = collect_upvars(cx, body, decl_id);
3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186
    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]) {
3187 3188 3189 3190 3191 3192
                    alt (cx.fcx.llupvars.find(did)) {
                        case (none[ValueRef]) {
                            llbinding = cx.fcx.llargs.get(did);
                        }
                        case (some[ValueRef](?llval)) { llbinding = llval; }
                    }
3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211
                }
                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()));
3212 3213
    }

3214 3215 3216 3217 3218 3219 3220 3221 3222 3223
    // 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);
3224 3225 3226

    // Step 2: Declare foreach body function.

3227
    let str s = mangle_name_by_seq(cx.fcx.ccx, "foreach");
3228 3229 3230 3231 3232 3233 3234

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

3235 3236 3237
    auto iter_body_llty = type_of_fn_full(cx.fcx.ccx, ast.proto_fn,
                                          none[TypeRef],
                                          vec(rec(mode=ast.val, ty=decl_ty)),
3238
                                          plain_ty(ty.ty_nil), 0u);
3239

3240 3241
    let ValueRef lliterbody = decl_private_fastcall_fn(cx.fcx.ccx.llmod,
                                                       s, iter_body_llty);
3242 3243 3244 3245

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

3246
    auto fcx = new_fn_ctxt(cx.fcx.ccx, lliterbody);
3247 3248
    auto bcx = new_top_block_ctxt(fcx);

3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272
    // 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);

3273 3274 3275 3276
    auto res = trans_block(bcx, body);
    res.bcx.build.RetVoid();


3277
    // Step 3: Call iter passing [lliterbody, llenv], plus other args.
3278 3279

    alt (seq.node) {
3280

3281
        case (ast.expr_call(?f, ?args, ?ann)) {
3282

3283 3284 3285 3286 3287 3288 3289
            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);

3290 3291 3292 3293 3294 3295
            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);

3296 3297
            // log "lliterbody: " + val_str(cx.fcx.ccx.tn, lliterbody);
            ret trans_call(cx, f,
3298
                           some[ValueRef](cx.build.Load(pair)),
3299 3300
                           args,
                           ann);
3301 3302
        }
    }
3303 3304 3305 3306
    fail;
}


3307 3308
fn trans_while(@block_ctxt cx, @ast.expr cond,
               &ast.block body) -> result {
3309

3310 3311
    auto cond_cx = new_scope_block_ctxt(cx, "while cond");
    auto body_cx = new_scope_block_ctxt(cx, "while loop body");
3312
    auto next_cx = new_sub_block_ctxt(cx, "next");
3313 3314

    auto body_res = trans_block(body_cx, body);
3315 3316 3317
    auto cond_res = trans_expr(cond_cx, cond);

    body_res.bcx.build.Br(cond_cx.llbb);
3318 3319 3320

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

    cx.build.Br(cond_cx.llbb);
3323 3324 3325
    ret res(next_cx, C_nil());
}

3326 3327
fn trans_do_while(@block_ctxt cx, &ast.block body,
                  @ast.expr cond) -> result {
3328

3329
    auto body_cx = new_scope_block_ctxt(cx, "do-while loop body");
3330
    auto next_cx = new_sub_block_ctxt(cx, "next");
3331 3332

    auto body_res = trans_block(body_cx, body);
3333 3334 3335 3336 3337 3338
    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);
3339 3340 3341
    ret res(next_cx, body_res.val);
}

P
Patrick Walton 已提交
3342 3343
// Pattern matching translation

3344 3345
fn trans_pat_match(@block_ctxt cx, @ast.pat pat, ValueRef llval,
                   @block_ctxt next_cx) -> result {
P
Patrick Walton 已提交
3346 3347 3348
    alt (pat.node) {
        case (ast.pat_wild(_)) { ret res(cx, llval); }
        case (ast.pat_bind(_, _, _)) { ret res(cx, llval); }
3349 3350 3351

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

3355 3356
            auto matched_cx = new_sub_block_ctxt(lleq.bcx, "matched_cx");
            lleq.bcx.build.CondBr(lleq.val, matched_cx.llbb, next_cx.llbb);
3357 3358 3359
            ret res(matched_cx, llval);
        }

P
Patrick Walton 已提交
3360
        case (ast.pat_tag(?id, ?subpats, ?vdef_opt, ?ann)) {
3361 3362 3363 3364 3365
            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)));
3366
            auto lldiscrim = cx.build.Load(lldiscrimptr);
3367

P
Patrick Walton 已提交
3368 3369 3370
            auto vdef = option.get[ast.variant_def](vdef_opt);
            auto variant_id = vdef._1;
            auto variant_tag = 0;
3371 3372

            auto variants = tag_variants(cx.fcx.ccx, vdef._0);
P
Patrick Walton 已提交
3373
            auto i = 0;
3374 3375
            for (ast.variant v in variants) {
                auto this_variant_id = v.id;
P
Patrick Walton 已提交
3376
                if (variant_id._0 == this_variant_id._0 &&
G
Graydon Hoare 已提交
3377
                    variant_id._1 == this_variant_id._1) {
P
Patrick Walton 已提交
3378 3379 3380 3381 3382 3383 3384
                    variant_tag = i;
                }
                i += 1;
            }

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

3385
            auto lleq = cx.build.ICmp(lib.llvm.LLVMIntEQ, lldiscrim,
P
Patrick Walton 已提交
3386 3387 3388
                                      C_int(variant_tag));
            cx.build.CondBr(lleq, matched_cx.llbb, next_cx.llbb);

3389 3390
            auto ty_params = node_ann_ty_params(ann);

P
Patrick Walton 已提交
3391
            if (_vec.len[@ast.pat](subpats) > 0u) {
3392 3393
                auto llblobptr = matched_cx.build.GEP(lltagptr,
                    vec(C_int(0), C_int(1)));
P
Patrick Walton 已提交
3394 3395
                auto i = 0;
                for (@ast.pat subpat in subpats) {
3396 3397
                    auto rslt = GEP_tag(matched_cx, llblobptr, vdef._0,
                                        vdef._1, ty_params, i);
3398 3399 3400
                    auto llsubvalptr = rslt.val;
                    matched_cx = rslt.bcx;

3401
                    auto llsubval = load_scalar_or_boxed(matched_cx,
G
Graydon Hoare 已提交
3402 3403
                                                         llsubvalptr,
                                                         pat_ty(subpat));
P
Patrick Walton 已提交
3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416
                    auto subpat_res = trans_pat_match(matched_cx, subpat,
                                                      llsubval, next_cx);
                    matched_cx = subpat_res.bcx;
                }
            }

            ret res(matched_cx, llval);
        }
    }

    fail;
}

3417 3418
fn trans_pat_binding(@block_ctxt cx, @ast.pat pat, ValueRef llval)
    -> result {
P
Patrick Walton 已提交
3419 3420
    alt (pat.node) {
        case (ast.pat_wild(_)) { ret res(cx, llval); }
3421
        case (ast.pat_lit(_, _)) { ret res(cx, llval); }
P
Patrick Walton 已提交
3422 3423 3424
        case (ast.pat_bind(?id, ?def_id, ?ann)) {
            auto ty = node_ann_type(cx.fcx.ccx, ann);

3425 3426 3427 3428
            auto rslt = alloc_ty(cx, ty);
            auto dst = rslt.val;
            auto bcx = rslt.bcx;

P
Patrick Walton 已提交
3429
            llvm.LLVMSetValueName(dst, _str.buf(id));
3430
            bcx.fcx.lllocals.insert(def_id, dst);
3431 3432
            bcx.cleanups +=
                vec(clean(bind drop_slot(_, dst, ty)));
P
Patrick Walton 已提交
3433

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

3439 3440 3441 3442 3443 3444 3445
            // 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 已提交
3446

3447 3448
            auto ty_param_substs = node_ann_ty_params(ann);

P
Patrick Walton 已提交
3449 3450 3451
            auto this_cx = cx;
            auto i = 0;
            for (@ast.pat subpat in subpats) {
3452 3453
                auto rslt = GEP_tag(this_cx, llblobptr, vdef._0, vdef._1,
                                    ty_param_substs, i);
3454 3455 3456
                this_cx = rslt.bcx;
                auto llsubvalptr = rslt.val;

3457
                auto llsubval = load_scalar_or_boxed(this_cx, llsubvalptr,
G
Graydon Hoare 已提交
3458
                                                     pat_ty(subpat));
P
Patrick Walton 已提交
3459 3460 3461
                auto subpat_res = trans_pat_binding(this_cx, subpat,
                                                    llsubval);
                this_cx = subpat_res.bcx;
3462
                i += 1;
P
Patrick Walton 已提交
3463 3464 3465 3466 3467 3468 3469
            }

            ret res(this_cx, llval);
        }
    }
}

3470 3471
fn trans_alt(@block_ctxt cx, @ast.expr expr, vec[ast.arm] arms)
    -> result {
P
Patrick Walton 已提交
3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504
    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());
}

3505
type generic_info = rec(@ty.t item_type,
3506 3507
                        vec[ValueRef] tydescs);

3508 3509
type lval_result = rec(result res,
                       bool is_mem,
3510
                       option.t[generic_info] generic,
3511 3512 3513 3514 3515
                       option.t[ValueRef] llobj);

fn lval_mem(@block_ctxt cx, ValueRef val) -> lval_result {
    ret rec(res=res(cx, val),
            is_mem=true,
3516
            generic=none[generic_info],
3517 3518 3519 3520 3521 3522
            llobj=none[ValueRef]);
}

fn lval_val(@block_ctxt cx, ValueRef val) -> lval_result {
    ret rec(res=res(cx, val),
            is_mem=false,
3523
            generic=none[generic_info],
3524 3525
            llobj=none[ValueRef]);
}
3526

3527 3528 3529 3530 3531 3532 3533 3534
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));
3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547

    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);
        }
    }
3548 3549 3550 3551 3552 3553 3554

    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;
3555
            _vec.push[ValueRef](tydescs, td.val);
3556 3557 3558 3559 3560 3561 3562 3563 3564 3565
        }
        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;
}

3566
fn trans_path(@block_ctxt cx, &ast.path p, &option.t[ast.def] dopt,
G
Graydon Hoare 已提交
3567
              &ast.ann ann) -> lval_result {
3568 3569 3570 3571
    alt (dopt) {
        case (some[ast.def](?def)) {
            alt (def) {
                case (ast.def_arg(?did)) {
3572 3573 3574 3575 3576 3577 3578 3579 3580
                    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);
                        }
                    }
3581 3582
                }
                case (ast.def_local(?did)) {
3583 3584 3585 3586 3587 3588 3589 3590 3591
                    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 已提交
3592
                }
P
Patrick Walton 已提交
3593 3594
                case (ast.def_binding(?did)) {
                    check (cx.fcx.lllocals.contains_key(did));
3595
                    ret lval_mem(cx, cx.fcx.lllocals.get(did));
P
Patrick Walton 已提交
3596
                }
3597 3598 3599 3600
                case (ast.def_obj_field(?did)) {
                    check (cx.fcx.llobjfields.contains_key(did));
                    ret lval_mem(cx, cx.fcx.llobjfields.get(did));
                }
3601
                case (ast.def_fn(?did)) {
3602
                    check (cx.fcx.ccx.items.contains_key(did));
3603
                    auto fn_item = cx.fcx.ccx.items.get(did);
3604
                    ret lval_generic_fn(cx, ty.item_ty(fn_item), did, ann);
3605
                }
3606
                case (ast.def_obj(?did)) {
3607 3608 3609
                    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);
3610
                }
3611
                case (ast.def_variant(?tid, ?vid)) {
3612
                    if (cx.fcx.ccx.fn_pairs.contains_key(vid)) {
3613 3614 3615
                        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;
3616
                        auto fty = plain_ty(ty.ty_nil);
3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627
                        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);
3628
                    } else {
3629 3630
                        // Nullary variant.
                        auto tag_ty = node_ann_type(cx.fcx.ccx, ann);
3631
                        auto lldiscrim_gv = cx.fcx.ccx.discrims.get(vid);
3632 3633 3634 3635
                        auto lldiscrim = cx.build.Load(lldiscrim_gv);

                        auto alloc_result = alloc_ty(cx, tag_ty);
                        auto lltagblob = alloc_result.val;
3636 3637 3638 3639 3640 3641 3642

                        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);
                        }
3643
                        auto lltagptr = alloc_result.bcx.build.PointerCast(
3644
                            lltagblob, T_ptr(lltagty));
3645 3646 3647 3648 3649 3650

                        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);
3651
                    }
3652
                }
3653 3654 3655 3656
                case (ast.def_const(?did)) {
                    check (cx.fcx.ccx.consts.contains_key(did));
                    ret lval_mem(cx, cx.fcx.ccx.consts.get(did));
                }
3657 3658 3659 3660 3661 3662
                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);
                }
3663 3664
                case (_) {
                    cx.fcx.ccx.sess.unimpl("def variant in trans");
G
Graydon Hoare 已提交
3665 3666 3667
                }
            }
        }
3668
        case (none[ast.def]) {
3669
            cx.fcx.ccx.sess.err("unresolved expr_path in trans");
3670 3671 3672 3673 3674
        }
    }
    fail;
}

3675 3676
fn trans_field(@block_ctxt cx, &ast.span sp, @ast.expr base,
               &ast.ident field, &ast.ann ann) -> lval_result {
3677
    auto r = trans_expr(cx, base);
3678
    auto t = ty.expr_ty(base);
3679 3680
    r = autoderef(r.bcx, r.val, t);
    t = autoderefed_ty(t);
3681
    alt (t.struct) {
3682
        case (ty.ty_tup(_)) {
3683
            let uint ix = ty.field_num(cx.fcx.ccx.sess, sp, field);
3684
            auto v = GEP_tup_like(r.bcx, t, r.val, vec(0, ix as int));
3685
            ret lval_mem(v.bcx, v.val);
3686
        }
3687 3688
        case (ty.ty_rec(?fields)) {
            let uint ix = ty.field_idx(cx.fcx.ccx.sess, sp, field, fields);
3689
            auto v = GEP_tup_like(r.bcx, t, r.val, vec(0, ix as int));
3690
            ret lval_mem(v.bcx, v.val);
3691
        }
3692 3693
        case (ty.ty_obj(?methods)) {
            let uint ix = ty.method_idx(cx.fcx.ccx.sess, sp, field, methods);
3694 3695 3696 3697 3698 3699
            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)));
3700 3701 3702

            auto lvo = lval_mem(r.bcx, v);
            ret rec(llobj = some[ValueRef](r.val) with lvo);
3703
        }
3704
        case (_) { cx.fcx.ccx.sess.unimpl("field variant in trans_field"); }
3705 3706 3707 3708
    }
    fail;
}

3709 3710
fn trans_index(@block_ctxt cx, &ast.span sp, @ast.expr base,
               @ast.expr idx, &ast.ann ann) -> lval_result {
3711

G
Graydon Hoare 已提交
3712
    auto lv = trans_expr(cx, base);
3713
    lv = autoderef(lv.bcx, lv.val, ty.expr_ty(base));
G
Graydon Hoare 已提交
3714 3715
    auto ix = trans_expr(lv.bcx, idx);
    auto v = lv.val;
3716
    auto bcx = ix.bcx;
3717

3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729
    // 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;
    }

3730 3731
    auto unit_sz = size_of(bcx, node_ann_type(cx.fcx.ccx, ann));
    bcx = unit_sz.bcx;
3732 3733

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

3735 3736
    auto lim = bcx.build.GEP(v, vec(C_int(0), C_int(abi.vec_elt_fill)));
    lim = bcx.build.Load(lim);
3737

3738 3739
    auto bounds_check = bcx.build.ICmp(lib.llvm.LLVMIntULT,
                                       scaled_ix, lim);
3740

3741 3742 3743
    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);
3744 3745

    // fail: bad bounds check.
B
Brian Anderson 已提交
3746
    auto fail_res = trans_fail(fail_cx, sp, "bounds check");
3747 3748 3749
    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)));
3750
    auto elt = next_cx.build.GEP(body, vec(C_int(0), ix_val));
3751
    ret lval_mem(next_cx, elt);
3752 3753
}

3754 3755 3756 3757
// 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).

3758
fn trans_lval(@block_ctxt cx, @ast.expr e) -> lval_result {
3759
    alt (e.node) {
3760 3761
        case (ast.expr_path(?p, ?dopt, ?ann)) {
            ret trans_path(cx, p, dopt, ann);
3762 3763 3764 3765
        }
        case (ast.expr_field(?base, ?ident, ?ann)) {
            ret trans_field(cx, e.span, base, ident, ann);
        }
3766 3767 3768
        case (ast.expr_index(?base, ?idx, ?ann)) {
            ret trans_index(cx, e.span, base, idx, ann);
        }
3769
        case (_) { cx.fcx.ccx.sess.unimpl("expr variant in trans_lval"); }
G
Graydon Hoare 已提交
3770 3771 3772 3773
    }
    fail;
}

3774
fn trans_cast(@block_ctxt cx, @ast.expr e, &ast.ann ann) -> result {
3775 3776 3777 3778
    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);
3779
    if (!ty.type_is_fp(t)) {
3780
        // TODO: native-to-native casts
3781 3782
        if (ty.type_is_native(ty.expr_ty(e))) {
            e_res.val = e_res.bcx.build.PtrToInt(e_res.val, lldsttype);
3783 3784
        } else if (ty.type_is_native(t)) {
            e_res.val = e_res.bcx.build.IntToPtr(e_res.val, lldsttype);
3785
        } else if (llvm.LLVMGetIntTypeWidth(lldsttype) >
3786
            llvm.LLVMGetIntTypeWidth(llsrctype)) {
3787
            if (ty.type_is_signed(t)) {
3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809
                // 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;
}

3810 3811 3812 3813
fn trans_bind_thunk(@crate_ctxt cx,
                    @ty.t incoming_fty,
                    @ty.t outgoing_fty,
                    vec[option.t[@ast.expr]] args,
3814
                    @ty.t closure_ty,
3815 3816
                    vec[@ty.t] bound_tys,
                    uint ty_param_count) -> ValueRef {
3817 3818 3819
    // Construct a thunk-call with signature incoming_fty, and that copies
    // args forward into a call to outgoing_fty.

3820
    let str s = mangle_name_by_seq(cx, "thunk");
3821
    let TypeRef llthunk_ty = get_pair_fn_ty(type_of(cx, incoming_fty));
3822
    let ValueRef llthunk = decl_private_fastcall_fn(cx.llmod, s, llthunk_ty);
3823

3824
    auto fcx = new_fn_ctxt(cx, llthunk);
3825 3826
    auto bcx = new_top_block_ctxt(fcx);

3827
    auto llclosure_ptr_ty = type_of(cx, ty.plain_box_ty(closure_ty));
3828
    auto llclosure = bcx.build.PointerCast(fcx.llenv, llclosure_ptr_ty);
3829

3830 3831 3832 3833 3834 3835
    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,
3836 3837 3838
                                         vec(C_int(0),
                                             C_int(abi.fn_field_box)));
    lltargetclosure = bcx.build.Load(lltargetclosure);
3839 3840

    auto outgoing_ret_ty = ty.ty_fn_ret(outgoing_fty);
3841
    auto outgoing_args = ty.ty_fn_args(outgoing_fty);
3842 3843 3844 3845 3846 3847 3848

    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,
3849
                                   fcx.lltaskptr,
3850
                                   lltargetclosure);
3851 3852 3853 3854 3855

    // Copy in the type parameters.
    let uint i = 0u;
    while (i < ty_param_count) {
        auto lltyparam_ptr =
3856 3857 3858 3859 3860 3861 3862
            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));
3863 3864 3865
        i += 1u;
    }

3866
    let uint a = 3u;    // retptr, task ptr, env come first
3867
    let int b = 0;
3868
    let uint outgoing_arg_index = 0u;
3869 3870 3871
    let vec[TypeRef] llout_arg_tys =
        type_of_explicit_args(cx, outgoing_args);

3872
    for (option.t[@ast.expr] arg in args) {
3873 3874 3875 3876

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

3877 3878 3879 3880
        alt (arg) {

            // Arg provided at binding time; thunk copies it from closure.
            case (some[@ast.expr](_)) {
3881 3882 3883 3884 3885 3886
                auto bound_arg =
                    GEP_tup_like(bcx, closure_ty, llclosure,
                                 vec(0,
                                     abi.box_rc_field_body,
                                     abi.closure_elt_bindings,
                                     b));
3887

3888
                bcx = bound_arg.bcx;
3889 3890 3891 3892 3893 3894 3895 3896 3897
                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);
                }

3898
                llargs += vec(val);
3899 3900 3901 3902 3903 3904
                b += 1;
            }

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

                if (ty.count_ty_params(out_arg.ty) > 0u) {
                    check (out_arg.mode == ast.alias);
3908
                    passed_arg = bcx.build.PointerCast(passed_arg,
3909
                                                       llout_arg_ty);
3910
                }
3911

3912
                llargs += vec(passed_arg);
3913 3914 3915
                a += 1u;
            }
        }
3916

3917
        outgoing_arg_index += 1u;
3918 3919 3920
    }

    // FIXME: turn this call + ret into a tail call.
3921
    auto lltargetfn = bcx.build.GEP(lltarget.val,
3922 3923
                                    vec(C_int(0),
                                        C_int(abi.fn_field_code)));
3924 3925 3926 3927 3928 3929 3930 3931 3932 3933

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

3934
    lltargetfn = bcx.build.Load(lltargetfn);
3935

3936
    auto r = bcx.build.FastCall(lltargetfn, llargs);
3937
    bcx.build.RetVoid();
3938 3939 3940 3941

    ret llthunk;
}

3942 3943 3944
fn trans_bind(@block_ctxt cx, @ast.expr f,
              vec[option.t[@ast.expr]] args,
              &ast.ann ann) -> result {
3945 3946 3947 3948
    auto f_res = trans_lval(cx, f);
    if (f_res.is_mem) {
        cx.fcx.ccx.sess.unimpl("re-binding existing function");
    } else {
3949 3950
        let vec[@ast.expr] bound = vec();

3951 3952 3953 3954 3955
        for (option.t[@ast.expr] argopt in args) {
            alt (argopt) {
                case (none[@ast.expr]) {
                }
                case (some[@ast.expr](?e)) {
3956
                    _vec.push[@ast.expr](bound, e);
3957 3958 3959
                }
            }
        }
3960 3961

        // Figure out which tydescs we need to pass, if any.
B
Brian Anderson 已提交
3962 3963
        let @ty.t outgoing_fty;
        let vec[ValueRef] lltydescs;
3964 3965 3966
        alt (f_res.generic) {
            case (none[generic_info]) {
                outgoing_fty = ty.expr_ty(f);
B
Brian Anderson 已提交
3967
                lltydescs = vec();
3968 3969 3970 3971 3972 3973 3974 3975 3976
            }
            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) {
3977 3978 3979 3980 3981 3982
            // 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);
3983 3984 3985 3986

            // Translate the bound expressions.
            let vec[@ty.t] bound_tys = vec();
            let vec[ValueRef] bound_vals = vec();
3987
            auto i = 0u;
3988 3989 3990
            for (@ast.expr e in bound) {
                auto arg = trans_expr(bcx, e);
                bcx = arg.bcx;
3991

3992 3993
                _vec.push[ValueRef](bound_vals, arg.val);
                _vec.push[@ty.t](bound_tys, ty.expr_ty(e));
3994 3995

                i += 1u;
3996 3997 3998
            }

            // Synthesize a closure type.
3999
            let @ty.t bindings_ty = ty.plain_tup_ty(bound_tys);
4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012

            // 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,
4013
                    ty.plain_tup_ty(captured_tys));
4014

4015
            let @ty.t closure_ty = ty.plain_tup_ty(closure_tys);
4016 4017

            auto r = trans_malloc_boxed(bcx, closure_ty);
4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034
            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);
4035 4036
            bcx = bindings_tydesc.bcx;
            bcx.build.Store(bindings_tydesc.val, bound_tydesc);
4037

4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050
            // 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));

4051 4052
            // Store thunk-target.
            auto bound_target =
4053 4054
                bcx.build.GEP(closure,
                              vec(C_int(0),
4055
                                  C_int(abi.closure_elt_target)));
4056
            auto src = bcx.build.Load(f_res.res.val);
4057
            bound_target = bcx.build.PointerCast(bound_target, llclosurety);
4058
            bcx.build.Store(src, bound_target);
4059

4060
            // Copy expr values into boxed bindings.
4061
            i = 0u;
4062 4063 4064 4065
            auto bindings =
                bcx.build.GEP(closure,
                              vec(C_int(0),
                                  C_int(abi.closure_elt_bindings)));
4066 4067
            for (ValueRef v in bound_vals) {
                auto bound = bcx.build.GEP(bindings,
4068
                                           vec(C_int(0), C_int(i as int)));
4069
                bcx = copy_ty(r.bcx, INIT, bound, v, bound_tys.(i)).bcx;
4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089
                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;
                    }
4090 4091

                    outgoing_fty = ginfo.item_type;
4092
                }
4093 4094
            }

4095 4096 4097 4098
            // 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)));
4099 4100

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

4102
            let ValueRef llthunk =
4103
                trans_bind_thunk(cx.fcx.ccx, pair_ty, outgoing_fty,
4104
                                 args, closure_ty, bound_tys,
4105
                                 ty_param_count);
4106 4107 4108 4109 4110 4111 4112

            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)));
4113 4114 4115 4116 4117
            bcx.build.Store
                (bcx.build.PointerCast
                 (box,
                  T_opaque_closure_ptr(bcx.fcx.ccx.tn)),
                 pair_box);
4118

4119
            find_scope_cx(cx).cleanups +=
4120
                vec(clean(bind drop_slot(_, pair_v, pair_ty)));
4121

4122 4123
            ret res(bcx, pair_v);
        }
4124 4125 4126
    }
}

4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137
// 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,
4138
              option.t[ValueRef] lliterbody,
4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150
              &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);
4151 4152 4153 4154
    auto llretslot_res = alloc_ty(bcx, retty);
    bcx = llretslot_res.bcx;
    auto llretslot = llretslot_res.val;

4155 4156 4157 4158 4159 4160 4161 4162 4163 4164
    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)) {
4165 4166
        llargs += vec(bcx.build.PointerCast(llretslot,
                                            T_typaram_ptr(cx.fcx.ccx.tn)));
4167 4168 4169 4170 4171 4172
    } 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.
4173 4174 4175
        llargs +=
            vec(cx.build.PointerCast(llretslot,
                                     T_ptr(type_of(bcx.fcx.ccx, retty))));
4176
    } else {
4177
        llargs += vec(llretslot);
4178 4179 4180 4181
    }


    // Arg 1: Task pointer.
4182
    llargs += vec(bcx.fcx.lltaskptr);
4183 4184 4185 4186 4187 4188 4189

    // 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).
4190
            llargs += vec(bcx.build.Load(ob));
4191 4192
        }
        case (_) {
4193
            llargs += vec(llenv);
4194 4195 4196 4197 4198 4199
        }
    }

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

4200 4201 4202 4203
    // ... then possibly an lliterbody argument.
    alt (lliterbody) {
        case (none[ValueRef]) {}
        case (some[ValueRef](?lli)) {
4204
            llargs += vec(lli);
4205 4206 4207
        }
    }

4208
    // ... then explicit args.
4209 4210 4211 4212 4213 4214

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

4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250
    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;
        }

4251 4252
        if (ty.count_ty_params(args.(i).ty) > 0u) {
            auto lldestty = arg_tys.(i);
4253 4254 4255 4256 4257 4258 4259
            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);
                }
            }

4260
            val = bcx.build.PointerCast(val, lldestty);
4261 4262
        }

4263 4264 4265 4266 4267 4268 4269 4270 4271
        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);
            }
        }

4272
        llargs += vec(val);
4273 4274 4275 4276 4277 4278
        i += 1u;
    }

    ret tup(bcx, llargs, llretslot);
}

4279
fn trans_call(@block_ctxt cx, @ast.expr f,
4280 4281 4282
              option.t[ValueRef] lliterbody,
              vec[@ast.expr] args,
              &ast.ann ann) -> result {
4283
    auto f_res = trans_lval(cx, f);
4284
    auto faddr = f_res.res.val;
4285
    auto llenv = C_null(T_opaque_closure_ptr(cx.fcx.ccx.tn));
4286 4287 4288 4289 4290 4291 4292 4293 4294

    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;
4295 4296
            auto pair = faddr;
            faddr = bcx.build.GEP(pair, vec(C_int(0),
G
Graydon Hoare 已提交
4297
                                            C_int(abi.fn_field_code)));
4298
            faddr = bcx.build.Load(faddr);
4299

4300 4301 4302 4303
            auto llclosure = bcx.build.GEP(pair,
                                           vec(C_int(0),
                                               C_int(abi.fn_field_box)));
            llenv = bcx.build.Load(llclosure);
4304
        }
4305
    }
4306 4307
    auto fn_ty = ty.expr_ty(f);
    auto ret_ty = ty.ann_to_type(ann);
G
Graydon Hoare 已提交
4308
    auto args_res = trans_args(f_res.res.bcx,
4309
                               llenv, f_res.llobj,
4310
                               f_res.generic,
4311
                               lliterbody,
4312
                               args, fn_ty);
G
Graydon Hoare 已提交
4313

4314
    auto bcx = args_res._0;
4315 4316 4317
    auto llargs = args_res._1;
    auto llretslot = args_res._2;

4318 4319 4320 4321 4322 4323 4324 4325
    /*
    log "calling: " + val_str(cx.fcx.ccx.tn, faddr);

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

4326 4327 4328 4329 4330 4331 4332 4333
    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.
4334 4335
        find_scope_cx(cx).cleanups +=
            vec(clean(bind drop_ty(_, retval, ret_ty)));
4336
    }
G
Graydon Hoare 已提交
4337

4338
    ret res(bcx, retval);
4339 4340
}

4341 4342
fn trans_tup(@block_ctxt cx, vec[ast.elt] elts,
             &ast.ann ann) -> result {
4343 4344 4345 4346 4347 4348
    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;

4349 4350
    find_scope_cx(cx).cleanups +=
        vec(clean(bind drop_ty(_, tup_val, t)));
G
Graydon Hoare 已提交
4351
    let int i = 0;
4352

4353
    for (ast.elt e in elts) {
4354 4355 4356 4357 4358 4359
        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 已提交
4360 4361
        i += 1;
    }
4362
    ret res(bcx, tup_val);
G
Graydon Hoare 已提交
4363 4364
}

4365 4366
fn trans_vec(@block_ctxt cx, vec[@ast.expr] args,
             &ast.ann ann) -> result {
4367 4368 4369
    auto t = node_ann_type(cx.fcx.ccx, ann);
    auto unit_ty = t;
    alt (t.struct) {
4370 4371
        case (ty.ty_vec(?mt)) {
            unit_ty = mt.ty;
G
Graydon Hoare 已提交
4372 4373 4374 4375 4376 4377
        }
        case (_) {
            cx.fcx.ccx.sess.bug("non-vec type in trans_vec");
        }
    }

4378 4379 4380
    auto bcx = cx;
    auto unit_sz = size_of(bcx, unit_ty);
    bcx = unit_sz.bcx;
4381 4382
    auto data_sz = bcx.build.Mul(C_int(_vec.len[@ast.expr](args) as int),
                                 unit_sz.val);
G
Graydon Hoare 已提交
4383 4384

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

4388
    auto llty = type_of(bcx.fcx.ccx, t);
4389
    auto vec_val = vi2p(bcx, sub.val, llty);
4390 4391
    find_scope_cx(bcx).cleanups +=
        vec(clean(bind drop_ty(_, vec_val, t)));
G
Graydon Hoare 已提交
4392

4393 4394 4395 4396
    auto body = bcx.build.GEP(vec_val, vec(C_int(0),
                                           C_int(abi.vec_elt_data)));

    auto pseudo_tup_ty =
4397 4398
        ty.plain_tup_ty(_vec.init_elt[@ty.t](unit_ty,
                                             _vec.len[@ast.expr](args)));
G
Graydon Hoare 已提交
4399
    let int i = 0;
4400

G
Graydon Hoare 已提交
4401
    for (@ast.expr e in args) {
4402 4403 4404 4405
        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;
4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420

        // 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)) {
4421
            auto llunit_ty = type_of(cx.fcx.ccx, unit_ty);
4422 4423 4424 4425 4426 4427
            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 已提交
4428 4429
        i += 1;
    }
4430 4431 4432
    auto fill = bcx.build.GEP(vec_val,
                              vec(C_int(0), C_int(abi.vec_elt_fill)));
    bcx.build.Store(data_sz, fill);
4433

4434
    ret res(bcx, vec_val);
G
Graydon Hoare 已提交
4435 4436
}

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

4440 4441 4442 4443 4444 4445 4446
    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;

4447 4448
    find_scope_cx(cx).cleanups +=
        vec(clean(bind drop_ty(_, rec_val, t)));
4449
    let int i = 0;
4450

G
Graydon Hoare 已提交
4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467
    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) {
4468
        auto e_ty = tf.mt.ty;
4469 4470
        auto dst_res = GEP_tup_like(bcx, t, rec_val, vec(0, i));
        bcx = dst_res.bcx;
G
Graydon Hoare 已提交
4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488

        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;
4489 4490
        i += 1;
    }
4491
    ret res(bcx, rec_val);
4492 4493
}

G
Graydon Hoare 已提交
4494

G
Graydon Hoare 已提交
4495

4496
fn trans_expr(@block_ctxt cx, @ast.expr e) -> result {
4497
    alt (e.node) {
4498
        case (ast.expr_lit(?lit, ?ann)) {
4499
            ret res(cx, trans_lit(cx.fcx.ccx, *lit, ann));
4500 4501
        }

4502
        case (ast.expr_unary(?op, ?x, ?ann)) {
4503
            ret trans_unary(cx, op, x, ann);
4504 4505
        }

P
Patrick Walton 已提交
4506
        case (ast.expr_binary(?op, ?x, ?y, _)) {
4507
            ret trans_binary(cx, op, x, y);
4508
        }
4509

P
Patrick Walton 已提交
4510
        case (ast.expr_if(?cond, ?thn, ?els, _)) {
4511
            ret trans_if(cx, cond, thn, els);
4512 4513
        }

G
Graydon Hoare 已提交
4514 4515 4516 4517
        case (ast.expr_for(?decl, ?seq, ?body, _)) {
            ret trans_for(cx, decl, seq, body);
        }

4518 4519 4520 4521
        case (ast.expr_for_each(?decl, ?seq, ?body, _)) {
            ret trans_for_each(cx, decl, seq, body);
        }

4522
        case (ast.expr_while(?cond, ?body, _)) {
4523
            ret trans_while(cx, cond, body);
4524 4525
        }

4526
        case (ast.expr_do_while(?body, ?cond, _)) {
4527
            ret trans_do_while(cx, body, cond);
4528 4529
        }

P
Patrick Walton 已提交
4530 4531 4532 4533
        case (ast.expr_alt(?expr, ?arms, _)) {
            ret trans_alt(cx, expr, arms);
        }

P
Patrick Walton 已提交
4534
        case (ast.expr_block(?blk, _)) {
4535
            ret trans_block(cx, blk);
4536
        }
4537

4538
        case (ast.expr_assign(?dst, ?src, ?ann)) {
4539
            auto lhs_res = trans_lval(cx, dst);
4540 4541
            check (lhs_res.is_mem);
            auto rhs_res = trans_expr(lhs_res.res.bcx, src);
4542
            auto t = node_ann_type(cx.fcx.ccx, ann);
G
Graydon Hoare 已提交
4543
            // FIXME: calculate copy init-ness in typestate.
4544 4545
            ret copy_ty(rhs_res.bcx, DROP_EXISTING,
                        lhs_res.res.val, rhs_res.val, t);
4546
        }
G
Graydon Hoare 已提交
4547

4548 4549 4550
        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);
4551
            check (lhs_res.is_mem);
4552
            auto lhs_val = load_scalar_or_boxed(lhs_res.res.bcx,
G
Graydon Hoare 已提交
4553
                                                lhs_res.res.val, t);
4554
            auto rhs_res = trans_expr(lhs_res.res.bcx, src);
4555 4556
            auto v = trans_eager_binop(rhs_res.bcx, op, t,
                                       lhs_val, rhs_res.val);
4557
            // FIXME: calculate copy init-ness in typestate.
4558 4559
            ret copy_ty(v.bcx, DROP_EXISTING,
                        lhs_res.res.val, v.val, t);
4560 4561
        }

4562 4563 4564 4565
        case (ast.expr_bind(?f, ?args, ?ann)) {
            ret trans_bind(cx, f, args, ann);
        }

G
Graydon Hoare 已提交
4566
        case (ast.expr_call(?f, ?args, ?ann)) {
4567
            ret trans_call(cx, f, none[ValueRef], args, ann);
4568 4569
        }

4570
        case (ast.expr_cast(?e, _, ?ann)) {
4571
            ret trans_cast(cx, e, ann);
4572
        }
G
Graydon Hoare 已提交
4573

4574
        case (ast.expr_vec(?args, _, ?ann)) {
G
Graydon Hoare 已提交
4575 4576 4577
            ret trans_vec(cx, args, ann);
        }

G
Graydon Hoare 已提交
4578 4579 4580
        case (ast.expr_tup(?args, ?ann)) {
            ret trans_tup(cx, args, ann);
        }
G
Graydon Hoare 已提交
4581

4582 4583
        case (ast.expr_rec(?args, ?base, ?ann)) {
            ret trans_rec(cx, args, base, ann);
4584 4585
        }

4586
        case (ast.expr_ext(_, _, _, ?expanded, _)) {
4587
            ret trans_expr(cx, expanded);
4588 4589
        }

4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605
        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);
        }

4606
        case (ast.expr_put(?e)) {
4607 4608 4609
            ret trans_put(cx, e);
        }

4610 4611 4612 4613
        case (ast.expr_be(?e)) {
            ret trans_be(cx, e);
        }

B
Brian Anderson 已提交
4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629
        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);
        }

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

4633
        case (_) {
4634
            auto t = ty.expr_ty(e);
4635
            auto sub = trans_lval(cx, e);
4636
            ret res(sub.res.bcx,
4637
                    load_scalar_or_boxed(sub.res.bcx, sub.res.val, t));
4638
        }
4639
    }
4640
    cx.fcx.ccx.sess.unimpl("expr variant in trans_expr");
4641 4642 4643
    fail;
}

4644
// We pass structural values around the compiler "by pointer" and
4645 4646
// non-structural values (scalars and boxes) "by value". This function selects
// whether to load a pointer or pass it.
4647

4648 4649 4650
fn load_scalar_or_boxed(@block_ctxt cx,
                        ValueRef v,
                        @ty.t t) -> ValueRef {
4651
    if (ty.type_is_scalar(t) || ty.type_is_boxed(t) || ty.type_is_native(t)) {
4652
        ret cx.build.Load(v);
4653 4654
    } else {
        ret v;
4655 4656 4657
    }
}

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

4660
    auto sub = trans_expr(cx, e);
4661
    auto e_ty = ty.expr_ty(e);
4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682
    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);
4683
            sub.bcx.build.Store(sub.val, tmp);
4684 4685 4686 4687
            auto v = vp2i(sub.bcx, tmp);
            ret trans_upcall(sub.bcx,
                             "upcall_log_double",
                             vec(v));
4688 4689 4690
        }
    }

4691
    alt (e_ty.struct) {
4692
        case (ty.ty_str) {
4693
            auto v = vp2i(sub.bcx, sub.val);
4694 4695 4696
            ret trans_upcall(sub.bcx,
                             "upcall_log_str",
                             vec(v));
4697 4698
        }
        case (_) {
4699 4700 4701
            ret trans_upcall(sub.bcx,
                             "upcall_log_int",
                             vec(sub.val));
4702 4703
        }
    }
4704
    fail;
4705 4706
}

4707
fn trans_check_expr(@block_ctxt cx, @ast.expr e) -> result {
4708 4709 4710
    auto cond_res = trans_expr(cx, e);

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

4715
    auto next_cx = new_sub_block_ctxt(cx, "next");
4716 4717 4718 4719 4720 4721 4722
    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 已提交
4723 4724 4725 4726 4727 4728 4729 4730 4731
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);
}

4732
fn trans_put(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756
    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);
4757 4758

            auto llarg = r.val;
4759
            bcx = r.bcx;
4760 4761 4762 4763 4764 4765
            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);
            }

4766
            llargs += vec(llarg);
4767 4768
        }
    }
4769

4770
    ret res(bcx, bcx.build.FastCall(llcallee, llargs));
4771 4772
}

4773 4774 4775 4776
fn trans_ret(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
    auto bcx = cx;
    auto val = C_nil();

4777 4778
    alt (e) {
        case (some[@ast.expr](?x)) {
4779
            auto t = ty.expr_ty(x);
4780 4781 4782
            auto r = trans_expr(cx, x);
            bcx = r.bcx;
            val = r.val;
4783
            bcx = copy_ty(bcx, INIT, cx.fcx.llretptr, val, t).bcx;
4784
        }
4785
        case (_) { /* fall through */  }
4786 4787
    }

4788 4789
    // Run all cleanups and back out.
    let bool more_cleanups = true;
4790
    auto cleanup_cx = cx;
4791
    while (more_cleanups) {
4792
        bcx = trans_block_cleanups(bcx, cleanup_cx);
4793
        alt (cleanup_cx.parent) {
4794
            case (parent_some(?b)) {
4795
                cleanup_cx = b;
4796 4797 4798 4799 4800 4801 4802
            }
            case (parent_none) {
                more_cleanups = false;
            }
        }
    }

4803 4804
    bcx.build.RetVoid();
    ret res(bcx, C_nil());
4805 4806
}

4807
fn trans_be(@block_ctxt cx, @ast.expr e) -> result {
4808
    // FIXME: This should be a typestate precondition
4809
    check (ast.is_call_expr(e));
4810 4811
    // FIXME: Turn this into a real tail call once
    // calling convention issues are settled
4812 4813 4814
    ret trans_ret(cx, some(e));
}

B
Brian Anderson 已提交
4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864
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 {
4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883

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

4884 4885 4886 4887
    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;
4888

4889 4890
    find_scope_cx(bcx).cleanups +=
        vec(clean(bind drop_ty(_, data_alloc.val, unit_ty)));
4891

4892 4893 4894
    auto sub = trans_upcall(bcx, "upcall_send",
                            vec(vp2i(bcx, chn.val),
                                vp2i(bcx, data_alloc.val)));
4895 4896
    bcx = sub.bcx;

4897
    ret res(bcx, chn.val);
B
Brian Anderson 已提交
4898 4899 4900 4901
}

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

    auto bcx = cx;
B
Brian Anderson 已提交
4904 4905 4906
    auto data = trans_lval(bcx, lhs);
    check (data.is_mem);
    bcx = data.res.bcx;
4907 4908 4909 4910 4911 4912 4913 4914 4915 4916
    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;
4917 4918
    auto prt = trans_expr(bcx, rhs);
    bcx = prt.bcx;
B
Brian Anderson 已提交
4919

4920
    auto sub = trans_upcall(bcx, "upcall_recv",
4921
                            vec(vp2i(bcx, lhs),
4922 4923 4924
                                vp2i(bcx, prt.val)));
    bcx = sub.bcx;

4925 4926
    auto data_load = load_scalar_or_boxed(bcx, lhs, unit_ty);
    auto cp = copy_ty(bcx, action, lhs, data_load, unit_ty);
4927
    bcx = cp.bcx;
B
Brian Anderson 已提交
4928

4929
    // TODO: Any cleanup need to be done here?
4930

4931
    ret res(bcx, lhs);
B
Brian Anderson 已提交
4932 4933
}

4934 4935 4936 4937 4938 4939 4940 4941 4942
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 +=
4943
        vec(clean(bind drop_slot(_, llptr, ty)));
4944 4945

    alt (local.init) {
4946
        case (some[ast.initializer](?init)) {
4947 4948 4949 4950 4951 4952 4953 4954 4955
            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;
                }
            }
4956 4957 4958
        }
        case (_) {
            if (middle.ty.type_has_dynamic_size(ty)) {
4959 4960
                auto llsz = size_of(bcx, ty);
                bcx = call_bzero(llsz.bcx, llptr, llsz.val).bcx;
4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973

            } 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;
4974
    alt (s.node) {
4975
        case (ast.stmt_expr(?e)) {
4976
            bcx = trans_expr(cx, e).bcx;
4977
        }
4978

4979 4980 4981
        case (ast.stmt_decl(?d)) {
            alt (d.node) {
                case (ast.decl_local(?local)) {
4982
                    bcx = init_local(bcx, local).bcx;
4983
                }
G
Graydon Hoare 已提交
4984 4985 4986
                case (ast.decl_item(?i)) {
                    trans_item(cx.fcx.ccx, *i);
                }
4987 4988
            }
        }
4989
        case (_) {
4990
            cx.fcx.ccx.sess.unimpl("stmt variant");
4991 4992
        }
    }
4993
    ret res(bcx, C_nil());
4994 4995
}

4996
fn new_builder(BasicBlockRef llbb) -> builder {
4997 4998 4999 5000 5001
    let BuilderRef llbuild = llvm.LLVMCreateBuilder();
    llvm.LLVMPositionBuilderAtEnd(llbuild, llbb);
    ret builder(llbuild);
}

5002 5003
// You probably don't want to use this one. See the
// next three functions instead.
5004
fn new_block_ctxt(@fn_ctxt cx, block_parent parent,
5005
                  block_kind kind,
5006
                  str name) -> @block_ctxt {
5007
    let vec[cleanup] cleanups = vec();
5008
    let BasicBlockRef llbb =
5009
        llvm.LLVMAppendBasicBlock(cx.llfn,
5010
                                  _str.buf(cx.ccx.names.next(name)));
5011

5012
    ret @rec(llbb=llbb,
5013
             build=new_builder(llbb),
5014
             parent=parent,
5015
             kind=kind,
5016
             mutable cleanups=cleanups,
5017 5018 5019
             fcx=cx);
}

5020 5021
// 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 {
5022 5023 5024 5025 5026 5027 5028
    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;
5029
}
5030

5031 5032
// 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 {
5033
    ret new_block_ctxt(bcx.fcx, parent_some(bcx), SCOPE_BLOCK, n);
5034 5035
}

5036
// Use this when you're making a general CFG BB within a scope.
5037
fn new_sub_block_ctxt(@block_ctxt bcx, str n) -> @block_ctxt {
5038
    ret new_block_ctxt(bcx.fcx, parent_some(bcx), NON_SCOPE_BLOCK, n);
5039
}
5040

5041

5042 5043
fn trans_block_cleanups(@block_ctxt cx,
                        @block_ctxt cleanup_cx) -> @block_ctxt {
5044
    auto bcx = cx;
5045

5046
    if (cleanup_cx.kind != SCOPE_BLOCK) {
5047 5048 5049
        check (_vec.len[cleanup](cleanup_cx.cleanups) == 0u);
    }

5050 5051 5052 5053
    auto i = _vec.len[cleanup](cleanup_cx.cleanups);
    while (i > 0u) {
        i -= 1u;
        auto c = cleanup_cx.cleanups.(i);
5054
        alt (c) {
5055
            case (clean(?cfn)) {
5056
                bcx = cfn(bcx).bcx;
5057 5058 5059
            }
        }
    }
5060 5061 5062
    ret bcx;
}

5063 5064 5065 5066 5067 5068 5069 5070 5071 5072
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;
                    }
5073
                    case (_) { /* fall through */ }
5074 5075
                }
            }
5076
            case (_) { /* fall through */ }
5077 5078 5079 5080
        }
    }
}

5081
fn alloc_ty(@block_ctxt cx, @ty.t t) -> result {
5082
    auto val = C_int(0);
5083
    auto bcx = cx;
5084
    if (ty.type_has_dynamic_size(t)) {
5085 5086 5087
        auto n = size_of(bcx, t);
        bcx = n.bcx;
        val = bcx.build.ArrayAlloca(T_i8(), n.val);
5088
    } else {
5089
        val = bcx.build.Alloca(type_of(cx.fcx.ccx, t));
5090
    }
5091
    ret res(bcx, val);
5092 5093
}

5094 5095 5096 5097 5098 5099 5100
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;
}

5101
fn trans_block(@block_ctxt cx, &ast.block b) -> result {
5102 5103
    auto bcx = cx;

5104
    for each (@ast.local local in block_locals(b)) {
5105
        bcx = alloc_local(bcx, local).bcx;
5106
    }
5107
    auto r = res(bcx, C_nil());
5108

5109
    for (@ast.stmt s in b.node.stmts) {
5110 5111
        r = trans_stmt(bcx, *s);
        bcx = r.bcx;
5112 5113 5114 5115 5116
        // 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;
        }
5117
    }
5118

5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131
    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());
        }
    }

5132
    bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
5133
    ret res(bcx, r.val);
5134 5135
}

5136 5137 5138 5139 5140 5141 5142
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args

5143
fn new_fn_ctxt(@crate_ctxt cx,
5144
               ValueRef llfndecl) -> @fn_ctxt {
5145

5146 5147 5148
    let ValueRef llretptr = llvm.LLVMGetParam(llfndecl, 0u);
    let ValueRef lltaskptr = llvm.LLVMGetParam(llfndecl, 1u);
    let ValueRef llenv = llvm.LLVMGetParam(llfndecl, 2u);
5149 5150

    let hashmap[ast.def_id, ValueRef] llargs = new_def_hash[ValueRef]();
5151 5152
    let hashmap[ast.def_id, ValueRef] llobjfields = new_def_hash[ValueRef]();
    let hashmap[ast.def_id, ValueRef] lllocals = new_def_hash[ValueRef]();
5153
    let hashmap[ast.def_id, ValueRef] llupvars = new_def_hash[ValueRef]();
5154
    let hashmap[ast.def_id, ValueRef] lltydescs = new_def_hash[ValueRef]();
5155

5156
    ret @rec(llfn=llfndecl,
5157
             lltaskptr=lltaskptr,
5158 5159
             llenv=llenv,
             llretptr=llretptr,
5160
             mutable llself=none[ValueRef],
5161
             mutable lliterbody=none[ValueRef],
5162
             llargs=llargs,
5163
             llobjfields=llobjfields,
5164
             lllocals=lllocals,
5165
             llupvars=llupvars,
5166
             lltydescs=lltydescs,
5167
             ccx=cx);
5168 5169
}

5170 5171 5172 5173 5174 5175 5176
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args

5177
fn create_llargs_for_fn_args(&@fn_ctxt cx,
5178
                             ast.proto proto,
5179
                             option.t[TypeRef] ty_self,
5180
                             @ty.t ret_ty,
5181
                             &vec[ast.arg] args,
5182
                             &vec[ast.ty_param] ty_params) {
5183 5184 5185 5186 5187 5188 5189 5190 5191 5192

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

    auto arg_n = 3u;
5193

5194 5195 5196 5197 5198 5199 5200
    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;
        }
5201 5202
    }

5203
    if (proto == ast.proto_iter) {
5204 5205 5206 5207 5208
        auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n);
        check (llarg as int != 0);
        cx.lliterbody = some[ValueRef](llarg);
        arg_n += 1u;
    }
5209

5210 5211 5212 5213 5214 5215 5216 5217
    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;
    }
}

5218 5219 5220 5221
// 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.

5222 5223 5224 5225
fn copy_args_to_allocas(@block_ctxt cx,
                        option.t[TypeRef] ty_self,
                        vec[ast.arg] args,
                        vec[ty.arg] arg_tys) {
5226 5227 5228

    let uint arg_n = 0u;

5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242
    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 (_) {
        }
    }

5243
    for (ast.arg aarg in args) {
5244 5245 5246 5247 5248 5249 5250 5251 5252
        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);
        }

5253 5254 5255 5256
        arg_n += 1u;
    }
}

5257 5258 5259 5260 5261
fn is_terminated(@block_ctxt cx) -> bool {
    auto inst = llvm.LLVMGetLastInstruction(cx.llbb);
    ret llvm.LLVMIsATerminatorInst(inst) as int != 0;
}

5262 5263
fn arg_tys_of_fn(ast.ann ann) -> vec[ty.arg] {
    alt (ty.ann_to_type(ann).struct) {
5264
        case (ty.ty_fn(_, ?arg_tys, _)) {
5265 5266 5267 5268 5269 5270
            ret arg_tys;
        }
    }
    fail;
}

5271 5272
fn ret_ty_of_fn_ty(@ty.t t) -> @ty.t {
    alt (t.struct) {
5273
        case (ty.ty_fn(_, _, ?ret_ty)) {
5274 5275 5276 5277 5278 5279
            ret ret_ty;
        }
    }
    fail;
}

5280 5281 5282 5283 5284

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

5285 5286
fn populate_fn_ctxt_from_llself(@block_ctxt cx, ValueRef llself) -> result {
    auto bcx = cx;
5287

5288
    let vec[@ty.t] field_tys = vec();
5289

5290 5291
    for (ast.obj_field f in bcx.fcx.ccx.obj_fields) {
        field_tys += vec(node_ann_type(bcx.fcx.ccx, f.ann));
5292 5293
    }

5294 5295
    // Synthesize a tuple type for the fields so that GEP_tup_like() can work
    // its magic.
5296
    auto fields_tup_ty = ty.plain_tup_ty(field_tys);
5297 5298 5299

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

    auto box_cell =
5302 5303 5304
        bcx.build.GEP(llself,
                      vec(C_int(0),
                          C_int(abi.obj_field_box)));
5305

5306
    auto box_ptr = bcx.build.Load(box_cell);
5307

5308
    box_ptr = bcx.build.PointerCast(box_ptr, llobj_box_ty);
5309

5310
    auto obj_typarams = bcx.build.GEP(box_ptr,
5311 5312 5313 5314
                                     vec(C_int(0),
                                         C_int(abi.box_rc_field_body),
                                         C_int(abi.obj_body_elt_typarams)));

5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329
    // 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()));
    }

5330 5331

    let int i = 0;
5332

5333 5334 5335 5336 5337 5338
    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);
5339 5340 5341 5342
        i += 1;
    }

    i = 0;
5343 5344 5345 5346
    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;
5347 5348 5349
        cx.fcx.llobjfields.insert(f.id, llfield);
        i += 1;
    }
5350 5351

    ret res(bcx, C_nil());
5352 5353
}

5354 5355 5356
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) {
5357

5358 5359
    auto llfndecl = cx.item_ids.get(fid);

5360
    auto fcx = new_fn_ctxt(cx, llfndecl);
5361
    create_llargs_for_fn_args(fcx, f.proto,
5362
                              ty_self, ret_ty_of_fn(ann),
5363
                              f.decl.inputs, ty_params);
5364
    auto bcx = new_top_block_ctxt(fcx);
5365

5366
    copy_args_to_allocas(bcx, ty_self, f.decl.inputs,
5367 5368 5369 5370
                         arg_tys_of_fn(ann));

    alt (fcx.llself) {
        case (some[ValueRef](?llself)) {
5371
            bcx = populate_fn_ctxt_from_llself(bcx, llself).bcx;
5372 5373 5374 5375
        }
        case (_) {
        }
    }
5376

5377 5378
    auto res = trans_block(bcx, f.body);
    if (!is_terminated(res.bcx)) {
5379 5380
        // FIXME: until LLVM has a unit type, we are moving around
        // C_nil values rather than their void type.
5381
        res.bcx.build.RetVoid();
5382
    }
5383 5384
}

5385 5386 5387
fn trans_vtbl(@crate_ctxt cx, TypeRef self_ty,
              &ast._obj ob,
              &vec[ast.ty_param] ty_params) -> ValueRef {
G
Graydon Hoare 已提交
5388
    let vec[ValueRef] methods = vec();
5389 5390 5391 5392 5393 5394 5395 5396 5397

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

5399 5400
        auto llfnty = T_nil();
        alt (node_ann_type(cx, m.node.ann).struct) {
5401 5402
            case (ty.ty_fn(?proto, ?inputs, ?output)) {
                llfnty = type_of_fn_full(cx, proto,
5403
                                         some[TypeRef](self_ty),
5404 5405
                                         inputs, output,
                                         _vec.len[ast.ty_param](ty_params));
5406 5407 5408
            }
        }

5409 5410
        let @crate_ctxt mcx = extend_path(cx, m.node.ident);
        let str s = mangle_name_by_seq(mcx, "method");
5411
        let ValueRef llfn = decl_private_fastcall_fn(cx.llmod, s, llfnty);
5412
        cx.item_ids.insert(m.node.id, llfn);
P
Patrick Walton 已提交
5413
        cx.item_symbols.insert(m.node.id, s);
5414

5415 5416
        trans_fn(mcx, m.node.meth, m.node.id, some[TypeRef](self_ty),
                 ty_params, m.node.ann);
5417
        methods += vec(llfn);
G
Graydon Hoare 已提交
5418
    }
5419
    auto vtbl = C_struct(methods);
5420 5421 5422
    auto vtbl_name = mangle_name_by_seq(cx, "vtbl");
    auto gvar = llvm.LLVMAddGlobal(cx.llmod, val_ty(vtbl),
                                   _str.buf(vtbl_name));
5423 5424
    llvm.LLVMSetInitializer(gvar, vtbl);
    llvm.LLVMSetGlobalConstant(gvar, True);
5425 5426
    llvm.LLVMSetLinkage(gvar, lib.llvm.LLVMPrivateLinkage
                        as llvm.Linkage);
5427
    ret gvar;
G
Graydon Hoare 已提交
5428 5429
}

5430 5431
fn trans_obj(@crate_ctxt cx, &ast._obj ob, ast.def_id oid,
             &vec[ast.ty_param] ty_params, &ast.ann ann) {
5432 5433 5434

    auto llctor_decl = cx.item_ids.get(oid);

5435
    // Translate obj ctor args to function arguments.
5436 5437 5438 5439 5440 5441 5442 5443
    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));
    }

5444
    auto fcx = new_fn_ctxt(cx, llctor_decl);
5445
    create_llargs_for_fn_args(fcx, ast.proto_fn,
5446
                              none[TypeRef], ret_ty_of_fn(ann),
5447
                              fn_args, ty_params);
5448 5449 5450

    auto bcx = new_top_block_ctxt(fcx);

5451
    let vec[ty.arg] arg_tys = arg_tys_of_fn(ann);
5452
    copy_args_to_allocas(bcx, none[TypeRef], fn_args, arg_tys);
5453

5454
    auto llself_ty = type_of(cx, ret_ty_of_fn(ann));
5455
    auto pair = bcx.fcx.llretptr;
5456
    auto vtbl = trans_vtbl(cx, llself_ty, ob, ty_params);
5457 5458 5459
    auto pair_vtbl = bcx.build.GEP(pair,
                                   vec(C_int(0),
                                       C_int(abi.obj_field_vtbl)));
5460 5461 5462
    auto pair_box = bcx.build.GEP(pair,
                                  vec(C_int(0),
                                      C_int(abi.obj_field_box)));
5463
    bcx.build.Store(vtbl, pair_vtbl);
5464

5465
    let TypeRef llbox_ty = T_opaque_obj_ptr(cx.tn);
5466 5467 5468 5469

    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.
5470 5471 5472 5473 5474
        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) {
5475
            _vec.push[@ty.t](obj_fields, a.ty);
5476
        }
5477 5478

        // Synthesize an obj body type.
5479 5480 5481
        auto tydesc_ty = plain_ty(ty.ty_type);
        let vec[@ty.t] tps = vec();
        for (ast.ty_param tp in ty_params) {
5482
            _vec.push[@ty.t](tps, tydesc_ty);
5483 5484
        }

5485 5486 5487 5488 5489 5490
        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);
5491

5492
        // Malloc a box for the body.
5493
        auto box = trans_malloc_boxed(bcx, body_ty);
5494 5495 5496 5497 5498 5499 5500 5501
        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);
5502

5503 5504
        // Store body tydesc.
        auto body_tydesc =
5505 5506 5507
            GEP_tup_like(bcx, body_ty, body.val,
                         vec(0, abi.obj_body_elt_tydesc));
        bcx = body_tydesc.bcx;
5508

5509 5510 5511
        auto body_td = get_tydesc(bcx, body_ty);
        bcx = body_td.bcx;
        bcx.build.Store(body_td.val, body_tydesc.val);
5512

5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527
        // 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;
        }

5528 5529
        // Copy args into body fields.
        auto body_fields =
5530 5531 5532
            GEP_tup_like(bcx, body_ty, body.val,
                         vec(0, abi.obj_body_elt_fields));
        bcx = body_fields.bcx;
5533

5534
        i = 0;
5535
        for (ast.obj_field f in ob.fields) {
5536 5537
            auto arg = bcx.fcx.llargs.get(f.id);
            arg = load_scalar_or_boxed(bcx, arg, arg_tys.(i).ty);
5538 5539 5540 5541
            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;
5542 5543 5544
            i += 1;
        }
        // Store box ptr in outer pair.
5545
        auto p = bcx.build.PointerCast(box.val, llbox_ty);
5546
        bcx.build.Store(p, pair_box);
5547
    }
5548
    bcx.build.RetVoid();
5549 5550
}

5551
fn trans_tag_variant(@crate_ctxt cx, ast.def_id tag_id,
5552 5553
                     &ast.variant variant, int index,
                     &vec[ast.ty_param] ty_params) {
5554
    if (_vec.len[ast.variant_arg](variant.args) == 0u) {
5555 5556 5557
        ret;    // nullary constructors are just constants
    }

5558 5559 5560 5561 5562 5563 5564 5565 5566 5567
    // 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));
    }

5568
    check (cx.item_ids.contains_key(variant.id));
5569 5570
    let ValueRef llfndecl = cx.item_ids.get(variant.id);

5571
    auto fcx = new_fn_ctxt(cx, llfndecl);
5572
    create_llargs_for_fn_args(fcx, ast.proto_fn,
5573
                              none[TypeRef], ret_ty_of_fn(variant.ann),
5574
                              fn_args, ty_params);
5575

5576 5577 5578 5579 5580
    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)));
    }

5581 5582 5583
    auto bcx = new_top_block_ctxt(fcx);

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

5586 5587 5588 5589 5590
    // 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,
5591
                                      vec(C_int(0), C_int(0)));
5592 5593
    bcx.build.Store(C_int(index), lldiscrimptr);

5594
    auto llblobptr = bcx.build.GEP(lltagptr,
5595
                                   vec(C_int(0), C_int(1)));
5596 5597 5598

    i = 0u;
    for (ast.variant_arg va in variant.args) {
5599 5600
        auto rslt = GEP_tag(bcx, llblobptr, tag_id, variant.id,
                            ty_param_substs, i as int);
5601 5602
        bcx = rslt.bcx;
        auto lldestptr = rslt.val;
5603

5604 5605 5606 5607 5608 5609
        // 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));

5610 5611
        auto arg_ty = arg_tys.(i).ty;
        auto llargval;
5612 5613
        if (ty.type_is_structural(arg_ty) ||
                ty.type_has_dynamic_size(arg_ty)) {
5614 5615 5616 5617 5618 5619 5620 5621
            llargval = llargptr;
        } else {
            llargval = bcx.build.Load(llargptr);
        }

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

5622 5623 5624 5625
        i += 1u;
    }

    bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
5626
    bcx.build.RetVoid();
5627 5628
}

5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644
// 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);
5645 5646 5647 5648 5649 5650

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

5653
fn trans_item(@crate_ctxt cx, &ast.item item) {
5654
    alt (item.node) {
5655
        case (ast.item_fn(?name, ?f, ?tps, ?fid, ?ann)) {
5656
            auto sub_cx = extend_path(cx, name);
5657
            trans_fn(sub_cx, f, fid, none[TypeRef], tps, ann);
5658
        }
5659
        case (ast.item_obj(?name, ?ob, ?tps, ?oid, ?ann)) {
5660 5661 5662
            auto sub_cx = @rec(obj_typarams=tps,
                               obj_fields=ob.fields with
                               *extend_path(cx, name));
5663
            trans_obj(sub_cx, ob, oid, tps, ann);
5664
        }
5665
        case (ast.item_mod(?name, ?m, _)) {
5666
            auto sub_cx = extend_path(cx, name);
5667
            trans_mod(sub_cx, m);
5668
        }
5669
        case (ast.item_tag(?name, ?variants, ?tps, ?tag_id)) {
5670
            auto sub_cx = extend_path(cx, name);
5671
            auto i = 0;
5672
            for (ast.variant variant in variants) {
5673
                trans_tag_variant(sub_cx, tag_id, variant, i, tps);
5674
                i += 1;
5675 5676
            }
        }
5677
        case (ast.item_const(?name, _, ?expr, ?cid, ?ann)) {
5678
            auto sub_cx = extend_path(cx, name);
5679 5680
            trans_const(sub_cx, expr, cid, ann);
        }
5681
        case (_) { /* fall through */ }
5682 5683 5684
    }
}

5685
fn trans_mod(@crate_ctxt cx, &ast._mod m) {
5686 5687
    for (@ast.item item in m.items) {
        trans_item(cx, *item);
5688 5689 5690
    }
}

5691 5692 5693 5694 5695 5696 5697 5698
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));
}

5699
fn decl_fn_and_pair(@crate_ctxt cx,
5700
                    str flav,
5701
                    vec[ast.ty_param] ty_params,
5702 5703 5704
                    &ast.ann ann,
                    ast.def_id id) {

5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717
    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;
        }
    }
5718 5719

    // Declare the function itself.
5720
    let str s = mangle_name_by_seq(cx, flav);
5721
    let ValueRef llfn = decl_private_fastcall_fn(cx.llmod, s, llfty);
5722 5723

    // Declare the global constant pair that points to it.
5724
    let str ps = mangle_name_by_type(cx, node_ann_type(cx, ann));
5725 5726 5727 5728 5729 5730

    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) {
5731 5732 5733
    let ValueRef gvar = llvm.LLVMAddGlobal(cx.llmod, llpairty,
                                           _str.buf(ps));
    auto pair = C_struct(vec(llfn,
5734
                             C_null(T_opaque_closure_ptr(cx.tn))));
5735 5736 5737

    llvm.LLVMSetInitializer(gvar, pair);
    llvm.LLVMSetGlobalConstant(gvar, True);
5738 5739 5740
    llvm.LLVMSetVisibility(gvar,
                           lib.llvm.LLVMProtectedVisibility
                           as llvm.Visibility);
5741 5742

    cx.item_ids.insert(id, llfn);
P
Patrick Walton 已提交
5743
    cx.item_symbols.insert(id, ps);
5744 5745 5746
    cx.fn_pairs.insert(id, gvar);
}

5747 5748 5749 5750 5751 5752 5753 5754 5755 5756
// 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;
        }
5757
        case (ast.native_item_fn(_, _, _, ?tps, _, _)) {
5758 5759 5760 5761 5762 5763 5764 5765
            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 {
5766 5767 5768
    auto x = node_ann_type(cx, ann);
    alt (x.struct) {
        case (ty.ty_native_fn(?abi, ?args, ?out)) {
5769
            ret type_of_fn(cx, ast.proto_fn, args, out, ty_param_count);
5770 5771 5772 5773 5774
        }
    }
    fail;
}

5775 5776 5777 5778
fn decl_native_fn_and_pair(@crate_ctxt cx,
                           str name,
                           &ast.ann ann,
                           ast.def_id id) {
5779 5780
    auto num_ty_param = native_fn_ty_param_count(cx, id);

5781
    // Declare the wrapper.
5782
    auto wrapper_type = native_fn_wrapper_type(cx, num_ty_param, ann);
5783
    let str s = mangle_name_by_seq(cx, "wrapper");
5784 5785
    let ValueRef wrapper_fn = decl_private_fastcall_fn(cx.llmod, s,
                                                       wrapper_type);
5786

5787 5788
    // Declare the global constant pair that points to it.
    auto wrapper_pair_type = T_fn_pair(cx.tn, wrapper_type);
5789
    let str ps = mangle_name_by_type(cx, node_ann_type(cx, ann));
5790

5791 5792
    register_fn_pair(cx, ps, wrapper_pair_type, wrapper_fn, id);

5793 5794 5795 5796
    // Build the wrapper.
    auto fcx = new_fn_ctxt(cx, wrapper_fn);
    auto bcx = new_top_block_ctxt(fcx);

5797 5798 5799 5800
    // Declare the function itself.
    auto item = cx.native_items.get(id);
    auto fn_type = node_ann_type(cx, ann);  // NB: has no type params

5801
    auto abi = ty.ty_fn_abi(fn_type);
5802 5803
    auto llfnty = type_of_native_fn(cx, abi, ty.ty_fn_args(fn_type),
                                    ty.ty_fn_ret(fn_type), num_ty_param);
5804

5805
    let vec[ValueRef] call_args = vec();
5806
    auto arg_n = 3u;
5807 5808
    auto pass_task;

5809
    auto lltaskptr = bcx.build.PtrToInt(fcx.lltaskptr, T_int());
5810 5811
    alt (abi) {
        case (ast.native_abi_rust) {
5812
            pass_task = true;
5813
            call_args += vec(lltaskptr);
5814 5815 5816
            for each (uint i in _uint.range(0u, num_ty_param)) {
                auto llarg = llvm.LLVMGetParam(fcx.llfn, arg_n);
                check (llarg as int != 0);
5817
                call_args += vec(bcx.build.PointerCast(llarg, T_i32()));
5818 5819 5820 5821
                arg_n += 1u;
            }
        }
        case (ast.native_abi_cdecl) {
5822
            pass_task = false;
5823 5824 5825 5826 5827 5828
        }
    }
    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);
5829
        call_args += vec(bcx.build.PointerCast(llarg, T_i32()));
5830 5831
        arg_n += 1u;
    }
5832

5833 5834
    auto r = trans_native(bcx.build, cx.glues, lltaskptr, cx.externs, cx.tn,
                          cx.llmod, name, pass_task, call_args);
5835 5836
    auto rptr = bcx.build.BitCast(fcx.llretptr, T_ptr(T_i32()));
    bcx.build.Store(r, rptr);
5837
    bcx.build.RetVoid();
5838 5839
}

5840 5841
fn collect_native_item(&@crate_ctxt cx, @ast.native_item i) -> @crate_ctxt {
    alt (i.node) {
5842
        case (ast.native_item_fn(?name, _, _, _, ?fid, ?ann)) {
5843 5844
            cx.native_items.insert(fid, i);
            if (! cx.obj_methods.contains_key(fid)) {
5845
                decl_native_fn_and_pair(cx, name, ann, fid);
5846 5847 5848 5849 5850 5851
            }
        }
        case (_) { /* fall through */ }
    }
    ret cx;
}
5852

5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877
fn item_name(@ast.item i) -> str {
    alt (i.node) {
        case (ast.item_mod(?name, _, _)) {
            ret name;
        }
        case (ast.item_tag(?name, _, _, _)) {
            ret name;
        }
        case (ast.item_const(?name, _, _, _, _)) {
            ret name;
        }
        case (ast.item_fn(?name, _, _, _, _)) {
            ret name;
        }
        case (ast.item_native_mod(?name, _, _)) {
            ret name;
        }
        case (ast.item_ty(?name, _, _, _, _)) {
            ret name;
        }
        case (ast.item_obj(?name, _, _, _, _)) {
            ret name;
        }
    }
}
5878

5879
fn collect_item(&@crate_ctxt cx, @ast.item i) -> @crate_ctxt {
5880
    alt (i.node) {
5881 5882 5883 5884 5885 5886
        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);
5887
            cx.items.insert(cid, i);
5888
            cx.consts.insert(cid, g);
5889 5890 5891 5892 5893 5894
        }

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

5895
        case (ast.item_tag(?name, ?variants, ?tps, ?tag_id)) {
5896 5897 5898 5899
            cx.items.insert(tag_id, i);
        }
        case (_) { /* fall through */ }
    }
5900
    ret extend_path(cx, item_name(i));
5901 5902 5903
}

fn collect_item_pass2(&@crate_ctxt cx, @ast.item i) -> @crate_ctxt {
5904
    alt (i.node) {
5905
        case (ast.item_fn(?name, ?f, ?tps, ?fid, ?ann)) {
5906
            cx.items.insert(fid, i);
5907
            if (! cx.obj_methods.contains_key(fid)) {
5908 5909
                decl_fn_and_pair(extend_path(cx, name), "fn",
                                 tps, ann, fid);
5910
            }
5911 5912
        }

5913
        case (ast.item_obj(?name, ?ob, ?tps, ?oid, ?ann)) {
5914
            cx.items.insert(oid, i);
5915 5916
            decl_fn_and_pair(extend_path(cx, name), "obj_ctor",
                             tps, ann, oid);
5917 5918 5919
            for (@ast.method m in ob.methods) {
                cx.obj_methods.insert(m.node.id, ());
            }
5920 5921
        }

5922
        case (_) { /* fall through */ }
5923
    }
5924
    ret extend_path(cx, item_name(i));
5925 5926 5927
}


5928
fn collect_items(@crate_ctxt cx, @ast.crate crate) {
5929

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

5933 5934
    // 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.
5935 5936 5937 5938 5939 5940 5941 5942 5943 5944

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

5946
    fold.fold_crate[@crate_ctxt](cx, fld2, crate);
5947 5948
}

5949 5950 5951 5952
fn collect_tag_ctor(&@crate_ctxt cx, @ast.item i) -> @crate_ctxt {

    alt (i.node) {

5953
        case (ast.item_tag(_, ?variants, ?tps, _)) {
5954 5955
            for (ast.variant variant in variants) {
                if (_vec.len[ast.variant_arg](variant.args) != 0u) {
5956
                    decl_fn_and_pair(extend_path(cx, variant.name), "tag",
5957
                                     tps, variant.ann, variant.id);
5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978
                }
            }
        }

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


5979 5980 5981 5982 5983 5984
// 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;
5985 5986 5987
            auto n_variants = _vec.len[ast.variant](variants);
            while (i < n_variants) {
                auto variant = variants.(i);
5988 5989 5990 5991

                auto discrim_val = C_int(i as int);

                // FIXME: better name.
P
Patrick Walton 已提交
5992
                auto s = cx.names.next("_rust_tag_discrim");
5993
                auto discrim_gvar = llvm.LLVMAddGlobal(cx.llmod, T_int(),
P
Patrick Walton 已提交
5994
                                                       _str.buf(s));
5995 5996 5997 5998 5999 6000 6001 6002

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

6003
                cx.discrims.insert(variant.id, discrim_gvar);
P
Patrick Walton 已提交
6004
                cx.discrim_symbols.insert(variant.id, s);
6005 6006 6007 6008

                i += 1u;
            }
        }
6009 6010 6011 6012 6013 6014

        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);
6015 6016
            auto s = mangle_name_by_type(extend_path(cx, name),
                                         node_ann_type(cx, ann));
P
Patrick Walton 已提交
6017
            cx.item_symbols.insert(cid, s);
6018 6019
        }

6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036
        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);
}

6037 6038 6039 6040 6041 6042 6043 6044 6045 6046

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

6047 6048 6049 6050
fn p2i(ValueRef v) -> ValueRef {
    ret llvm.LLVMConstPtrToInt(v, T_int());
}

6051 6052 6053 6054
fn i2p(ValueRef v, TypeRef t) -> ValueRef {
    ret llvm.LLVMConstIntToPtr(v, t);
}

6055
fn trans_exit_task_glue(@glue_fns glues,
6056
                        &hashmap[str, ValueRef] externs,
6057
                        type_names tn, ModuleRef llmod) {
6058 6059 6060
    let vec[TypeRef] T_args = vec();
    let vec[ValueRef] V_args = vec();

6061
    auto llfn = glues.exit_task_glue;
6062
    let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 3u);
6063

6064 6065
    auto entrybb = llvm.LLVMAppendBasicBlock(llfn, _str.buf("entry"));
    auto build = new_builder(entrybb);
6066
    auto tptr = build.PtrToInt(lltaskptr, T_int());
6067
    auto V_args2 = vec(tptr) + V_args;
6068 6069
    trans_native(build, glues, lltaskptr,
                 externs, tn, llmod, "upcall_exit", true, V_args2);
6070
    build.RetVoid();
6071 6072
}

6073
fn create_typedefs(@crate_ctxt cx) {
6074 6075 6076
    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));
6077 6078
}

6079
fn create_crate_constant(ValueRef crate_ptr, @glue_fns glues) {
6080

6081
    let ValueRef crate_addr = p2i(crate_ptr);
6082 6083

    let ValueRef activate_glue_off =
6084
        llvm.LLVMConstSub(p2i(glues.activate_glue), crate_addr);
6085 6086

    let ValueRef yield_glue_off =
6087
        llvm.LLVMConstSub(p2i(glues.yield_glue), crate_addr);
6088

6089
    let ValueRef exit_task_glue_off =
6090
        llvm.LLVMConstSub(p2i(glues.exit_task_glue), crate_addr);
6091 6092 6093

    let ValueRef crate_val =
        C_struct(vec(C_null(T_int()),     // ptrdiff_t image_base_off
6094
                     p2i(crate_ptr),   // uintptr_t self_addr
6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105
                     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
6106 6107
                     C_null(T_int()),     // int n_libs
                     C_int(abi.abi_x86_rustc_fastcall) // uintptr_t abi_tag
6108 6109
                     ));

6110
    llvm.LLVMSetInitializer(crate_ptr, crate_val);
6111 6112
}

6113 6114 6115 6116
fn find_main_fn(@crate_ctxt cx) -> ValueRef {
    auto e = sep() + "main";
    let ValueRef v = C_nil();
    let uint n = 0u;
6117 6118
    for each (@tup(ast.def_id, str) i in cx.item_symbols.items()) {
        if (_str.ends_with(i._1, e)) {
6119
            n += 1u;
6120
            v = cx.item_ids.get(i._0);
6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136
        }
    }
    alt (n) {
        case (0u) {
            cx.sess.err("main fn not found");
        }
        case (1u) {
            ret v;
        }
        case (_) {
            cx.sess.err("multiple main fns found");
        }
    }
    fail;
}

6137
fn trans_main_fn(@crate_ctxt cx, ValueRef llcrate) {
6138 6139 6140
    auto T_main_args = vec(T_int(), T_int());
    auto T_rust_start_args = vec(T_int(), T_int(), T_int(), T_int());

6141 6142 6143 6144 6145 6146 6147
    auto main_name;
    if (_str.eq(std.os.target_os(), "win32")) {
        main_name = "WinMain@16";
    } else {
        main_name = "main";
    }

6148
    auto llmain =
6149
        decl_cdecl_fn(cx.llmod, main_name, T_fn(T_main_args, T_int()));
6150

6151 6152
    auto llrust_start = decl_cdecl_fn(cx.llmod, "rust_start",
                                      T_fn(T_rust_start_args, T_int()));
6153 6154 6155

    auto llargc = llvm.LLVMGetParam(llmain, 0u);
    auto llargv = llvm.LLVMGetParam(llmain, 1u);
6156
    auto llrust_main = find_main_fn(cx);
6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167

    //
    // 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(""));
6168
    auto b = new_builder(llbb);
6169 6170 6171 6172 6173 6174

    auto start_args = vec(p2i(llrust_main), p2i(llcrate), llargc, llargv);

    b.Ret(b.Call(llrust_start, start_args));
}

6175 6176
fn declare_intrinsics(ModuleRef llmod) -> hashmap[str,ValueRef] {

6177
    let vec[TypeRef] T_trap_args = vec();
6178 6179 6180 6181 6182 6183
    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;
6184 6185
}

6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203

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

6204 6205 6206 6207 6208 6209 6210 6211
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.
}

6212
fn decl_no_op_type_glue(ModuleRef llmod, type_names tn) -> ValueRef {
6213
    auto ty = T_fn(vec(T_taskptr(tn), T_ptr(T_i8())), T_void());
6214 6215 6216 6217
    ret decl_fastcall_fn(llmod, abi.no_op_type_glue_name(), ty);
}

fn make_no_op_type_glue(ValueRef fun) {
6218 6219
    auto bb_name = _str.buf("_rust_no_op_type_glue_bb");
    auto llbb = llvm.LLVMAppendBasicBlock(fun, bb_name);
6220
    new_builder(llbb).RetVoid();
6221 6222
}

6223
fn decl_memcpy_glue(ModuleRef llmod) -> ValueRef {
6224 6225 6226
    auto p8 = T_ptr(T_i8());

    auto ty = T_fn(vec(p8, p8, T_int()), T_void());
6227 6228
    ret decl_fastcall_fn(llmod, abi.memcpy_glue_name(), ty);
}
6229

6230 6231 6232 6233
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.
6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266
    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();
}

6267
fn decl_bzero_glue(ModuleRef llmod) -> ValueRef {
6268 6269 6270
    auto p8 = T_ptr(T_i8());

    auto ty = T_fn(vec(p8, T_int()), T_void());
6271 6272
    ret decl_fastcall_fn(llmod, abi.bzero_glue_name(), ty);
}
6273

6274
fn make_bzero_glue(ValueRef fun) -> ValueRef {
6275
    // We're not using the LLVM memset intrinsic. Same as with memcpy.
6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307
    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;
}

6308
fn make_vec_append_glue(ModuleRef llmod, type_names tn) -> ValueRef {
6309
    /*
6310
     * Args to vec_append_glue:
6311 6312 6313 6314 6315 6316 6317 6318 6319 6320
     *
     *   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.
     *
6321
     *   3. Dst vec ptr (i.e. ptr to ptr to rust_vec).
6322 6323
     *
     *   4. Src vec (i.e. ptr to rust_vec).
6324
     *
6325
     *   5. Flag indicating whether to skip trailing null on dst.
6326 6327 6328 6329 6330 6331
     *
     */

    auto ty = T_fn(vec(T_taskptr(tn),
                       T_ptr(T_tydesc(tn)),
                       T_ptr(T_tydesc(tn)),
6332 6333 6334
                       T_ptr(T_opaque_vec_ptr()),
                       T_opaque_vec_ptr(), T_bool()),
                   T_void());
6335

6336
    auto llfn = decl_fastcall_fn(llmod, abi.vec_append_glue_name(), ty);
6337 6338 6339
    ret llfn;
}

6340 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 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378

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

6379
fn trans_vec_append_glue(@crate_ctxt cx) {
6380

6381
    auto llfn = cx.glues.vec_append_glue;
6382 6383 6384 6385

    let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 0u);
    let ValueRef llvec_tydesc = llvm.LLVMGetParam(llfn, 1u);
    let ValueRef llelt_tydesc = llvm.LLVMGetParam(llfn, 2u);
6386 6387 6388
    let ValueRef lldst_vec_ptr = llvm.LLVMGetParam(llfn, 3u);
    let ValueRef llsrc_vec = llvm.LLVMGetParam(llfn, 4u);
    let ValueRef llskipnull = llvm.LLVMGetParam(llfn, 5u);
6389 6390 6391 6392 6393 6394 6395 6396 6397 6398

    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](),
6399
                    llupvars=new_def_hash[ValueRef](),
6400 6401 6402 6403 6404
                    lltydescs=new_def_hash[ValueRef](),
                    ccx=cx);

    auto bcx = new_top_block_ctxt(fcx);

6405 6406
    auto lldst_vec = bcx.build.Load(lldst_vec_ptr);

6407 6408
    // 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.
6409

6410
    auto llcopy_dst_ptr = bcx.build.Alloca(T_int());
6411 6412
    auto llnew_vec_res =
        trans_upcall(bcx, "upcall_vec_grow",
6413 6414 6415
                     vec(vp2i(bcx, lldst_vec),
                         vec_fill_adjusted(bcx, llsrc_vec, llskipnull),
                         vp2i(bcx, llcopy_dst_ptr),
6416 6417 6418
                         vp2i(bcx, llvec_tydesc)));

    bcx = llnew_vec_res.bcx;
6419 6420
    auto llnew_vec = vi2p(bcx, llnew_vec_res.val,
                          T_opaque_vec_ptr());
6421

6422
    put_vec_fill(bcx, llnew_vec, C_int(0));
6423

6424 6425
    auto copy_dst_cx = new_sub_block_ctxt(bcx, "copy new <- dst");
    auto copy_src_cx = new_sub_block_ctxt(bcx, "copy new <- src");
6426

6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450
    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,
6451 6452 6453
                    @block_ctxt cx,
                    ValueRef dst, ValueRef src) -> result {
            call_tydesc_glue_full(cx, src,
6454 6455
                                  elt_tydesc,
                                  abi.tydesc_field_take_glue_off);
6456
            ret res(cx, src);
6457 6458
        }

6459
        auto bcx = iter_sequence_raw(cx, dst, src, src_lim,
6460
                                     elt_llsz, bind take_one(elt_tydesc,
6461
                                                             _, _, _)).bcx;
6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474

        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);
6475
    copy_dst_cx.build.Store(vec_p1(copy_dst_cx, llnew_vec), pp0);
6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494
    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();
6495 6496 6497
}


6498 6499 6500
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()),
6501 6502
             /*
              * Note: the signature passed to decl_cdecl_fn here looks unusual
6503
              * because it is. It corresponds neither to a native signature
6504 6505 6506 6507 6508 6509 6510 6511
              * 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(),
6512 6513 6514 6515
                                            T_fn(vec(T_int(),
                                                     T_int(),
                                                     T_int(),
                                                     T_taskptr(tn)),
6516
                                                 T_void())),
6517

6518 6519
             native_glues_rust =
             _vec.init_fn[ValueRef](bind decl_native_glue(llmod, tn, true,
6520
                                                          _),
6521 6522 6523
                                    abi.n_native_glues + 1 as uint),
             native_glues_cdecl =
             _vec.init_fn[ValueRef](bind decl_native_glue(llmod, tn, false,
6524
                                                          _),
6525
                                    abi.n_native_glues + 1 as uint),
6526 6527 6528
             no_op_type_glue = decl_no_op_type_glue(llmod, tn),
             memcpy_glue = decl_memcpy_glue(llmod),
             bzero_glue = decl_bzero_glue(llmod),
6529
             vec_append_glue = make_vec_append_glue(llmod, tn));
6530 6531
}

6532 6533 6534 6535
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.
6536 6537 6538 6539
    auto llmod =
        llvm.LLVMModuleCreateWithNameInContext(_str.buf("rust_out"),
                                               llvm.LLVMGetGlobalContext());

6540 6541
    llvm.LLVMSetDataLayout(llmod, _str.buf(x86.get_data_layout()));
    llvm.LLVMSetTarget(llmod, _str.buf(x86.get_target_triple()));
6542
    auto td = mk_target_data(x86.get_data_layout());
6543
    auto tn = mk_type_names();
6544
    let ValueRef crate_ptr =
6545
        llvm.LLVMAddGlobal(llmod, T_crate(tn), _str.buf("rust_crate"));
6546

6547 6548
    auto intrinsics = declare_intrinsics(llmod);

6549
    llvm.LLVMSetModuleInlineAsm(llmod, _str.buf(x86.get_module_asm()));
6550

6551 6552 6553
    auto glues = make_glues(llmod, tn);
    create_crate_constant(crate_ptr, glues);
    make_memcpy_glue(glues.memcpy_glue);
6554
    make_bzero_glue(glues.bzero_glue);
6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576

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

6577
    auto intrinsics = declare_intrinsics(llmod);
6578

6579
    auto glues = make_glues(llmod, tn);
6580 6581
    auto hasher = ty.hash_ty;
    auto eqer = ty.eq_ty;
6582
    auto tag_sizes = map.mk_hashmap[@ty.t,uint](hasher, eqer);
6583
    auto tydescs = map.mk_hashmap[@ty.t,@tydesc_info](hasher, eqer);
6584
    let vec[ast.ty_param] obj_typarams = vec();
6585
    let vec[ast.obj_field] obj_fields = vec();
6586

6587
    let vec[str] pth = vec();
6588 6589
    auto cx = @rec(sess = sess,
                   llmod = llmod,
6590
                   td = td,
6591
                   tn = tn,
6592
                   crate_ptr = crate_ptr,
6593
                   externs = new_str_hash[ValueRef](),
6594
                   intrinsics = intrinsics,
6595
                   item_ids = new_def_hash[ValueRef](),
6596
                   items = new_def_hash[@ast.item](),
6597
                   native_items = new_def_hash[@ast.native_item](),
P
Patrick Walton 已提交
6598
                   item_symbols = new_def_hash[str](),
6599
                   tag_sizes = tag_sizes,
6600
                   discrims = new_def_hash[ValueRef](),
P
Patrick Walton 已提交
6601
                   discrim_symbols = new_def_hash[str](),
6602
                   fn_pairs = new_def_hash[ValueRef](),
6603
                   consts = new_def_hash[ValueRef](),
6604
                   obj_methods = new_def_hash[()](),
6605
                   tydescs = tydescs,
6606
                   obj_typarams = obj_typarams,
6607
                   obj_fields = obj_fields,
6608
                   glues = glues,
6609
                   names = namegen(0),
6610 6611
                   path = pth,
                   sha = std.sha1.mk_sha1());
6612

6613 6614
    create_typedefs(cx);

6615
    collect_items(cx, crate);
6616
    collect_tag_ctors(cx, crate);
6617
    trans_constants(cx, crate);
6618
    trans_mod(cx, crate.node.module);
6619
    trans_vec_append_glue(cx);
6620
    if (!shared) {
6621
        trans_main_fn(cx, cx.crate_ptr);
6622
    }
6623

6624 6625 6626
    // Translate the metadata.
    middle.metadata.write_metadata(cx, crate);

6627 6628
    check_module(llmod);

6629
    llvm.LLVMWriteBitcodeToFile(llmod, _str.buf(output));
6630 6631 6632 6633 6634 6635 6636 6637 6638 6639
    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
6640
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
6641 6642
// End:
//