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

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

18
import middle.ty.pat_ty;
P
Patrick Walton 已提交
19

20
import util.common;
21
import util.common.append;
22
import util.common.istr;
23
import util.common.new_def_hash;
24
import util.common.new_str_hash;
25 26 27

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

40 41
import lib.llvm.False;
import lib.llvm.True;
42

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

50 51
type glue_fns = rec(ValueRef activate_glue,
                    ValueRef yield_glue,
52
                    ValueRef exit_task_glue,
53 54
                    vec[ValueRef] upcall_glues,
                    ValueRef no_op_type_glue);
55

56
tag arity { nullary; n_ary; }
57
type tag_info = rec(type_handle th,
58 59
                    mutable vec[tup(ast.def_id,arity)] variants,
                    mutable uint size);
60

61
state type crate_ctxt = rec(session.session sess,
62
                            ModuleRef llmod,
63
                            target_data td,
64
                            hashmap[str, ValueRef] upcalls,
65
                            hashmap[str, ValueRef] intrinsics,
66 67
                            hashmap[str, ValueRef] item_names,
                            hashmap[ast.def_id, ValueRef] item_ids,
68
                            hashmap[ast.def_id, @ast.item] items,
69
                            hashmap[ast.def_id, @tag_info] tags,
70 71
                            hashmap[ast.def_id, ValueRef] fn_pairs,
                            hashmap[ast.def_id,()] obj_methods,
72
                            hashmap[@ty.t, ValueRef] tydescs,
73
                            vec[ast.obj_field] obj_fields,
74 75 76
                            @glue_fns glues,
                            namegen names,
                            str path);
77

78 79
state type fn_ctxt = rec(ValueRef llfn,
                         ValueRef lltaskptr,
80
                         ValueRef llclosure,
81
                         mutable option.t[ValueRef] llself,
82
                         mutable option.t[ValueRef] llretptr,
83
                         hashmap[ast.def_id, ValueRef] llargs,
84
                         hashmap[ast.def_id, ValueRef] llobjfields,
85
                         hashmap[ast.def_id, ValueRef] lllocals,
86
                         hashmap[ast.def_id, ValueRef] lltydescs,
87
                         @crate_ctxt ccx);
88

89
tag cleanup {
90
    clean(fn(@block_ctxt cx) -> result);
91 92 93 94
}

state type block_ctxt = rec(BasicBlockRef llbb,
                            builder build,
95
                            block_parent parent,
96
                            bool is_scope,
97 98 99
                            mutable vec[cleanup] cleanups,
                            @fn_ctxt fcx);

100 101 102 103 104 105 106 107
// 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);
}

108

109 110 111 112 113 114 115 116
state type result = rec(mutable @block_ctxt bcx,
                        mutable ValueRef val);

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

117 118 119 120 121 122 123 124 125 126 127
fn ty_str(TypeRef t) -> str {
    ret lib.llvm.type_to_str(t);
}

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

fn val_str(ValueRef v) -> str {
    ret ty_str(val_ty(v));
}
128 129 130 131


// LLVM type constructors.

132 133 134 135 136 137 138 139 140 141 142
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.
143 144 145
    ret llvm.LLVMVoidType();
}

146 147 148 149 150
fn T_nil() -> TypeRef {
    // NB: See above in T_void().
    ret llvm.LLVMInt1Type();
}

151 152 153 154
fn T_i1() -> TypeRef {
    ret llvm.LLVMInt1Type();
}

155 156 157 158 159 160 161 162 163
fn T_i8() -> TypeRef {
    ret llvm.LLVMInt8Type();
}

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

fn T_i32() -> TypeRef {
164 165 166
    ret llvm.LLVMInt32Type();
}

167 168 169 170
fn T_i64() -> TypeRef {
    ret llvm.LLVMInt64Type();
}

171 172 173 174 175 176 177 178
fn T_f32() -> TypeRef {
    ret llvm.LLVMFloatType();
}

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

179 180 181 182
fn T_bool() -> TypeRef {
    ret T_i1();
}

183 184 185 186 187
fn T_int() -> TypeRef {
    // FIXME: switch on target type.
    ret T_i32();
}

188 189 190 191
fn T_char() -> TypeRef {
    ret T_i32();
}

192 193 194 195
fn T_fn(vec[TypeRef] inputs, TypeRef output) -> TypeRef {
    ret llvm.LLVMFunctionType(output,
                              _vec.buf[TypeRef](inputs),
                              _vec.len[TypeRef](inputs),
196 197 198
                              False);
}

199
fn T_fn_pair(TypeRef tfn) -> TypeRef {
200
    ret T_struct(vec(T_ptr(tfn),
201
                     T_opaque_closure_ptr()));
202 203
}

204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
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();
}

fn T_task() -> TypeRef {
    ret T_struct(vec(T_int(),      // Refcount
220 221 222 223 224 225 226 227 228 229
                     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
                     ));
}

230 231 232 233 234 235
fn T_tydesc() -> TypeRef {
    auto pvoid = T_ptr(T_i8());
    auto glue_fn_ty = T_ptr(T_fn(vec(T_taskptr(), pvoid), T_void()));
    ret T_struct(vec(pvoid,             // first_param
                     T_int(),           // size
                     T_int(),           // align
236
                     glue_fn_ty,        // take_glue_off
237 238 239 240 241 242 243 244
                     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
}

245 246 247 248
fn T_array(TypeRef t, uint n) -> TypeRef {
    ret llvm.LLVMArrayType(t, n);
}

249 250 251 252 253
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
254 255 256
                     ));
}

257 258
fn T_str() -> TypeRef {
    ret T_vec(T_i8());
259 260
}

261 262 263 264
fn T_box(TypeRef t) -> TypeRef {
    ret T_struct(vec(T_int(), t));
}

265 266 267 268 269 270 271 272 273 274 275 276 277 278
fn T_crate() -> TypeRef {
    ret 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
279
                     T_int()       // int n_libs
280 281 282
                     ));
}

283 284 285 286 287 288
fn T_double() -> TypeRef {
    ret llvm.LLVMDoubleType();
}

fn T_taskptr() -> TypeRef {
    ret T_ptr(T_task());
289 290
}

291 292 293 294
fn T_typaram_ptr() -> TypeRef {
    ret T_ptr(T_i8());
}

295 296 297 298 299 300 301 302 303 304
fn T_closure_ptr(TypeRef lltarget_ty,
                 TypeRef llbindings_ty) -> TypeRef {
    ret T_ptr(T_box(T_struct(vec(T_ptr(T_tydesc()),
                                 lltarget_ty,
                                 llbindings_ty)
                             // FIXME: add captured typarams.
                             )));
}

fn T_opaque_closure_ptr() -> TypeRef {
305 306 307
    ret T_closure_ptr(T_struct(vec(T_ptr(T_nil()),
                                   T_ptr(T_nil()))),
                      T_nil());
308 309 310
}


311
fn type_of(@crate_ctxt cx, @ty.t t) -> TypeRef {
312 313
    let TypeRef llty = type_of_inner(cx, t);
    check (llty as int != 0);
314
    llvm.LLVMAddTypeName(cx.llmod, _str.buf(ty.ty_to_str(t)), llty);
315 316 317
    ret llty;
}

318
// NB: this must match trans_args and create_llargs_for_fn_args.
319 320 321 322
fn type_of_fn_full(@crate_ctxt cx,
                   option.t[TypeRef] obj_self,
                   vec[ty.arg] inputs,
                   @ty.t output) -> TypeRef {
323
    let vec[TypeRef] atys = vec(T_taskptr());
324

325 326
    auto fn_ty = ty.plain_ty(ty.ty_fn(inputs, output));
    auto ty_param_count = ty.count_ty_params(fn_ty);
327 328
    auto i = 0u;
    while (i < ty_param_count) {
329
        atys += T_ptr(T_tydesc());
330 331 332
        i += 1u;
    }

333 334 335 336
    if (ty.type_has_dynamic_size(output)) {
        atys += T_typaram_ptr();
    }

337 338 339 340 341
    alt (obj_self) {
        case (some[TypeRef](?t)) {
            check (t as int != 0);
            atys += t;
        }
342 343 344
        case (_) {
            atys += T_opaque_closure_ptr();
        }
345 346
    }

347
    for (ty.arg arg in inputs) {
348 349 350 351 352 353 354 355 356 357
        if (ty.type_has_dynamic_size(arg.ty)) {
            check (arg.mode == ast.alias);
            atys += T_typaram_ptr();
        } else {
            let TypeRef t = type_of(cx, arg.ty);
            alt (arg.mode) {
                case (ast.alias) {
                    t = T_ptr(t);
                }
                case (_) { /* fall through */  }
358
            }
359
            atys += t;
360 361 362 363
        }
    }

    auto ret_ty;
364
    if (ty.type_is_nil(output) || ty.type_has_dynamic_size(output)) {
365 366 367 368 369 370 371 372
        ret_ty = llvm.LLVMVoidType();
    } else {
        ret_ty = type_of(cx, output);
    }

    ret T_fn(atys, ret_ty);
}

373 374 375 376
fn type_of_fn(@crate_ctxt cx, vec[ty.arg] inputs, @ty.t output) -> TypeRef {
    ret type_of_fn_full(cx, none[TypeRef], inputs, output);
}

377
fn type_of_inner(@crate_ctxt cx, @ty.t t) -> TypeRef {
378
    alt (t.struct) {
379 380 381 382 383
        case (ty.ty_nil) { ret T_nil(); }
        case (ty.ty_bool) { ret T_bool(); }
        case (ty.ty_int) { ret T_int(); }
        case (ty.ty_uint) { ret T_int(); }
        case (ty.ty_machine(?tm)) {
384 385 386 387 388 389 390 391 392 393 394 395 396
            alt (tm) {
                case (common.ty_i8) { ret T_i8(); }
                case (common.ty_u8) { ret T_i8(); }
                case (common.ty_i16) { ret T_i16(); }
                case (common.ty_u16) { ret T_i16(); }
                case (common.ty_i32) { ret T_i32(); }
                case (common.ty_u32) { ret T_i32(); }
                case (common.ty_i64) { ret T_i64(); }
                case (common.ty_u64) { ret T_i64(); }
                case (common.ty_f32) { ret T_f32(); }
                case (common.ty_f64) { ret T_f64(); }
            }
        }
397 398 399
        case (ty.ty_char) { ret T_char(); }
        case (ty.ty_str) { ret T_ptr(T_str()); }
        case (ty.ty_tag(?tag_id)) {
400 401
            ret llvm.LLVMResolveTypeHandle(cx.tags.get(tag_id).th.llth);
        }
402
        case (ty.ty_box(?t)) {
403 404
            ret T_ptr(T_box(type_of(cx, t)));
        }
405
        case (ty.ty_vec(?t)) {
406
            ret T_ptr(T_vec(type_of(cx, t)));
407
        }
408
        case (ty.ty_tup(?elts)) {
409
            let vec[TypeRef] tys = vec();
410
            for (@ty.t elt in elts) {
411
                tys += type_of(cx, elt);
412 413 414
            }
            ret T_struct(tys);
        }
415
        case (ty.ty_rec(?fields)) {
416
            let vec[TypeRef] tys = vec();
417
            for (ty.field f in fields) {
418 419 420 421
                tys += type_of(cx, f.ty);
            }
            ret T_struct(tys);
        }
422
        case (ty.ty_fn(?args, ?out)) {
423
            ret T_fn_pair(type_of_fn(cx, args, out));
424
        }
425
        case (ty.ty_obj(?meths)) {
426 427 428
            auto th = mk_type_handle();
            auto self_ty = llvm.LLVMResolveTypeHandle(th.llth);

429
            let vec[TypeRef] mtys = vec();
430
            for (ty.method m in meths) {
431 432 433 434
                let TypeRef mty =
                    type_of_fn_full(cx,
                                    some[TypeRef](self_ty),
                                    m.inputs, m.output);
435
                mtys += T_ptr(mty);
436
            }
437
            let TypeRef vtbl = T_struct(mtys);
438 439
            let TypeRef body = T_struct(vec(T_ptr(T_tydesc()),
                                            T_nil()));
440 441
            let TypeRef pair =
                T_struct(vec(T_ptr(vtbl),
442
                             T_ptr(T_box(body))));
443 444 445 446
            auto abs_pair = llvm.LLVMResolveTypeHandle(th.llth);
            llvm.LLVMRefineType(abs_pair, pair);
            abs_pair = llvm.LLVMResolveTypeHandle(th.llth);
            ret abs_pair;
447
        }
448
        case (ty.ty_var(_)) {
449
            log "ty_var in trans.type_of";
450 451
            fail;
        }
452
        case (ty.ty_param(_)) {
453
            ret T_typaram_ptr();
454 455 456 457 458
        }
    }
    fail;
}

459
fn type_of_arg(@crate_ctxt cx, &ty.arg arg) -> TypeRef {
460 461 462 463 464 465 466
    auto ty = type_of(cx, arg.ty);
    if (arg.mode == ast.alias) {
        ty = T_ptr(ty);
    }
    ret ty;
}

467 468 469 470 471 472 473 474 475
// 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 {
476 477 478 479 480 481 482 483 484 485 486 487 488 489
            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) &&
                            c != (' ' as u8) && c != ('\t' as u8) &&
                            c != (';' as u8)) {
                        auto v = vec(c);
                        result += _str.from_bytes(v);
                    }
                }
            }
490 491 492 493 494
        }
    }
    ret result;
}

495 496 497 498 499 500
// LLVM constant constructors.

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

501
fn C_integral(int i, TypeRef t) -> ValueRef {
502 503 504 505 506 507
    // 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);
    //
508 509 510
    ret llvm.LLVMConstIntOfString(t, _str.buf(istr(i)), 10);
}

511 512 513 514 515
fn C_nil() -> ValueRef {
    // NB: See comment above in T_void().
    ret C_integral(0, T_i1());
}

516 517
fn C_bool(bool b) -> ValueRef {
    if (b) {
518
        ret C_integral(1, T_bool());
519
    } else {
520
        ret C_integral(0, T_bool());
521 522 523
    }
}

524 525
fn C_int(int i) -> ValueRef {
    ret C_integral(i, T_int());
526 527
}

528
fn C_str(@crate_ctxt cx, str s) -> ValueRef {
529
    auto sc = llvm.LLVMConstString(_str.buf(s), _str.byte_len(s), False);
530
    auto g = llvm.LLVMAddGlobal(cx.llmod, val_ty(sc),
531 532
                                _str.buf(cx.names.next("str")));
    llvm.LLVMSetInitializer(g, sc);
533
    llvm.LLVMSetGlobalConstant(g, True);
534 535
    llvm.LLVMSetLinkage(g, lib.llvm.LLVMPrivateLinkage
                        as llvm.Linkage);
536
    ret g;
537 538
}

539 540 541 542 543 544 545 546 547 548 549
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));
}

550 551 552 553 554 555
fn C_struct(vec[ValueRef] elts) -> ValueRef {
    ret llvm.LLVMConstStruct(_vec.buf[ValueRef](elts),
                             _vec.len[ValueRef](elts),
                             False);
}

556
fn decl_fn(ModuleRef llmod, str name, uint cc, TypeRef llty) -> ValueRef {
557 558
    let ValueRef llfn =
        llvm.LLVMAddFunction(llmod, _str.buf(name), llty);
559
    llvm.LLVMSetFunctionCallConv(llfn, cc);
560 561 562
    ret llfn;
}

563 564
fn decl_cdecl_fn(ModuleRef llmod, str name, TypeRef llty) -> ValueRef {
    ret decl_fn(llmod, name, lib.llvm.LLVMCCallConv, llty);
565 566
}

567 568
fn decl_fastcall_fn(ModuleRef llmod, str name, TypeRef llty) -> ValueRef {
    ret decl_fn(llmod, name, lib.llvm.LLVMFastCallConv, llty);
569 570
}

571
fn decl_glue(ModuleRef llmod, str s) -> ValueRef {
572
    ret decl_cdecl_fn(llmod, s, T_fn(vec(T_taskptr()), T_void()));
573 574
}

575
fn decl_upcall(ModuleRef llmod, uint _n) -> ValueRef {
576 577 578 579
    // It doesn't actually matter what type we come up with here, at the
    // moment, as we cast the upcall function pointers to int before passing
    // them to the indirect upcall-invocation glue.  But eventually we'd like
    // to call them directly, once we have a calling convention worked out.
580
    let int n = _n as int;
581
    let str s = abi.upcall_glue_name(n);
582
    let vec[TypeRef] args =
583 584
        vec(T_taskptr(), // taskptr
            T_int())     // callee
585 586
        + _vec.init_elt[TypeRef](T_int(), n as uint);

587
    ret decl_fastcall_fn(llmod, s, T_fn(args, T_int()));
588 589
}

590
fn get_upcall(@crate_ctxt cx, str name, int n_args) -> ValueRef {
591 592 593
    if (cx.upcalls.contains_key(name)) {
        ret cx.upcalls.get(name);
    }
594
    auto inputs = vec(T_taskptr());
595
    inputs += _vec.init_elt[TypeRef](T_int(), n_args as uint);
596
    auto output = T_int();
597
    auto f = decl_cdecl_fn(cx.llmod, name, T_fn(inputs, output));
598 599 600 601
    cx.upcalls.insert(name, f);
    ret f;
}

602
fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args) -> result {
603
    let int n = _vec.len[ValueRef](args) as int;
604
    let ValueRef llupcall = get_upcall(cx.fcx.ccx, name, n);
605 606
    llupcall = llvm.LLVMConstPointerCast(llupcall, T_int());

607
    let ValueRef llglue = cx.fcx.ccx.glues.upcall_glues.(n);
608 609 610 611
    let vec[ValueRef] call_args = vec(cx.fcx.lltaskptr, llupcall);
    for (ValueRef a in args) {
        call_args += cx.build.ZExtOrBitCast(a, T_int());
    }
612
    ret res(cx, cx.build.FastCall(llglue, call_args));
613 614
}

615 616 617
fn trans_non_gc_free(@block_ctxt cx, ValueRef v) -> result {
    ret trans_upcall(cx, "upcall_free", vec(cx.build.PtrToInt(v, T_int()),
                                            C_int(0)));
618 619
}

620 621 622 623 624 625 626 627 628 629 630 631 632 633
fn find_scope_cx(@block_ctxt cx) -> @block_ctxt {
    if (cx.is_scope) {
        ret cx;
    }
    alt (cx.parent) {
        case (parent_some(?b)) {
            be find_scope_cx(b);
        }
        case (parent_none) {
            fail;
        }
    }
}

634 635 636 637 638 639 640 641
fn size_of(TypeRef t) -> ValueRef {
    ret llvm.LLVMConstIntCast(lib.llvm.llvm.LLVMSizeOf(t), T_int(), False);
}

fn align_of(TypeRef t) -> ValueRef {
    ret llvm.LLVMConstIntCast(lib.llvm.llvm.LLVMAlignOf(t), T_int(), False);
}

642 643
fn trans_malloc_inner(@block_ctxt cx, TypeRef llptr_ty) -> result {
    auto llbody_ty = lib.llvm.llvm.LLVMGetElementType(llptr_ty);
644 645
    // FIXME: need a table to collect tydesc globals.
    auto tydesc = C_int(0);
646
    auto sz = size_of(llbody_ty);
647
    auto sub = trans_upcall(cx, "upcall_malloc", vec(sz, tydesc));
648 649 650 651 652 653 654 655
    sub.val = sub.bcx.build.IntToPtr(sub.val, llptr_ty);
    ret sub;
}

fn trans_malloc(@block_ctxt cx, @ty.t t) -> result {
    auto scope_cx = find_scope_cx(cx);
    auto llptr_ty = type_of(cx.fcx.ccx, t);
    auto sub = trans_malloc_inner(cx, llptr_ty);
656
    scope_cx.cleanups += clean(bind drop_ty(_, sub.val, t));
657 658 659 660
    ret sub;
}


661 662 663 664 665
// 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.
666 667
fn field_of_tydesc(@block_ctxt cx, @ty.t t, int field) -> ValueRef {
    auto tydesc = get_tydesc(cx, t);
668 669
    ret cx.build.GEP(tydesc, vec(C_int(0), C_int(field)));
}
670

671
fn get_tydesc(&@block_ctxt cx, @ty.t t) -> ValueRef {
672
    // Is the supplied type a type param? If so, return the passed-in tydesc.
673
    alt (ty.type_param(t)) {
674 675
        case (some[ast.def_id](?id)) { ret cx.fcx.lltydescs.get(id); }
        case (none[ast.def_id])      { /* fall through */ }
676
    }
677 678

    // Does it contain a type param? If so, generate a derived tydesc.
679
    if (ty.count_ty_params(t) > 0u) {
680 681 682 683 684
        log "TODO: trans.get_tydesc(): generate a derived type descriptor";
        fail;
    }

    // Otherwise, generate a tydesc if necessary, and return it.
685 686
    if (!cx.fcx.ccx.tydescs.contains_key(t)) {
        make_tydesc(cx.fcx.ccx, t);
687
    }
688
    ret cx.fcx.ccx.tydescs.get(t);
689 690
}

691
fn make_tydesc(@crate_ctxt cx, @ty.t t) {
692
    auto tg = make_take_glue;
693
    auto take_glue = make_generic_glue(cx, t, "take", tg);
694
    auto dg = make_drop_glue;
695
    auto drop_glue = make_generic_glue(cx, t, "drop", dg);
696

697
    auto llty = type_of(cx, t);
698 699 700
    auto pvoid = T_ptr(T_i8());
    auto glue_fn_ty = T_ptr(T_fn(vec(T_taskptr(), pvoid), T_void()));
    auto tydesc = C_struct(vec(C_null(pvoid),
701 702
                               size_of(llty),
                               align_of(llty),
703
                               take_glue,             // take_glue_off
704 705 706 707 708 709 710
                               drop_glue,             // drop_glue_off
                               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

711
    auto name = sanitize(cx.names.next("tydesc_" + ty.ty_to_str(t)));
712 713 714
    auto gvar = llvm.LLVMAddGlobal(cx.llmod, val_ty(tydesc), _str.buf(name));
    llvm.LLVMSetInitializer(gvar, tydesc);
    llvm.LLVMSetGlobalConstant(gvar, True);
715 716
    llvm.LLVMSetLinkage(gvar, lib.llvm.LLVMPrivateLinkage
                        as llvm.Linkage);
717
    cx.tydescs.insert(t, gvar);
718 719
}

720
fn make_generic_glue(@crate_ctxt cx, @ty.t t, str name,
721
                     val_and_ty_fn helper) -> ValueRef {
722
    auto llfnty = T_fn(vec(T_taskptr(), T_ptr(T_i8())), T_void());
723

724
    auto fn_name = cx.names.next("_rust_" + name) + "." + ty.ty_to_str(t);
725 726 727 728 729 730
    fn_name = sanitize(fn_name);
    auto llfn = decl_fastcall_fn(cx.llmod, fn_name, llfnty);

    auto fcx = new_fn_ctxt(cx, fn_name, llfn);
    auto bcx = new_top_block_ctxt(fcx);

731
    auto re;
732
    if (!ty.type_is_scalar(t)) {
733
        auto llty;
734
        if (ty.type_is_structural(t)) {
735 736 737 738
            llty = T_ptr(type_of(cx, t));
        } else {
            llty = type_of(cx, t);
        }
739

740 741
        auto llrawptr = llvm.LLVMGetParam(llfn, 1u);
        auto llval = bcx.build.BitCast(llrawptr, llty);
G
Graydon Hoare 已提交
742

743 744 745 746
        re = helper(bcx, llval, t);
    } else {
        re = res(bcx, C_nil());
    }
747

748
    re.bcx.build.RetVoid();
749 750 751
    ret llfn;
}

752 753
fn make_take_glue(@block_ctxt cx, ValueRef v, @ty.t t) -> result {
    if (ty.type_is_boxed(t)) {
754 755
        ret incr_refcnt_of_boxed(cx, v);

756
    } else if (ty.type_is_structural(t)) {
757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781
        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());
}

782
fn make_drop_glue(@block_ctxt cx, ValueRef v, @ty.t t) -> result {
783
    alt (t.struct) {
784
        case (ty.ty_str) {
785 786 787 788 789 790
            ret decr_refcnt_and_if_zero(cx, v,
                                        bind trans_non_gc_free(_, v),
                                        "free string",
                                        T_int(), C_int(0));
        }

791 792
        case (ty.ty_vec(_)) {
            fn hit_zero(@block_ctxt cx, ValueRef v, @ty.t t) -> result {
793 794 795 796 797 798 799 800 801 802
                auto res = iter_sequence(cx, v, t, bind drop_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,
                                        bind hit_zero(_, v, t),
                                        "free vector",
                                        T_int(), C_int(0));
        }

803 804
        case (ty.ty_box(?body_ty)) {
            fn hit_zero(@block_ctxt cx, ValueRef v, @ty.t body_ty) -> result {
805 806 807 808
                auto body = cx.build.GEP(v,
                                         vec(C_int(0),
                                             C_int(abi.box_rc_field_body)));

809
                auto body_val = load_scalar_or_boxed(cx, body, body_ty);
810 811 812 813 814 815 816 817 818 819
                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,
                                        bind hit_zero(_, v, body_ty),
                                        "free box",
                                        T_int(), C_int(0));
        }

820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863
        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 fields =
                    cx.build.GEP(body,
                                 vec(C_int(0),
                                     C_int(abi.obj_body_elt_fields)));
                auto llrawptr = cx.build.BitCast(fields, T_ptr(T_i8()));

                auto tydescptr =
                    cx.build.GEP(body,
                                 vec(C_int(0),
                                     C_int(abi.obj_body_elt_tydesc)));
                auto tydesc = cx.build.Load(tydescptr);
                auto llfnptr =
                    cx.build.GEP(tydesc,
                                 vec(C_int(0),
                                     C_int(abi.tydesc_field_drop_glue_off)));
                auto llfn = cx.build.Load(llfnptr);
                cx.build.FastCall(llfn, vec(cx.fcx.lltaskptr, llrawptr));

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

864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907
        case (ty.ty_fn(_,_)) {
            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)));

                auto bindings =
                    cx.build.GEP(body,
                                 vec(C_int(0),
                                     C_int(abi.closure_elt_bindings)));
                auto llrawptr = cx.build.BitCast(bindings, T_ptr(T_i8()));

                auto tydescptr =
                    cx.build.GEP(body,
                                 vec(C_int(0),
                                     C_int(abi.closure_elt_tydesc)));
                auto tydesc = cx.build.Load(tydescptr);
                auto llfnptr =
                    cx.build.GEP(tydesc,
                                 vec(C_int(0),
                                     C_int(abi.tydesc_field_drop_glue_off)));
                auto llfn = cx.build.Load(llfnptr);
                cx.build.FastCall(llfn, vec(cx.fcx.lltaskptr, llrawptr));

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

908
        case (_) {
909
            if (ty.type_is_structural(t)) {
910 911 912
                ret iter_structural_ty(cx, v, t,
                                       bind drop_ty(_, _, _));

913 914
            } else if (ty.type_is_scalar(t) ||
                       ty.type_is_nil(t)) {
915 916 917 918
                ret res(cx, C_nil());
            }
        }
    }
919
    cx.fcx.ccx.sess.bug("bad type in trans.make_drop_glue_inner: " +
920
                        ty.ty_to_str(t));
921 922 923
    fail;
}

924 925
fn decr_refcnt_and_if_zero(@block_ctxt cx,
                           ValueRef box_ptr,
926
                           fn(@block_ctxt cx) -> result inner,
927
                           str inner_name,
928
                           TypeRef t_else, ValueRef v_else) -> result {
929

930
    auto load_rc_cx = new_sub_block_ctxt(cx, "load rc");
931 932 933 934
    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");

935 936
    auto null_test = cx.build.IsNull(box_ptr);
    cx.build.CondBr(null_test, next_cx.llbb, load_rc_cx.llbb);
937

938 939 940 941 942 943 944 945 946 947

    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);
948 949 950 951

    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);
952 953 954 955
    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);
956

957
    auto phi = next_cx.build.Phi(t_else,
958
                                 vec(v_else, v_else, v_else, inner_res.val),
959
                                 vec(cx.llbb,
960
                                     load_rc_cx.llbb,
961
                                     rc_adj_cx.llbb,
962 963
                                     inner_res.bcx.llbb));

964
    ret res(next_cx, phi);
965 966
}

967 968
fn type_of_variant(@crate_ctxt cx, &ast.variant v) -> TypeRef {
    let vec[TypeRef] lltys = vec();
969 970 971
    alt (ty.ann_to_type(v.ann).struct) {
        case (ty.ty_fn(?args, _)) {
            for (ty.arg arg in args) {
972 973 974 975 976 977 978 979
                lltys += vec(type_of(cx, arg.ty));
            }
        }
        case (_) { fail; }
    }
    ret T_struct(lltys);
}

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

982
// Iterates through the elements of a structural type.
983 984
fn iter_structural_ty(@block_ctxt cx,
                      ValueRef v,
985
                      @ty.t t,
986 987 988
                      val_and_ty_fn f)
    -> result {
    let result r = res(cx, C_nil());
989

990 991 992 993
    fn iter_boxpp(@block_ctxt cx,
                  ValueRef box_cell,
                  val_and_ty_fn f) -> result {
        auto box_ptr = cx.build.Load(box_cell);
994 995
        auto tnil = ty.plain_ty(ty.ty_nil);
        auto tbox = ty.plain_ty(ty.ty_box(tnil));
996 997 998 999 1000 1001 1002 1003 1004 1005 1006

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

        auto r = f(inner_cx, box_ptr, tbox);
        r.bcx.build.Br(next_cx.llbb);
        ret res(next_cx, r.val);
    }

1007
    alt (t.struct) {
1008
        case (ty.ty_tup(?args)) {
1009
            let int i = 0;
1010
            for (@ty.t arg in args) {
1011
                auto elt = r.bcx.build.GEP(v, vec(C_int(0), C_int(i)));
1012
                r = f(r.bcx,
1013
                      load_scalar_or_boxed(r.bcx, elt, arg),
1014
                      arg);
1015 1016 1017
                i += 1;
            }
        }
1018
        case (ty.ty_rec(?fields)) {
1019
            let int i = 0;
1020
            for (ty.field fld in fields) {
1021
                auto llfld = r.bcx.build.GEP(v, vec(C_int(0), C_int(i)));
1022
                r = f(r.bcx,
1023
                      load_scalar_or_boxed(r.bcx, llfld, fld.ty),
1024
                      fld.ty);
1025 1026 1027
                i += 1;
            }
        }
1028
        case (ty.ty_tag(?tid)) {
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
            check (cx.fcx.ccx.tags.contains_key(tid));
            auto info = cx.fcx.ccx.tags.get(tid);
            auto n_variants = _vec.len[tup(ast.def_id,arity)](info.variants);

            // Look up the tag in the typechecked AST.
            check (cx.fcx.ccx.items.contains_key(tid));
            auto tag_item = cx.fcx.ccx.items.get(tid);
            let vec[ast.variant] variants = vec();  // FIXME: typestate bug
            alt (tag_item.node) {
                case (ast.item_tag(_, ?vs, _, _)) {
                    variants = vs;
                }
                case (_) {
                    log "trans: ty_tag doesn't actually refer to a tag";
                    fail;
                }
            }

            auto lldiscrim_ptr = cx.build.GEP(v, vec(C_int(0), C_int(0)));
            auto llunion_ptr = cx.build.GEP(v, vec(C_int(0), C_int(1)));
            auto lldiscrim = cx.build.Load(lldiscrim_ptr);
G
Graydon Hoare 已提交
1050

1051 1052 1053 1054 1055
            auto unr_cx = new_sub_block_ctxt(cx, "tag-iter-unr");
            unr_cx.build.Unreachable();

            auto llswitch = cx.build.Switch(lldiscrim, unr_cx.llbb,
                                            n_variants);
G
Graydon Hoare 已提交
1056

1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
            auto next_cx = new_sub_block_ctxt(cx, "tag-iter-next");

            auto i = 0u;
            for (tup(ast.def_id,arity) variant in info.variants) {
                auto variant_cx = new_sub_block_ctxt(cx, "tag-iter-variant-" +
                                                     _uint.to_str(i, 10u));
                llvm.LLVMAddCase(llswitch, C_int(i as int), variant_cx.llbb);

                alt (variant._1) {
                    case (n_ary) {
                        let vec[ValueRef] vals = vec(C_int(0), C_int(1),
                                                     C_int(i as int));
1069
                        auto llvar = variant_cx.build.GEP(v, vals);
1070 1071
                        auto llvarty = type_of_variant(cx.fcx.ccx,
                                                       variants.(i));
1072

1073
                        auto fn_ty = ty.ann_to_type(variants.(i).ann);
1074
                        alt (fn_ty.struct) {
1075
                            case (ty.ty_fn(?args, _)) {
1076 1077 1078 1079
                                auto llvarp = variant_cx.build.
                                    TruncOrBitCast(llunion_ptr,
                                                   T_ptr(llvarty));

1080
                                auto j = 0u;
1081
                                for (ty.arg a in args) {
1082 1083
                                    auto llfldp = variant_cx.build.GEP(llvarp,
                                        vec(C_int(0), C_int(j as int)));
1084
                                    auto llfld =
1085
                                        load_scalar_or_boxed(variant_cx,
1086
                                                            llfldp, a.ty);
1087

1088 1089 1090 1091 1092 1093 1094 1095 1096
                                    auto res = f(variant_cx, llfld, a.ty);
                                    variant_cx = res.bcx;
                                    j += 1u;
                                }
                            }
                            case (_) { fail; }
                        }

                        variant_cx.build.Br(next_cx.llbb);
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
                    }
                    case (nullary) {
                        // Nothing to do.
                        variant_cx.build.Br(next_cx.llbb);
                    }
                }

                i += 1u;
            }

            ret res(next_cx, C_nil());
        }
1109
        case (ty.ty_fn(_,_)) {
1110 1111 1112 1113
            auto box_cell =
                cx.build.GEP(v,
                             vec(C_int(0),
                                 C_int(abi.fn_field_box)));
1114
            ret iter_boxpp(cx, box_cell, f);
1115
        }
1116
        case (ty.ty_obj(_)) {
1117 1118 1119 1120
            auto box_cell =
                cx.build.GEP(v,
                             vec(C_int(0),
                                 C_int(abi.obj_field_box)));
1121
            ret iter_boxpp(cx, box_cell, f);
1122
        }
1123 1124 1125
        case (_) {
            cx.fcx.ccx.sess.unimpl("type in iter_structural_ty");
        }
1126
    }
1127
    ret r;
1128 1129
}

1130 1131 1132
// Iterates through the elements of a vec or str.
fn iter_sequence(@block_ctxt cx,
                 ValueRef v,
1133
                 @ty.t t,
1134 1135 1136 1137
                 val_and_ty_fn f) -> result {

    fn iter_sequence_body(@block_ctxt cx,
                          ValueRef v,
1138
                          @ty.t elt_ty,
1139 1140 1141 1142 1143 1144 1145
                          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)));
1146 1147

        auto llunit_ty = type_of(cx.fcx.ccx, elt_ty);
1148
        auto unit_sz = size_of(llunit_ty);
1149

1150 1151
        auto len = cx.build.Load(lenptr);
        if (trailing_null) {
1152
            len = cx.build.Sub(len, unit_sz);
1153 1154 1155 1156
        }

        auto r = res(cx, C_nil());

1157 1158
        auto cond_cx = new_scope_block_ctxt(cx, "sequence-iter cond");
        auto body_cx = new_scope_block_ctxt(cx, "sequence-iter body");
1159 1160
        auto next_cx = new_sub_block_ctxt(cx, "next");

1161 1162
        cx.build.Br(cond_cx.llbb);

1163
        auto ix = cond_cx.build.Phi(T_int(), vec(C_int(0)), vec(cx.llbb));
1164 1165 1166 1167 1168
        auto scaled_ix = cond_cx.build.Phi(T_int(),
                                           vec(C_int(0)), vec(cx.llbb));

        auto end_test = cond_cx.build.ICmp(lib.llvm.LLVMIntNE,
                                           scaled_ix, len);
1169 1170
        cond_cx.build.CondBr(end_test, body_cx.llbb, next_cx.llbb);

1171
        auto elt = body_cx.build.GEP(p0, vec(C_int(0), ix));
1172
        auto body_res = f(body_cx,
1173
                          load_scalar_or_boxed(body_cx, elt, elt_ty),
1174
                          elt_ty);
1175
        auto next_ix = body_res.bcx.build.Add(ix, C_int(1));
1176 1177
        auto next_scaled_ix = body_res.bcx.build.Add(scaled_ix, unit_sz);

1178 1179 1180
        cond_cx.build.AddIncomingToPhi(ix, vec(next_ix),
                                       vec(body_res.bcx.llbb));

1181 1182 1183
        cond_cx.build.AddIncomingToPhi(scaled_ix, vec(next_scaled_ix),
                                       vec(body_res.bcx.llbb));

1184 1185 1186 1187
        body_res.bcx.build.Br(cond_cx.llbb);
        ret res(next_cx, C_nil());
    }

1188 1189
    alt (t.struct) {
        case (ty.ty_vec(?et)) {
1190 1191
            ret iter_sequence_body(cx, v, et, f, false);
        }
1192 1193
        case (ty.ty_str) {
            auto et = ty.plain_ty(ty.ty_machine(common.ty_u8));
1194
            ret iter_sequence_body(cx, v, et, f, true);
1195
        }
1196
        case (_) { fail; }
1197
    }
1198 1199 1200 1201 1202 1203
    cx.fcx.ccx.sess.bug("bad type in trans.iter_sequence");
    fail;
}

fn incr_all_refcnts(@block_ctxt cx,
                    ValueRef v,
1204
                    @ty.t t) -> result {
1205

1206
    if (!ty.type_is_scalar(t)) {
1207
        auto llrawptr = cx.build.BitCast(v, T_ptr(T_i8()));
1208
        auto llfnptr = field_of_tydesc(cx, t, abi.tydesc_field_take_glue_off);
1209 1210
        auto llfn = cx.build.Load(llfnptr);
        cx.build.FastCall(llfn, vec(cx.fcx.lltaskptr, llrawptr));
1211
    }
1212
    ret res(cx, C_nil());
1213 1214
}

1215 1216
fn drop_slot(@block_ctxt cx,
             ValueRef slot,
1217
             @ty.t t) -> result {
1218
    auto llptr = load_scalar_or_boxed(cx, slot, t);
1219 1220 1221 1222 1223 1224
    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;
1225 1226
}

1227 1228
fn drop_ty(@block_ctxt cx,
           ValueRef v,
1229
           @ty.t t) -> result {
1230

1231
    if (!ty.type_is_scalar(t)) {
1232
        auto llrawptr = cx.build.BitCast(v, T_ptr(T_i8()));
1233 1234 1235
        auto llfnptr = field_of_tydesc(cx, t, abi.tydesc_field_drop_glue_off);
        auto llfn = cx.build.Load(llfnptr);
        cx.build.FastCall(llfn, vec(cx.fcx.lltaskptr, llrawptr));
1236
    }
1237
    ret res(cx, C_nil());
1238 1239 1240 1241 1242
}

fn build_memcpy(@block_ctxt cx,
                ValueRef dst,
                ValueRef src,
1243
                ValueRef n_bytes) -> result {
1244 1245 1246
    // FIXME: switch to the 64-bit variant when on such a platform.
    check (cx.fcx.ccx.intrinsics.contains_key("llvm.memcpy.p0i8.p0i8.i32"));
    auto memcpy = cx.fcx.ccx.intrinsics.get("llvm.memcpy.p0i8.p0i8.i32");
1247 1248
    auto src_ptr = cx.build.PointerCast(src, T_ptr(T_i8()));
    auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
1249
    auto size = cx.build.IntCast(n_bytes, T_i32());
1250 1251 1252 1253 1254 1255
    auto align = cx.build.IntCast(C_int(1), T_i32());

    // FIXME: align seems like it should be
    //   lib.llvm.llvm.LLVMAlignOf(llty);
    // but this makes it upset because it's not a constant.

1256 1257 1258 1259 1260 1261
    auto volatile = C_integral(0, T_i1());
    ret res(cx, cx.build.Call(memcpy,
                              vec(dst_ptr, src_ptr,
                                  size, align, volatile)));
}

1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275
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);
        auto llsz = cx.build.Load(llszptr);
        ret build_memcpy(cx, dst, src, llsz);

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

1276 1277 1278 1279
fn copy_ty(@block_ctxt cx,
           bool is_init,
           ValueRef dst,
           ValueRef src,
1280 1281
           @ty.t t) -> result {
    if (ty.type_is_scalar(t)) {
1282 1283
        ret res(cx, cx.build.Store(src, dst));

1284
    } else if (ty.type_is_nil(t)) {
1285 1286
        ret res(cx, C_nil());

1287
    } else if (ty.type_is_boxed(t)) {
1288
        auto r = incr_all_refcnts(cx, src, t);
1289
        if (! is_init) {
1290
            r = drop_ty(r.bcx, r.bcx.build.Load(dst), t);
1291 1292 1293
        }
        ret res(r.bcx, r.bcx.build.Store(src, dst));

1294 1295
    } else if (ty.type_is_structural(t) ||
               ty.type_has_dynamic_size(t)) {
1296 1297 1298 1299
        auto r = incr_all_refcnts(cx, src, t);
        if (! is_init) {
            r = drop_ty(r.bcx, dst, t);
        }
1300
        ret memcpy_ty(r.bcx, dst, src, t);
1301 1302 1303
    }

    cx.fcx.ccx.sess.bug("unexpected type in trans.copy_ty: " +
1304
                        ty.ty_to_str(t));
1305 1306 1307
    fail;
}

1308
impure fn trans_lit(@block_ctxt cx, &ast.lit lit, &ast.ann ann) -> result {
1309
    alt (lit.node) {
1310
        case (ast.lit_int(?i)) {
1311
            ret res(cx, C_int(i));
1312 1313
        }
        case (ast.lit_uint(?u)) {
1314
            ret res(cx, C_int(u as int));
1315
        }
1316 1317 1318 1319 1320 1321
        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 已提交
1322 1323 1324 1325 1326 1327 1328 1329 1330
                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(); }
1331 1332 1333 1334 1335 1336
                case (_) {
                    cx.fcx.ccx.sess.bug("bad mach int literal type");
                }
            }
            ret res(cx, C_integral(i, t));
        }
1337
        case (ast.lit_char(?c)) {
1338
            ret res(cx, C_integral(c as int, T_char()));
1339 1340
        }
        case (ast.lit_bool(?b)) {
1341 1342 1343 1344
            ret res(cx, C_bool(b));
        }
        case (ast.lit_nil) {
            ret res(cx, C_nil());
1345 1346 1347
        }
        case (ast.lit_str(?s)) {
            auto len = (_str.byte_len(s) as int) + 1;
1348
            auto sub = trans_upcall(cx, "upcall_new_str",
1349
                                    vec(p2i(C_str(cx.fcx.ccx, s)),
1350 1351
                                        C_int(len)));
            sub.val = sub.bcx.build.IntToPtr(sub.val,
1352
                                             T_ptr(T_str()));
1353
            auto t = node_ann_type(cx.fcx.ccx, ann);
1354
            find_scope_cx(cx).cleanups +=
1355
                clean(bind drop_ty(_, sub.val, t));
1356
            ret sub;
1357 1358 1359 1360
        }
    }
}

1361
fn target_type(@crate_ctxt cx, @ty.t t) -> @ty.t {
1362
    alt (t.struct) {
1363 1364
        case (ty.ty_int) {
            auto tm = ty.ty_machine(cx.sess.get_targ_cfg().int_type);
1365 1366
            ret @rec(struct=tm with *t);
        }
1367 1368
        case (ty.ty_uint) {
            auto tm = ty.ty_machine(cx.sess.get_targ_cfg().uint_type);
1369 1370
            ret @rec(struct=tm with *t);
        }
1371
        case (_) { /* fall through */ }
1372 1373 1374 1375
    }
    ret t;
}

1376
fn node_ann_type(@crate_ctxt cx, &ast.ann a) -> @ty.t {
1377 1378
    alt (a) {
        case (ast.ann_none) {
1379
            cx.sess.bug("missing type annotation");
1380 1381
        }
        case (ast.ann_type(?t)) {
1382
            ret target_type(cx, t);
1383 1384 1385 1386
        }
    }
}

1387 1388 1389 1390
fn node_type(@crate_ctxt cx, &ast.ann a) -> TypeRef {
    ret type_of(cx, node_ann_type(cx, a));
}

1391
impure fn trans_unary(@block_ctxt cx, ast.unop op,
1392
                      @ast.expr e, &ast.ann a) -> result {
1393 1394 1395

    auto sub = trans_expr(cx, e);

1396 1397
    alt (op) {
        case (ast.bitnot) {
1398 1399
            sub.val = cx.build.Not(sub.val);
            ret sub;
1400 1401
        }
        case (ast.not) {
1402 1403
            sub.val = cx.build.Not(sub.val);
            ret sub;
1404 1405 1406
        }
        case (ast.neg) {
            // FIXME: switch by signedness.
1407 1408
            sub.val = cx.build.Neg(sub.val);
            ret sub;
1409
        }
1410
        case (ast.box) {
1411
            auto e_ty = ty.expr_ty(e);
1412 1413 1414 1415
            auto e_val = sub.val;
            sub = trans_malloc(sub.bcx, node_ann_type(sub.bcx.fcx.ccx, a));
            auto box = sub.val;
            auto rc = sub.bcx.build.GEP(box,
1416 1417
                                        vec(C_int(0),
                                            C_int(abi.box_rc_field_refcnt)));
1418 1419 1420 1421 1422 1423
            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);
            sub = copy_ty(sub.bcx, true, body, e_val, e_ty);
            ret res(sub.bcx, box);
1424
        }
1425 1426 1427 1428 1429
        case (ast.deref) {
            sub.val = sub.bcx.build.GEP(sub.val,
                                        vec(C_int(0),
                                            C_int(abi.box_rc_field_body)));
            auto e_ty = node_ann_type(sub.bcx.fcx.ccx, a);
1430 1431
            if (ty.type_is_scalar(e_ty) ||
                ty.type_is_nil(e_ty)) {
1432 1433 1434
                sub.val = sub.bcx.build.Load(sub.val);
            }
            ret sub;
1435
        }
1436 1437 1438 1439
    }
    fail;
}

1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475
fn trans_eager_binop(@block_ctxt cx, ast.binop op,
                     ValueRef lhs, ValueRef rhs) -> ValueRef {

    alt (op) {
        case (ast.add) { ret cx.build.Add(lhs, rhs); }
        case (ast.sub) { ret cx.build.Sub(lhs, rhs); }

        // FIXME: switch by signedness.
        case (ast.mul) { ret cx.build.Mul(lhs, rhs); }
        case (ast.div) { ret cx.build.SDiv(lhs, rhs); }
        case (ast.rem) { ret cx.build.SRem(lhs, rhs); }

        case (ast.bitor) { ret cx.build.Or(lhs, rhs); }
        case (ast.bitand) { ret cx.build.And(lhs, rhs); }
        case (ast.bitxor) { ret cx.build.Xor(lhs, rhs); }
        case (ast.lsl) { ret cx.build.Shl(lhs, rhs); }
        case (ast.lsr) { ret cx.build.LShr(lhs, rhs); }
        case (ast.asr) { ret cx.build.AShr(lhs, rhs); }
        case (_) {
            auto cmp = lib.llvm.LLVMIntEQ;
            alt (op) {
                case (ast.eq) { cmp = lib.llvm.LLVMIntEQ; }
                case (ast.ne) { cmp = lib.llvm.LLVMIntNE; }

                // FIXME: switch by signedness.
                case (ast.lt) { cmp = lib.llvm.LLVMIntSLT; }
                case (ast.le) { cmp = lib.llvm.LLVMIntSLE; }
                case (ast.ge) { cmp = lib.llvm.LLVMIntSGE; }
                case (ast.gt) { cmp = lib.llvm.LLVMIntSGT; }
            }
            ret cx.build.ICmp(cmp, lhs, rhs);
        }
    }
    fail;
}

1476
impure fn trans_binary(@block_ctxt cx, ast.binop op,
1477
                       @ast.expr a, @ast.expr b) -> result {
1478

1479 1480 1481 1482 1483 1484 1485
    // First couple cases are lazy:

    alt (op) {
        case (ast.and) {
            // Lazy-eval and
            auto lhs_res = trans_expr(cx, a);

1486
            auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
1487 1488
            auto rhs_res = trans_expr(rhs_cx, b);

1489
            auto lhs_false_cx = new_scope_block_ctxt(cx, "lhs false");
1490
            auto lhs_false_res = res(lhs_false_cx, C_bool(false));
1491 1492 1493

            lhs_res.bcx.build.CondBr(lhs_res.val,
                                     rhs_cx.llbb,
1494 1495 1496 1497
                                     lhs_false_cx.llbb);

            ret join_results(cx, T_bool(),
                             vec(lhs_false_res, rhs_res));
1498 1499 1500 1501 1502 1503
        }

        case (ast.or) {
            // Lazy-eval or
            auto lhs_res = trans_expr(cx, a);

1504
            auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
1505 1506
            auto rhs_res = trans_expr(rhs_cx, b);

1507
            auto lhs_true_cx = new_scope_block_ctxt(cx, "lhs true");
1508
            auto lhs_true_res = res(lhs_true_cx, C_bool(true));
1509 1510

            lhs_res.bcx.build.CondBr(lhs_res.val,
1511
                                     lhs_true_cx.llbb,
1512
                                     rhs_cx.llbb);
1513 1514 1515

            ret join_results(cx, T_bool(),
                             vec(lhs_true_res, rhs_res));
1516
        }
1517 1518

        case (_) {
1519 1520 1521 1522 1523
            // Remaining cases are eager:
            auto lhs = trans_expr(cx, a);
            auto sub = trans_expr(lhs.bcx, b);
            ret res(sub.bcx, trans_eager_binop(sub.bcx, op,
                                               lhs.val, sub.val));
1524
        }
1525 1526 1527 1528
    }
    fail;
}

1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559
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)) {
            live += r;
            vals += r.val;
            bbs += r.bcx.llbb;
        }
    }

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

        case (_) { /* fall through */ }
1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572
    }

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

1573
impure fn trans_if(@block_ctxt cx, @ast.expr cond,
1574
                   &ast.block thn, &option.t[ast.block] els) -> result {
1575 1576 1577

    auto cond_res = trans_expr(cx, cond);

1578
    auto then_cx = new_scope_block_ctxt(cx, "then");
1579 1580
    auto then_res = trans_block(then_cx, thn);

1581
    auto else_cx = new_scope_block_ctxt(cx, "else");
1582
    auto else_res = res(else_cx, C_nil());
1583 1584 1585

    alt (els) {
        case (some[ast.block](?eblk)) {
1586
            else_res = trans_block(else_cx, eblk);
1587
        }
1588
        case (_) { /* fall through */ }
1589 1590
    }

1591
    cond_res.bcx.build.CondBr(cond_res.val,
1592 1593
                              then_cx.llbb,
                              else_cx.llbb);
1594 1595 1596 1597

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

1600
impure fn trans_while(@block_ctxt cx, @ast.expr cond,
1601 1602
                      &ast.block body) -> result {

1603 1604
    auto cond_cx = new_scope_block_ctxt(cx, "while cond");
    auto body_cx = new_scope_block_ctxt(cx, "while loop body");
1605
    auto next_cx = new_sub_block_ctxt(cx, "next");
1606 1607

    auto body_res = trans_block(body_cx, body);
1608 1609 1610 1611 1612 1613 1614 1615
    auto cond_res = trans_expr(cond_cx, cond);

    body_res.bcx.build.Br(cond_cx.llbb);
    cond_res.bcx.build.CondBr(cond_res.val,
                              body_cx.llbb,
                              next_cx.llbb);

    cx.build.Br(cond_cx.llbb);
1616 1617 1618 1619
    ret res(next_cx, C_nil());
}

impure fn trans_do_while(@block_ctxt cx, &ast.block body,
1620
                         @ast.expr cond) -> result {
1621

1622
    auto body_cx = new_scope_block_ctxt(cx, "do-while loop body");
1623
    auto next_cx = new_sub_block_ctxt(cx, "next");
1624 1625

    auto body_res = trans_block(body_cx, body);
1626 1627 1628 1629 1630 1631
    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);
1632 1633 1634
    ret res(next_cx, body_res.val);
}

P
Patrick Walton 已提交
1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661
// Pattern matching translation

// Returns a pointer to the union part of the LLVM representation of a tag
// type, cast to the appropriate type.
fn get_pat_union_ptr(@block_ctxt cx, vec[@ast.pat] subpats, ValueRef llval)
        -> ValueRef {
    auto llblobptr = cx.build.GEP(llval, vec(C_int(0), C_int(1)));

    // Generate the union type.
    let vec[TypeRef] llsubpattys = vec();
    for (@ast.pat subpat in subpats) {
        llsubpattys += vec(type_of(cx.fcx.ccx, pat_ty(subpat)));
    }

    // Recursively check subpatterns.
    auto llunionty = T_struct(llsubpattys);
    ret cx.build.TruncOrBitCast(llblobptr, T_ptr(llunionty));
}

impure fn trans_pat_match(@block_ctxt cx, @ast.pat pat, ValueRef llval,
                          @block_ctxt next_cx) -> result {
    alt (pat.node) {
        case (ast.pat_wild(_)) { ret res(cx, llval); }
        case (ast.pat_bind(_, _, _)) { ret res(cx, llval); }
        case (ast.pat_tag(?id, ?subpats, ?vdef_opt, ?ann)) {
            auto lltagptr = cx.build.GEP(llval, vec(C_int(0), C_int(0)));
            auto lltag = cx.build.Load(lltagptr);
1662

P
Patrick Walton 已提交
1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690
            auto vdef = option.get[ast.variant_def](vdef_opt);
            auto variant_id = vdef._1;
            auto tinfo = cx.fcx.ccx.tags.get(vdef._0);
            auto variant_tag = 0;
            auto i = 0;
            for (tup(ast.def_id,arity) vinfo in tinfo.variants) {
                auto this_variant_id = vinfo._0;
                if (variant_id._0 == this_variant_id._0 &&
                        variant_id._1 == this_variant_id._1) {
                    variant_tag = i;
                }
                i += 1;
            }

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

            auto lleq = cx.build.ICmp(lib.llvm.LLVMIntEQ, lltag,
                                      C_int(variant_tag));
            cx.build.CondBr(lleq, matched_cx.llbb, next_cx.llbb);

            if (_vec.len[@ast.pat](subpats) > 0u) {
                auto llunionptr = get_pat_union_ptr(matched_cx, subpats,
                                                    llval);
                auto i = 0;
                for (@ast.pat subpat in subpats) {
                    auto llsubvalptr = matched_cx.build.GEP(llunionptr,
                                                            vec(C_int(0),
                                                                C_int(i)));
1691
                    auto llsubval = load_scalar_or_boxed(matched_cx,
P
Patrick Walton 已提交
1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731
                                                        llsubvalptr,
                                                        pat_ty(subpat));
                    auto subpat_res = trans_pat_match(matched_cx, subpat,
                                                      llsubval, next_cx);
                    matched_cx = subpat_res.bcx;
                }
            }

            ret res(matched_cx, llval);
        }
    }

    fail;
}

impure fn trans_pat_binding(@block_ctxt cx, @ast.pat pat, ValueRef llval)
        -> result {
    alt (pat.node) {
        case (ast.pat_wild(_)) { ret res(cx, llval); }
        case (ast.pat_bind(?id, ?def_id, ?ann)) {
            auto ty = node_ann_type(cx.fcx.ccx, ann);
            auto llty = type_of(cx.fcx.ccx, ty);

            auto dst = cx.build.Alloca(llty);
            llvm.LLVMSetValueName(dst, _str.buf(id));
            cx.fcx.lllocals.insert(def_id, dst);
            cx.cleanups += clean(bind drop_slot(_, dst, ty));

            ret copy_ty(cx, true, dst, llval, ty);
        }
        case (ast.pat_tag(_, ?subpats, _, _)) {
            if (_vec.len[@ast.pat](subpats) == 0u) { ret res(cx, llval); }

            auto llunionptr = get_pat_union_ptr(cx, subpats, llval);

            auto this_cx = cx;
            auto i = 0;
            for (@ast.pat subpat in subpats) {
                auto llsubvalptr = this_cx.build.GEP(llunionptr,
                                                     vec(C_int(0), C_int(i)));
1732
                auto llsubval = load_scalar_or_boxed(this_cx, llsubvalptr,
P
Patrick Walton 已提交
1733 1734 1735 1736
                                                    pat_ty(subpat));
                auto subpat_res = trans_pat_binding(this_cx, subpat,
                                                    llsubval);
                this_cx = subpat_res.bcx;
1737
                i += 1;
P
Patrick Walton 已提交
1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779
            }

            ret res(this_cx, llval);
        }
    }
}

impure fn trans_alt(@block_ctxt cx, @ast.expr expr, vec[ast.arm] arms)
        -> result {
    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());
}

1780
type generic_info = rec(@ty.t item_type,
1781 1782
                        vec[ValueRef] tydescs);

1783 1784
type lval_result = rec(result res,
                       bool is_mem,
1785
                       option.t[generic_info] generic,
1786 1787 1788 1789 1790
                       option.t[ValueRef] llobj);

fn lval_mem(@block_ctxt cx, ValueRef val) -> lval_result {
    ret rec(res=res(cx, val),
            is_mem=true,
1791
            generic=none[generic_info],
1792 1793 1794 1795 1796 1797
            llobj=none[ValueRef]);
}

fn lval_val(@block_ctxt cx, ValueRef val) -> lval_result {
    ret rec(res=res(cx, val),
            is_mem=false,
1798
            generic=none[generic_info],
1799 1800
            llobj=none[ValueRef]);
}
1801

1802
fn trans_path(@block_ctxt cx, &ast.path p, &option.t[ast.def] dopt,
1803
        &ast.ann ann) -> lval_result {
1804 1805 1806 1807 1808
    alt (dopt) {
        case (some[ast.def](?def)) {
            alt (def) {
                case (ast.def_arg(?did)) {
                    check (cx.fcx.llargs.contains_key(did));
1809
                    ret lval_mem(cx, cx.fcx.llargs.get(did));
1810 1811 1812
                }
                case (ast.def_local(?did)) {
                    check (cx.fcx.lllocals.contains_key(did));
1813
                    ret lval_mem(cx, cx.fcx.lllocals.get(did));
G
Graydon Hoare 已提交
1814
                }
P
Patrick Walton 已提交
1815 1816
                case (ast.def_binding(?did)) {
                    check (cx.fcx.lllocals.contains_key(did));
1817
                    ret lval_mem(cx, cx.fcx.lllocals.get(did));
P
Patrick Walton 已提交
1818
                }
1819 1820 1821 1822
                case (ast.def_obj_field(?did)) {
                    check (cx.fcx.llobjfields.contains_key(did));
                    ret lval_mem(cx, cx.fcx.llobjfields.get(did));
                }
1823
                case (ast.def_fn(?did)) {
1824
                    check (cx.fcx.ccx.fn_pairs.contains_key(did));
1825 1826 1827
                    check (cx.fcx.ccx.item_ids.contains_key(did));

                    auto fn_item = cx.fcx.ccx.items.get(did);
1828
                    auto lv = lval_val(cx, cx.fcx.ccx.fn_pairs.get(did));
1829 1830 1831
                    auto monoty = node_ann_type(cx.fcx.ccx, ann);
                    auto tys = ty.resolve_ty_params(fn_item, monoty);

G
Graydon Hoare 已提交
1832 1833 1834 1835 1836 1837
                    if (_vec.len[@ty.t](tys) != 0u) {
                        let vec[ValueRef] tydescs = vec();
                        for (@ty.t t in tys) {
                            append[ValueRef](tydescs,
                                             get_tydesc(cx, t));
                        }
1838
                        auto gen = rec( item_type = ty.item_ty(fn_item)._1,
1839 1840 1841
                                        tydescs = tydescs );
                        lv = rec(generic = some[generic_info](gen)
                                 with lv);
G
Graydon Hoare 已提交
1842
                    }
1843

1844
                    ret lv;
1845
                }
1846
                case (ast.def_obj(?did)) {
1847 1848
                    check (cx.fcx.ccx.fn_pairs.contains_key(did));
                    ret lval_val(cx, cx.fcx.ccx.fn_pairs.get(did));
1849
                }
1850 1851
                case (ast.def_variant(?tid, ?vid)) {
                    check (cx.fcx.ccx.tags.contains_key(tid));
1852 1853 1854 1855 1856 1857 1858
                    if (cx.fcx.ccx.fn_pairs.contains_key(vid)) {
                        ret lval_val(cx, cx.fcx.ccx.fn_pairs.get(vid));
                    } else {
                        // Nullary variants are just scalar constants.
                        check (cx.fcx.ccx.item_ids.contains_key(vid));
                        ret lval_val(cx, cx.fcx.ccx.item_ids.get(vid));
                    }
1859
                }
1860 1861
                case (_) {
                    cx.fcx.ccx.sess.unimpl("def variant in trans");
G
Graydon Hoare 已提交
1862 1863 1864
                }
            }
        }
1865
        case (none[ast.def]) {
1866
            cx.fcx.ccx.sess.err("unresolved expr_path in trans");
1867 1868 1869 1870 1871
        }
    }
    fail;
}

1872
impure fn trans_field(@block_ctxt cx, &ast.span sp, @ast.expr base,
1873
                      &ast.ident field, &ast.ann ann) -> lval_result {
1874
    auto lv = trans_lval(cx, base);
1875 1876
    auto r = lv.res;
    check (lv.is_mem);
1877 1878 1879 1880
    auto t = ty.expr_ty(base);
    alt (t.struct) {
        case (ty.ty_tup(?fields)) {
            let uint ix = ty.field_num(cx.fcx.ccx.sess, sp, field);
1881
            auto v = r.bcx.build.GEP(r.val, vec(C_int(0), C_int(ix as int)));
1882
            ret lval_mem(r.bcx, v);
1883
        }
1884 1885
        case (ty.ty_rec(?fields)) {
            let uint ix = ty.field_idx(cx.fcx.ccx.sess, sp, field, fields);
1886
            auto v = r.bcx.build.GEP(r.val, vec(C_int(0), C_int(ix as int)));
1887
            ret lval_mem(r.bcx, v);
1888
        }
1889 1890
        case (ty.ty_obj(?methods)) {
            let uint ix = ty.method_idx(cx.fcx.ccx.sess, sp, field, methods);
1891 1892 1893 1894 1895 1896
            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)));
1897 1898 1899

            auto lvo = lval_mem(r.bcx, v);
            ret rec(llobj = some[ValueRef](r.val) with lvo);
1900
        }
1901
        case (_) { cx.fcx.ccx.sess.unimpl("field variant in trans_field"); }
1902 1903 1904 1905
    }
    fail;
}

1906
impure fn trans_index(@block_ctxt cx, &ast.span sp, @ast.expr base,
1907
                      @ast.expr idx, &ast.ann ann) -> lval_result {
1908

G
Graydon Hoare 已提交
1909 1910 1911
    auto lv = trans_expr(cx, base);
    auto ix = trans_expr(lv.bcx, idx);
    auto v = lv.val;
1912 1913

    auto llunit_ty = node_type(cx.fcx.ccx, ann);
1914
    auto unit_sz = size_of(llunit_ty);
1915 1916 1917 1918
    auto scaled_ix = ix.bcx.build.Mul(ix.val, unit_sz);

    auto lim = ix.bcx.build.GEP(v, vec(C_int(0), C_int(abi.vec_elt_fill)));
    lim = ix.bcx.build.Load(lim);
1919

1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936
    auto bounds_check = ix.bcx.build.ICmp(lib.llvm.LLVMIntULT,
                                          scaled_ix, lim);

    auto fail_cx = new_sub_block_ctxt(ix.bcx, "fail");
    auto next_cx = new_sub_block_ctxt(ix.bcx, "next");
    ix.bcx.build.CondBr(bounds_check, next_cx.llbb, fail_cx.llbb);

    // fail: bad bounds check.
    auto V_expr_str = p2i(C_str(cx.fcx.ccx, "out-of-bounds access"));
    auto V_filename = p2i(C_str(cx.fcx.ccx, sp.filename));
    auto V_line = sp.lo.line as int;
    auto args = vec(V_expr_str, V_filename, C_int(V_line));
    auto fail_res = trans_upcall(fail_cx, "upcall_fail", args);
    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)));
    auto elt = next_cx.build.GEP(body, vec(C_int(0), ix.val));
1937
    ret lval_mem(next_cx, elt);
1938 1939
}

1940 1941 1942 1943
// 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).

1944
impure fn trans_lval(@block_ctxt cx, @ast.expr e) -> lval_result {
1945
    alt (e.node) {
1946 1947
        case (ast.expr_path(?p, ?dopt, ?ann)) {
            ret trans_path(cx, p, dopt, ann);
1948 1949 1950 1951
        }
        case (ast.expr_field(?base, ?ident, ?ann)) {
            ret trans_field(cx, e.span, base, ident, ann);
        }
1952 1953 1954
        case (ast.expr_index(?base, ?idx, ?ann)) {
            ret trans_index(cx, e.span, base, idx, ann);
        }
1955
        case (_) { cx.fcx.ccx.sess.unimpl("expr variant in trans_lval"); }
G
Graydon Hoare 已提交
1956 1957 1958 1959
    }
    fail;
}

1960
impure fn trans_cast(@block_ctxt cx, @ast.expr e, &ast.ann ann) -> result {
1961 1962 1963 1964
    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);
1965
    if (!ty.type_is_fp(t)) {
1966 1967
        if (llvm.LLVMGetIntTypeWidth(lldsttype) >
            llvm.LLVMGetIntTypeWidth(llsrctype)) {
1968
            if (ty.type_is_signed(t)) {
1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990
                // 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;
}

1991

1992
// NB: this must match type_of_fn_full and create_llargs_for_fn_args.
G
Graydon Hoare 已提交
1993 1994
impure fn trans_args(@block_ctxt cx,
                     ValueRef llclosure,
1995
                     option.t[ValueRef] llobj,
1996
                     option.t[generic_info] gen,
G
Graydon Hoare 已提交
1997 1998
                     &vec[@ast.expr] es,
                     @ty.t fn_ty)
1999
    -> tup(@block_ctxt, vec[ValueRef], option.t[ValueRef]) {
2000 2001 2002
    let vec[ValueRef] vs = vec(cx.fcx.lltaskptr);
    let @block_ctxt bcx = cx;

2003
    let vec[ty.arg] args = ty.ty_fn_args(fn_ty);
2004

2005 2006
    let option.t[ValueRef] llretslot_opt = none[ValueRef];

2007 2008 2009
    alt (gen) {
        case (some[generic_info](?g)) {
            for (ValueRef t in g.tydescs) {
G
Graydon Hoare 已提交
2010 2011
                vs += t;
            }
2012 2013
            args = ty.ty_fn_args(g.item_type);
            if (ty.type_has_dynamic_size(ty.ty_fn_ret(g.item_type))) {
2014 2015 2016 2017 2018 2019
                auto retty = ty.ty_fn_ret(fn_ty);
                auto llretty = type_of(cx.fcx.ccx, retty);
                auto llretslot = cx.build.Alloca(llretty);
                llretslot = cx.build.PointerCast(llretslot, T_ptr(T_i8()));
                vs += llretslot;
                llretslot_opt = some[ValueRef](llretslot);
2020
            }
G
Graydon Hoare 已提交
2021 2022 2023 2024
        }
        case (_) { }
    }

2025 2026 2027 2028 2029 2030 2031
    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).
            vs += cx.build.Load(ob);
        }
2032 2033 2034
        case (_) {
            vs += llclosure;
        }
2035 2036
    }

2037
    auto i = 0u;
2038
    for (@ast.expr e in es) {
2039 2040 2041
        auto mode = args.(i).mode;

        auto re;
2042
        if (ty.type_is_structural(ty.expr_ty(e))) {
2043 2044 2045 2046 2047 2048
            re = trans_expr(bcx, e);
            if (mode == ast.val) {
                // Until here we've been treating structures by pointer;
                // we are now passing it as an arg, so need to load it.
                re.val = re.bcx.build.Load(re.val);
            }
2049 2050 2051 2052 2053 2054 2055 2056
        } 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);
            }
2057

2058 2059 2060 2061 2062 2063 2064
            if (!lv.is_mem) {
                // 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);
                re = res(lv.res.bcx, llptr);
2065
            } else {
2066
                re = lv.res;
2067
            }
2068 2069 2070 2071 2072 2073 2074 2075

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

        if (ty.type_has_dynamic_size(args.(i).ty)) {
            re.val = re.bcx.build.PointerCast(re.val,
                                              T_typaram_ptr());
2076
        }
2077 2078 2079 2080 2081

        vs += re.val;
        bcx = re.bcx;

        i += 1u;
2082 2083
    }

2084
    ret tup(bcx, vs, llretslot_opt);
2085 2086
}

2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175
impure fn trans_bind_thunk(@crate_ctxt cx,
                           @ty.t incoming_fty,
                           @ty.t outgoing_fty,
                           vec[option.t[@ast.expr]] args,
                           TypeRef llclosure_ty,
                           vec[@ty.t] bound_tys) -> ValueRef {
    // Construct a thunk-call with signature incoming_fty, and that copies
    // args forward into a call to outgoing_fty.

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

    let @ty.t rty = ret_ty_of_fn_ty(incoming_fty);

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

    auto fcx = new_fn_ctxt(cx, s, llthunk);
    auto bcx = new_top_block_ctxt(fcx);

    auto llclosure = bcx.build.PointerCast(fcx.llclosure, llclosure_ty);

    auto llbody = bcx.build.GEP(llclosure,
                                vec(C_int(0),
                                    C_int(abi.box_rc_field_body)));

    auto lltarget = bcx.build.GEP(llbody,
                                  vec(C_int(0),
                                      C_int(abi.closure_elt_target)));

    auto llbound = bcx.build.GEP(llbody,
                                 vec(C_int(0),
                                     C_int(abi.closure_elt_bindings)));

    auto lltargetclosure = bcx.build.GEP(lltarget,
                                         vec(C_int(0),
                                             C_int(abi.fn_field_box)));
    lltargetclosure = bcx.build.Load(lltargetclosure);
    let vec[ValueRef] llargs = vec(fcx.lltaskptr,
                                   lltargetclosure);
    let uint a = 0u;
    let int b = 0;
    for (option.t[@ast.expr] arg in args) {
        alt (arg) {

            // Arg provided at binding time; thunk copies it from closure.
            case (some[@ast.expr](_)) {
                let ValueRef bound_arg = bcx.build.GEP(llbound,
                                                       vec(C_int(0),
                                                           C_int(b)));
                // FIXME: possibly support passing aliases someday.
                llargs += bcx.build.Load(bound_arg);
                b += 1;
            }

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

    // FIXME: turn this call + ret into a tail call.
    auto lltargetfn = bcx.build.GEP(lltarget,
                                    vec(C_int(0),
                                        C_int(abi.fn_field_code)));
    lltargetfn = bcx.build.Load(lltargetfn);
    auto r = bcx.build.FastCall(lltargetfn, llargs);

    alt (fcx.llretptr) {
        case (some[ValueRef](?llptr)) {
            bcx.build.Store(bcx.build.Load(r), llptr);
            bcx.build.RetVoid();
        }
        case (none[ValueRef]) {
            if (ty.type_is_nil(rty)) {
                bcx.build.RetVoid();
            } else {
                bcx.build.Ret(r);
            }
        }
    }

    ret llthunk;
}

2176 2177 2178 2179 2180 2181 2182
impure fn trans_bind(@block_ctxt cx, @ast.expr f,
                     vec[option.t[@ast.expr]] args,
                     &ast.ann ann) -> result {
    auto f_res = trans_lval(cx, f);
    if (f_res.is_mem) {
        cx.fcx.ccx.sess.unimpl("re-binding existing function");
    } else {
2183 2184
        let vec[@ast.expr] bound = vec();

2185 2186 2187 2188 2189
        for (option.t[@ast.expr] argopt in args) {
            alt (argopt) {
                case (none[@ast.expr]) {
                }
                case (some[@ast.expr](?e)) {
2190
                    append[@ast.expr](bound, e);
2191 2192 2193
                }
            }
        }
2194
        if (_vec.len[@ast.expr](bound) == 0u) {
2195 2196 2197 2198 2199 2200
            // 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);
2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213

            // Translate the bound expressions.
            let vec[@ty.t] bound_tys = vec();
            let vec[ValueRef] bound_vals = vec();
            for (@ast.expr e in bound) {
                auto arg = trans_expr(bcx, e);
                bcx = arg.bcx;
                append[ValueRef](bound_vals, arg.val);
                append[@ty.t](bound_tys, ty.expr_ty(e));
            }

            // Synthesize a closure type.
            let @ty.t bindings_ty = ty.plain_ty(ty.ty_tup(bound_tys));
2214
            let TypeRef lltarget_ty = type_of(bcx.fcx.ccx, ty.expr_ty(f));
2215
            let TypeRef llbindings_ty = type_of(bcx.fcx.ccx, bindings_ty);
2216 2217
            let TypeRef llclosure_ty = T_closure_ptr(lltarget_ty,
                                                     llbindings_ty);
2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239

            // Malloc a box for the body.
            auto r = trans_malloc_inner(bcx, llclosure_ty);
            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);
            bcx.build.Store(bindings_tydesc, bound_tydesc);

2240 2241
            // Store thunk-target.
            auto bound_target =
2242 2243
                bcx.build.GEP(closure,
                              vec(C_int(0),
2244 2245
                                  C_int(abi.closure_elt_target)));
            bcx.build.Store(bcx.build.Load(f_res.res.val), bound_target);
2246

2247
            // Copy expr values into boxed bindings.
2248
            let int i = 0;
2249 2250 2251 2252
            auto bindings =
                bcx.build.GEP(closure,
                              vec(C_int(0),
                                  C_int(abi.closure_elt_bindings)));
2253 2254 2255 2256 2257 2258 2259
            for (ValueRef v in bound_vals) {
                auto bound = bcx.build.GEP(bindings,
                                           vec(C_int(0),C_int(i)));
                bcx = copy_ty(r.bcx, true, bound, v, bound_tys.(i)).bcx;
                i += 1;
            }

2260 2261 2262 2263
            // 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)));
2264 2265

            let @ty.t pair_ty = node_ann_type(cx.fcx.ccx, ann);
2266
            let ValueRef llthunk =
2267 2268
                trans_bind_thunk(cx.fcx.ccx, pair_ty, ty.expr_ty(f),
                                 args, llclosure_ty, bound_tys);
2269 2270 2271 2272 2273 2274 2275 2276 2277 2278

            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)));
            bcx.build.Store(bcx.build.PointerCast(box,
                                                  T_opaque_closure_ptr()),
                            pair_box);
2279

2280 2281 2282
            find_scope_cx(cx).cleanups +=
                clean(bind drop_slot(_, pair_v, pair_ty));

2283 2284
            ret res(bcx, pair_v);
        }
2285 2286 2287
    }
}

2288
impure fn trans_call(@block_ctxt cx, @ast.expr f,
G
Graydon Hoare 已提交
2289
                     vec[@ast.expr] args, &ast.ann ann) -> result {
2290
    auto f_res = trans_lval(cx, f);
2291
    auto faddr = f_res.res.val;
2292
    auto llclosure = C_null(T_opaque_closure_ptr());
2293 2294 2295 2296 2297 2298 2299 2300 2301

    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;
2302 2303
            auto pair = faddr;
            faddr = bcx.build.GEP(pair, vec(C_int(0),
2304 2305
                                             C_int(abi.fn_field_code)));
            faddr = bcx.build.Load(faddr);
2306 2307 2308 2309

            llclosure = bcx.build.GEP(pair, vec(C_int(0),
                                                 C_int(abi.fn_field_box)));
            llclosure = bcx.build.Load(llclosure);
2310
        }
2311
    }
2312 2313
    auto fn_ty = ty.expr_ty(f);
    auto ret_ty = ty.ann_to_type(ann);
G
Graydon Hoare 已提交
2314 2315
    auto args_res = trans_args(f_res.res.bcx,
                               llclosure, f_res.llobj,
2316
                               f_res.generic,
2317
                               args, fn_ty);
G
Graydon Hoare 已提交
2318

2319 2320
    auto bcx = args_res._0;
    auto real_retval = bcx.build.FastCall(faddr, args_res._1);
2321
    auto retval;
G
Graydon Hoare 已提交
2322

2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342
    // Check for a generic retslot.
    alt (args_res._2) {
        case (some[ValueRef](?llretslot)) {
            retval = bcx.build.Load(llretslot);
        }
        case (none[ValueRef]) {
            retval = real_retval;

            if (ty.type_is_nil(ret_ty)) {
                retval = C_nil();
            } else if (ty.type_is_structural(ret_ty)) {
                // Structured returns come back as first-class values. This is
                // nice for LLVM but wrong for us; we treat structured values
                // by pointer in most of our code here. So spill it to an
                // alloca.
                auto local = bcx.build.Alloca(type_of(cx.fcx.ccx, ret_ty));
                bcx.build.Store(retval, local);
                retval = local;
            }
        }
G
Graydon Hoare 已提交
2343 2344
    }

2345 2346


G
Graydon Hoare 已提交
2347 2348 2349 2350 2351
    // Retval doesn't correspond to anything really tangible in the frame, but
    // it's a ref all the same, so we put a note here to drop it when we're
    // done in this scope.
    find_scope_cx(cx).cleanups += clean(bind drop_ty(_, retval, ret_ty));

2352
    ret res(bcx, retval);
2353 2354
}

2355
impure fn trans_tup(@block_ctxt cx, vec[ast.elt] elts,
G
Graydon Hoare 已提交
2356
                    &ast.ann ann) -> result {
2357 2358
    auto t = node_ann_type(cx.fcx.ccx, ann);
    auto llty = type_of(cx.fcx.ccx, t);
2359
    auto tup_val = cx.build.Alloca(llty);
2360
    find_scope_cx(cx).cleanups += clean(bind drop_ty(_, tup_val, t));
G
Graydon Hoare 已提交
2361 2362
    let int i = 0;
    auto r = res(cx, C_nil());
2363
    for (ast.elt e in elts) {
2364
        auto t = ty.expr_ty(e.expr);
2365
        auto src_res = trans_expr(r.bcx, e.expr);
G
Graydon Hoare 已提交
2366 2367 2368 2369 2370 2371 2372
        auto dst_elt = r.bcx.build.GEP(tup_val, vec(C_int(0), C_int(i)));
        r = copy_ty(src_res.bcx, true, dst_elt, src_res.val, t);
        i += 1;
    }
    ret res(r.bcx, tup_val);
}

G
Graydon Hoare 已提交
2373 2374
impure fn trans_vec(@block_ctxt cx, vec[@ast.expr] args,
                    &ast.ann ann) -> result {
2375 2376 2377 2378
    auto t = node_ann_type(cx.fcx.ccx, ann);
    auto unit_ty = t;
    alt (t.struct) {
        case (ty.ty_vec(?t)) {
G
Graydon Hoare 已提交
2379 2380 2381 2382 2383 2384 2385 2386
            unit_ty = t;
        }
        case (_) {
            cx.fcx.ccx.sess.bug("non-vec type in trans_vec");
        }
    }

    auto llunit_ty = type_of(cx.fcx.ccx, unit_ty);
2387
    auto unit_sz = size_of(llunit_ty);
G
Graydon Hoare 已提交
2388 2389 2390 2391 2392 2393
    auto data_sz = llvm.LLVMConstMul(C_int(_vec.len[@ast.expr](args) as int),
                                     unit_sz);

    // FIXME: pass tydesc properly.
    auto sub = trans_upcall(cx, "upcall_new_vec", vec(data_sz, C_int(0)));

2394
    auto llty = type_of(cx.fcx.ccx, t);
G
Graydon Hoare 已提交
2395
    auto vec_val = sub.bcx.build.IntToPtr(sub.val, llty);
2396
    find_scope_cx(cx).cleanups += clean(bind drop_ty(_, vec_val, t));
G
Graydon Hoare 已提交
2397 2398 2399 2400 2401 2402 2403 2404 2405 2406

    auto body = sub.bcx.build.GEP(vec_val, vec(C_int(0),
                                               C_int(abi.vec_elt_data)));
    let int i = 0;
    for (@ast.expr e in args) {
        auto src_res = trans_expr(sub.bcx, e);
        auto dst_elt = sub.bcx.build.GEP(body, vec(C_int(0), C_int(i)));
        sub = copy_ty(src_res.bcx, true, dst_elt, src_res.val, unit_ty);
        i += 1;
    }
2407 2408 2409 2410
    auto fill = sub.bcx.build.GEP(vec_val,
                                  vec(C_int(0), C_int(abi.vec_elt_fill)));
    sub.bcx.build.Store(data_sz, fill);

G
Graydon Hoare 已提交
2411 2412 2413
    ret res(sub.bcx, vec_val);
}

2414
impure fn trans_rec(@block_ctxt cx, vec[ast.field] fields,
2415
                    &ast.ann ann) -> result {
2416 2417
    auto t = node_ann_type(cx.fcx.ccx, ann);
    auto llty = type_of(cx.fcx.ccx, t);
2418
    auto rec_val = cx.build.Alloca(llty);
2419
    find_scope_cx(cx).cleanups += clean(bind drop_ty(_, rec_val, t));
2420 2421
    let int i = 0;
    auto r = res(cx, C_nil());
2422
    for (ast.field f in fields) {
2423
        auto t = ty.expr_ty(f.expr);
2424 2425
        auto src_res = trans_expr(r.bcx, f.expr);
        auto dst_elt = r.bcx.build.GEP(rec_val, vec(C_int(0), C_int(i)));
2426 2427 2428 2429
        // FIXME: calculate copy init-ness in typestate.
        r = copy_ty(src_res.bcx, true, dst_elt, src_res.val, t);
        i += 1;
    }
2430
    ret res(r.bcx, rec_val);
2431 2432
}

G
Graydon Hoare 已提交
2433

G
Graydon Hoare 已提交
2434

2435
impure fn trans_expr(@block_ctxt cx, @ast.expr e) -> result {
2436
    alt (e.node) {
2437 2438
        case (ast.expr_lit(?lit, ?ann)) {
            ret trans_lit(cx, *lit, ann);
2439 2440
        }

2441
        case (ast.expr_unary(?op, ?x, ?ann)) {
2442
            ret trans_unary(cx, op, x, ann);
2443 2444
        }

P
Patrick Walton 已提交
2445
        case (ast.expr_binary(?op, ?x, ?y, _)) {
2446
            ret trans_binary(cx, op, x, y);
2447
        }
2448

P
Patrick Walton 已提交
2449
        case (ast.expr_if(?cond, ?thn, ?els, _)) {
2450
            ret trans_if(cx, cond, thn, els);
2451 2452
        }

2453
        case (ast.expr_while(?cond, ?body, _)) {
2454
            ret trans_while(cx, cond, body);
2455 2456
        }

2457
        case (ast.expr_do_while(?body, ?cond, _)) {
2458
            ret trans_do_while(cx, body, cond);
2459 2460
        }

P
Patrick Walton 已提交
2461 2462 2463 2464
        case (ast.expr_alt(?expr, ?arms, _)) {
            ret trans_alt(cx, expr, arms);
        }

P
Patrick Walton 已提交
2465
        case (ast.expr_block(?blk, _)) {
2466
            auto sub_cx = new_scope_block_ctxt(cx, "block-expr body");
2467
            auto next_cx = new_sub_block_ctxt(cx, "next");
2468 2469 2470 2471 2472 2473 2474
            auto sub = trans_block(sub_cx, blk);

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

            ret res(next_cx, sub.val);
        }
2475

2476
        case (ast.expr_assign(?dst, ?src, ?ann)) {
2477
            auto lhs_res = trans_lval(cx, dst);
2478 2479
            check (lhs_res.is_mem);
            auto rhs_res = trans_expr(lhs_res.res.bcx, src);
2480
            auto t = node_ann_type(cx.fcx.ccx, ann);
G
Graydon Hoare 已提交
2481
            // FIXME: calculate copy init-ness in typestate.
2482
            ret copy_ty(rhs_res.bcx, false, lhs_res.res.val, rhs_res.val, t);
2483
        }
G
Graydon Hoare 已提交
2484

2485 2486 2487
        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);
2488
            check (lhs_res.is_mem);
2489
            auto lhs_val = load_scalar_or_boxed(lhs_res.res.bcx,
2490 2491
                                               lhs_res.res.val, t);
            auto rhs_res = trans_expr(lhs_res.res.bcx, src);
2492 2493
            auto v = trans_eager_binop(rhs_res.bcx, op, lhs_val, rhs_res.val);
            // FIXME: calculate copy init-ness in typestate.
2494
            ret copy_ty(rhs_res.bcx, false, lhs_res.res.val, v, t);
2495 2496
        }

2497 2498 2499 2500
        case (ast.expr_bind(?f, ?args, ?ann)) {
            ret trans_bind(cx, f, args, ann);
        }

G
Graydon Hoare 已提交
2501 2502
        case (ast.expr_call(?f, ?args, ?ann)) {
            ret trans_call(cx, f, args, ann);
2503 2504
        }

2505
        case (ast.expr_cast(?e, _, ?ann)) {
2506
            ret trans_cast(cx, e, ann);
2507
        }
G
Graydon Hoare 已提交
2508

G
Graydon Hoare 已提交
2509 2510 2511 2512
        case (ast.expr_vec(?args, ?ann)) {
            ret trans_vec(cx, args, ann);
        }

G
Graydon Hoare 已提交
2513 2514 2515
        case (ast.expr_tup(?args, ?ann)) {
            ret trans_tup(cx, args, ann);
        }
G
Graydon Hoare 已提交
2516

2517 2518 2519 2520
        case (ast.expr_rec(?args, ?ann)) {
            ret trans_rec(cx, args, ann);
        }

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

2524
        case (_) {
2525
            auto t = ty.expr_ty(e);
2526
            auto sub = trans_lval(cx, e);
2527
            ret res(sub.res.bcx,
2528
                    load_scalar_or_boxed(sub.res.bcx, sub.res.val, t));
2529
        }
2530
    }
2531
    cx.fcx.ccx.sess.unimpl("expr variant in trans_expr");
2532 2533 2534
    fail;
}

2535
// We pass structural values around the compiler "by pointer" and
2536 2537
// non-structural values (scalars and boxes) "by value". This function selects
// whether to load a pointer or pass it.
2538

2539 2540 2541 2542
fn load_scalar_or_boxed(@block_ctxt cx,
                        ValueRef v,
                        @ty.t t) -> ValueRef {
    if (ty.type_is_scalar(t) || ty.type_is_boxed(t)) {
2543
        ret cx.build.Load(v);
2544 2545
    } else {
        ret v;
2546 2547 2548
    }
}

2549
impure fn trans_log(@block_ctxt cx, @ast.expr e) -> result {
2550

2551
    auto sub = trans_expr(cx, e);
2552
    auto e_ty = ty.expr_ty(e);
2553
    alt (e_ty.struct) {
2554
        case (ty.ty_str) {
2555 2556 2557 2558
            auto v = sub.bcx.build.PtrToInt(sub.val, T_int());
            ret trans_upcall(sub.bcx,
                             "upcall_log_str",
                             vec(v));
2559 2560
        }
        case (_) {
2561 2562 2563
            ret trans_upcall(sub.bcx,
                             "upcall_log_int",
                             vec(sub.val));
2564 2565
        }
    }
2566
    fail;
2567 2568
}

2569
impure fn trans_check_expr(@block_ctxt cx, @ast.expr e) -> result {
2570 2571 2572
    auto cond_res = trans_expr(cx, e);

    // FIXME: need pretty-printer.
2573 2574
    auto V_expr_str = p2i(C_str(cx.fcx.ccx, "<expr>"));
    auto V_filename = p2i(C_str(cx.fcx.ccx, e.span.filename));
2575 2576 2577
    auto V_line = e.span.lo.line as int;
    auto args = vec(V_expr_str, V_filename, C_int(V_line));

2578
    auto fail_cx = new_sub_block_ctxt(cx, "fail");
2579 2580
    auto fail_res = trans_upcall(fail_cx, "upcall_fail", args);

2581
    auto next_cx = new_sub_block_ctxt(cx, "next");
2582 2583 2584 2585 2586 2587 2588
    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());
}

2589
impure fn trans_ret(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
2590 2591 2592
    auto r = res(cx, C_nil());
    alt (e) {
        case (some[@ast.expr](?x)) {
2593
            auto t = ty.expr_ty(x);
2594
            r = trans_expr(cx, x);
2595 2596 2597 2598 2599

            // A return is an implicit copy into a newborn anonymous
            // 'return value' in the caller frame.
            r.bcx = incr_all_refcnts(r.bcx, r.val, t).bcx;

2600
            if (ty.type_is_structural(t)) {
G
Graydon Hoare 已提交
2601 2602 2603 2604 2605 2606
                // We usually treat structurals by-pointer; in particular,
                // trans_expr will have given us a structure pointer. But in
                // this case we're about to return. LLVM wants a first-class
                // value here (which makes sense; the frame is going away!)
                r.val = r.bcx.build.Load(r.val);
            }
2607
        }
2608
        case (_) { /* fall through */  }
2609 2610
    }

2611 2612
    // Run all cleanups and back out.
    let bool more_cleanups = true;
2613
    auto cleanup_cx = cx;
2614
    while (more_cleanups) {
2615 2616
        r.bcx = trans_block_cleanups(r.bcx, cleanup_cx);
        alt (cleanup_cx.parent) {
2617
            case (parent_some(?b)) {
2618
                cleanup_cx = b;
2619 2620 2621 2622 2623 2624 2625
            }
            case (parent_none) {
                more_cleanups = false;
            }
        }
    }

2626
    alt (e) {
2627
        case (some[@ast.expr](?ex)) {
2628 2629 2630
            auto t = ty.expr_ty(ex);

            if (ty.type_is_nil(t)) {
2631 2632
                r.bcx.build.RetVoid();
                r.val = C_nil();
2633 2634 2635 2636 2637
                ret r;  // FIXME: early return needed due to typestate bug
            }

            alt (cx.fcx.llretptr) {
                case (some[ValueRef](?llptr)) {
2638 2639
                    // Generic return via tydesc + retptr.
                    r = copy_ty(r.bcx, true, llptr, r.val, t);
2640 2641 2642 2643 2644
                    r.bcx.build.RetVoid();
                }
                case (none[ValueRef]) {
                    r.val = r.bcx.build.Ret(r.val);
                }
2645
            }
2646 2647
            ret r;
        }
2648
        case (_) { /* fall through */  }
2649 2650 2651 2652
    }

    // FIXME: until LLVM has a unit type, we are moving around
    // C_nil values rather than their void type.
2653 2654
    r.bcx.build.RetVoid();
    r.val = C_nil();
2655 2656 2657
    ret r;
}

2658
impure fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
2659
    auto sub = res(cx, C_nil());
2660
    alt (s.node) {
2661
        case (ast.stmt_log(?a)) {
2662
            sub.bcx = trans_log(cx, a).bcx;
2663 2664
        }

2665
        case (ast.stmt_check_expr(?a)) {
2666
            sub.bcx = trans_check_expr(cx, a).bcx;
2667 2668
        }

2669 2670 2671 2672
        case (ast.stmt_ret(?e)) {
            sub.bcx = trans_ret(cx, e).bcx;
        }

2673
        case (ast.stmt_expr(?e)) {
2674
            sub.bcx = trans_expr(cx, e).bcx;
2675
        }
2676

2677 2678 2679
        case (ast.stmt_decl(?d)) {
            alt (d.node) {
                case (ast.decl_local(?local)) {
2680 2681 2682 2683 2684

                    // 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);
2685
                    find_scope_cx(cx).cleanups +=
2686 2687
                        clean(bind drop_slot(_, llptr, ty));

2688 2689
                    alt (local.init) {
                        case (some[@ast.expr](?e)) {
2690
                            sub = trans_expr(cx, e);
2691
                            sub = copy_ty(sub.bcx, true, llptr, sub.val, ty);
2692
                        }
2693 2694 2695 2696 2697
                        case (_) {
                            auto llty = type_of(cx.fcx.ccx, ty);
                            auto null = lib.llvm.llvm.LLVMConstNull(llty);
                            sub = res(cx, cx.build.Store(null, llptr));
                        }
2698 2699
                    }
                }
G
Graydon Hoare 已提交
2700 2701 2702
                case (ast.decl_item(?i)) {
                    trans_item(cx.fcx.ccx, *i);
                }
2703 2704
            }
        }
2705
        case (_) {
2706
            cx.fcx.ccx.sess.unimpl("stmt variant");
2707 2708
        }
    }
2709
    ret sub;
2710 2711
}

2712
fn new_builder(BasicBlockRef llbb) -> builder {
2713 2714 2715 2716 2717
    let BuilderRef llbuild = llvm.LLVMCreateBuilder();
    llvm.LLVMPositionBuilderAtEnd(llbuild, llbb);
    ret builder(llbuild);
}

2718 2719
// You probably don't want to use this one. See the
// next three functions instead.
2720
fn new_block_ctxt(@fn_ctxt cx, block_parent parent,
2721
                  bool is_scope,
2722
                  str name) -> @block_ctxt {
2723
    let vec[cleanup] cleanups = vec();
2724
    let BasicBlockRef llbb =
2725
        llvm.LLVMAppendBasicBlock(cx.llfn,
2726
                                  _str.buf(cx.ccx.names.next(name)));
2727

2728
    ret @rec(llbb=llbb,
2729
             build=new_builder(llbb),
2730
             parent=parent,
2731
             is_scope=is_scope,
2732
             mutable cleanups=cleanups,
2733 2734 2735
             fcx=cx);
}

2736 2737
// 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 {
2738 2739
    ret new_block_ctxt(fcx, parent_none, true, "function top level");
}
2740

2741 2742 2743
// 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 {
    ret new_block_ctxt(bcx.fcx, parent_some(bcx), true, n);
2744 2745
}

2746
// Use this when you're making a general CFG BB within a scope.
2747
fn new_sub_block_ctxt(@block_ctxt bcx, str n) -> @block_ctxt {
2748
    ret new_block_ctxt(bcx.fcx, parent_some(bcx), false, n);
2749
}
2750

2751

2752 2753
fn trans_block_cleanups(@block_ctxt cx,
                        @block_ctxt cleanup_cx) -> @block_ctxt {
2754
    auto bcx = cx;
2755 2756 2757 2758 2759

    if (!cleanup_cx.is_scope) {
        check (_vec.len[cleanup](cleanup_cx.cleanups) == 0u);
    }

2760
    for (cleanup c in cleanup_cx.cleanups) {
2761
        alt (c) {
2762
            case (clean(?cfn)) {
2763
                bcx = cfn(bcx).bcx;
2764 2765 2766
            }
        }
    }
2767 2768 2769
    ret bcx;
}

2770 2771 2772 2773 2774 2775 2776 2777 2778 2779
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;
                    }
2780
                    case (_) { /* fall through */ }
2781 2782
                }
            }
2783
            case (_) { /* fall through */ }
2784 2785 2786 2787
        }
    }
}

2788
impure fn trans_block(@block_ctxt cx, &ast.block b) -> result {
2789 2790
    auto bcx = cx;

2791
    for each (@ast.local local in block_locals(b)) {
2792
        auto ty = node_type(cx.fcx.ccx, local.ann);
2793 2794 2795
        auto val = bcx.build.Alloca(ty);
        cx.fcx.lllocals.insert(local.id, val);
    }
2796
    auto r = res(bcx, C_nil());
2797

2798
    for (@ast.stmt s in b.node.stmts) {
2799 2800
        r = trans_stmt(bcx, *s);
        bcx = r.bcx;
2801 2802 2803 2804 2805
        // 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;
        }
2806
    }
2807

2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820
    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());
        }
    }

2821
    bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
2822
    ret res(bcx, r.val);
2823 2824
}

2825
fn new_fn_ctxt(@crate_ctxt cx,
2826
               str name,
2827
               ValueRef llfndecl) -> @fn_ctxt {
2828

2829
    let ValueRef lltaskptr = llvm.LLVMGetParam(llfndecl, 0u);
2830
    let ValueRef llclosure = llvm.LLVMGetParam(llfndecl, 1u);
2831 2832

    let hashmap[ast.def_id, ValueRef] llargs = new_def_hash[ValueRef]();
2833 2834
    let hashmap[ast.def_id, ValueRef] llobjfields = new_def_hash[ValueRef]();
    let hashmap[ast.def_id, ValueRef] lllocals = new_def_hash[ValueRef]();
2835
    let hashmap[ast.def_id, ValueRef] lltydescs = new_def_hash[ValueRef]();
2836

2837
    ret @rec(llfn=llfndecl,
2838
             lltaskptr=lltaskptr,
2839
             llclosure=llclosure,
2840
             mutable llself=none[ValueRef],
2841
             mutable llretptr=none[ValueRef],
2842
             llargs=llargs,
2843
             llobjfields=llobjfields,
2844
             lllocals=lllocals,
2845
             lltydescs=lltydescs,
2846
             ccx=cx);
2847 2848
}

2849
// NB: this must match trans_args and type_of_fn_full.
2850 2851
fn create_llargs_for_fn_args(&@fn_ctxt cx,
                             option.t[TypeRef] ty_self,
2852
                             @ty.t ret_ty,
2853
                             &vec[ast.arg] args,
2854
                             &vec[ast.ty_param] ty_params) {
2855
    let uint arg_n = 1u;
2856

2857 2858 2859 2860 2861 2862 2863
    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;
    }

2864 2865 2866 2867 2868
    if (ty.type_has_dynamic_size(ret_ty)) {
        cx.llretptr = some[ValueRef](llvm.LLVMGetParam(cx.llfn, arg_n));
        arg_n += 1u;
    }

2869 2870 2871 2872 2873 2874 2875
    alt (ty_self) {
        case (some[TypeRef](_)) {
            auto llself = llvm.LLVMGetParam(cx.llfn, arg_n);
            check (llself as int != 0);
            cx.llself = some[ValueRef](llself);
            arg_n += 1u;
        }
2876 2877 2878 2879
        case (_) {
            // llclosure, we don't know what it is.
            arg_n += 1u;
        }
2880 2881
    }

2882 2883 2884 2885 2886 2887 2888 2889
    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;
    }
}

2890 2891 2892 2893
// 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.

2894 2895 2896 2897
impure fn copy_args_to_allocas(@block_ctxt cx,
                               option.t[TypeRef] ty_self,
                               vec[ast.arg] args,
                               vec[ty.arg] arg_tys) {
2898 2899 2900

    let uint arg_n = 0u;

2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914
    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 (_) {
        }
    }

2915
    for (ast.arg aarg in args) {
2916 2917 2918 2919 2920 2921 2922 2923 2924
        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);
        }

2925 2926 2927 2928
        arg_n += 1u;
    }
}

2929 2930 2931 2932 2933
fn is_terminated(@block_ctxt cx) -> bool {
    auto inst = llvm.LLVMGetLastInstruction(cx.llbb);
    ret llvm.LLVMIsATerminatorInst(inst) as int != 0;
}

2934 2935 2936
fn arg_tys_of_fn(ast.ann ann) -> vec[ty.arg] {
    alt (ty.ann_to_type(ann).struct) {
        case (ty.ty_fn(?arg_tys, _)) {
2937 2938 2939 2940 2941 2942
            ret arg_tys;
        }
    }
    fail;
}

2943 2944
fn ret_ty_of_fn_ty(@ty.t t) -> @ty.t {
    alt (t.struct) {
2945
        case (ty.ty_fn(_, ?ret_ty)) {
2946 2947 2948 2949 2950 2951
            ret ret_ty;
        }
    }
    fail;
}

2952 2953 2954 2955 2956

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

2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994
fn create_llobjfields_for_fields(@block_ctxt cx, ValueRef llself) {

    let vec[TypeRef] llfield_tys = vec();

    for (ast.obj_field f in cx.fcx.ccx.obj_fields) {
        llfield_tys += node_type(cx.fcx.ccx, f.ann);
    }

    let TypeRef llfields_ty = T_struct(llfield_tys);
    let TypeRef lltydesc_ty = T_ptr(T_tydesc());
    let TypeRef llobj_body_ty = T_struct(vec(lltydesc_ty,
                                             llfields_ty));
    let TypeRef llobj_box_ty = T_ptr(T_box(llobj_body_ty));

    auto box_cell =
        cx.build.GEP(llself,
                     vec(C_int(0),
                         C_int(abi.obj_field_box)));

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

    box_ptr = cx.build.PointerCast(box_ptr, llobj_box_ty);

    auto obj_fields = cx.build.GEP(box_ptr,
                                   vec(C_int(0),
                                       C_int(abi.box_rc_field_body),
                                       C_int(abi.obj_body_elt_fields)));

    let int i = 0;
    for (ast.obj_field f in cx.fcx.ccx.obj_fields) {
        let ValueRef llfield = cx.build.GEP(obj_fields,
                                            vec(C_int(0),
                                                C_int(i)));
        cx.fcx.llobjfields.insert(f.id, llfield);
        i += 1;
    }
}

2995
impure fn trans_fn(@crate_ctxt cx, &ast._fn f, ast.def_id fid,
2996
                   option.t[TypeRef] ty_self,
2997
                   &vec[ast.ty_param] ty_params, &ast.ann ann) {
2998

2999 3000 3001
    auto llfndecl = cx.item_ids.get(fid);
    cx.item_names.insert(cx.path, llfndecl);

3002
    auto fcx = new_fn_ctxt(cx, cx.path, llfndecl);
3003
    create_llargs_for_fn_args(fcx, ty_self, ret_ty_of_fn(ann),
3004
                              f.inputs, ty_params);
3005
    auto bcx = new_top_block_ctxt(fcx);
3006

3007 3008 3009 3010 3011 3012 3013 3014 3015 3016
    copy_args_to_allocas(bcx, ty_self, f.inputs,
                         arg_tys_of_fn(ann));

    alt (fcx.llself) {
        case (some[ValueRef](?llself)) {
            create_llobjfields_for_fields(bcx, llself);
        }
        case (_) {
        }
    }
3017

3018 3019
    auto res = trans_block(bcx, f.body);
    if (!is_terminated(res.bcx)) {
3020 3021
        // FIXME: until LLVM has a unit type, we are moving around
        // C_nil values rather than their void type.
3022
        res.bcx.build.RetVoid();
3023
    }
3024 3025
}

3026 3027
impure fn trans_vtbl(@crate_ctxt cx, TypeRef self_ty,
                     &ast._obj ob,
3028
                     &vec[ast.ty_param] ty_params) -> ValueRef {
G
Graydon Hoare 已提交
3029
    let vec[ValueRef] methods = vec();
3030 3031 3032 3033 3034 3035 3036 3037 3038

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

3040 3041 3042 3043 3044 3045 3046 3047 3048
        auto llfnty = T_nil();
        alt (node_ann_type(cx, m.node.ann).struct) {
            case (ty.ty_fn(?inputs, ?output)) {
                llfnty = type_of_fn_full(cx,
                                         some[TypeRef](self_ty),
                                         inputs, output);
            }
        }

3049 3050 3051 3052
        let @crate_ctxt mcx = @rec(path=cx.path + "." + m.node.ident
                                   with *cx);

        let str s = cx.names.next("_rust_method") + "." + mcx.path;
3053 3054 3055
        let ValueRef llfn = decl_fastcall_fn(cx.llmod, s, llfnty);
        cx.item_ids.insert(m.node.id, llfn);

3056 3057
        trans_fn(mcx, m.node.meth, m.node.id, some[TypeRef](self_ty),
                 ty_params, m.node.ann);
3058
        methods += llfn;
G
Graydon Hoare 已提交
3059
    }
3060 3061 3062 3063 3064 3065
    auto vtbl = C_struct(methods);
    auto gvar = llvm.LLVMAddGlobal(cx.llmod,
                                   val_ty(vtbl),
                                   _str.buf("_rust_vtbl" + "." + cx.path));
    llvm.LLVMSetInitializer(gvar, vtbl);
    llvm.LLVMSetGlobalConstant(gvar, True);
3066 3067
    llvm.LLVMSetLinkage(gvar, lib.llvm.LLVMPrivateLinkage
                        as llvm.Linkage);
3068
    ret gvar;
G
Graydon Hoare 已提交
3069 3070
}

3071
impure fn trans_obj(@crate_ctxt cx, &ast._obj ob, ast.def_id oid,
3072
                    &vec[ast.ty_param] ty_params, &ast.ann ann) {
3073 3074 3075 3076

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

3077
    // Translate obj ctor args to function arguments.
3078 3079 3080 3081 3082 3083 3084 3085 3086
    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));
    }

    auto fcx = new_fn_ctxt(cx, cx.path, llctor_decl);
3087
    create_llargs_for_fn_args(fcx, none[TypeRef], ret_ty_of_fn(ann),
3088
                              fn_args, ty_params);
3089 3090 3091

    auto bcx = new_top_block_ctxt(fcx);

3092
    let vec[ty.arg] arg_tys = arg_tys_of_fn(ann);
3093
    copy_args_to_allocas(bcx, none[TypeRef], fn_args, arg_tys);
3094

3095 3096 3097
    auto llself_ty = type_of(cx, ret_ty_of_fn(ann));
    auto pair = bcx.build.Alloca(llself_ty);
    auto vtbl = trans_vtbl(cx, llself_ty, ob, ty_params);
3098 3099 3100
    auto pair_vtbl = bcx.build.GEP(pair,
                                   vec(C_int(0),
                                       C_int(abi.obj_field_vtbl)));
3101 3102 3103
    auto pair_box = bcx.build.GEP(pair,
                                  vec(C_int(0),
                                      C_int(abi.obj_field_box)));
3104
    bcx.build.Store(vtbl, pair_vtbl);
3105

3106 3107
    let TypeRef llbox_ty = T_ptr(T_box(T_struct(vec(T_ptr(T_tydesc()),
                                                    T_nil()))));
3108 3109 3110 3111 3112 3113 3114 3115 3116
    if (_vec.len[ty.arg](arg_tys) == 0u) {
        // Store null into pair, if no args.
        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) {
            append[@ty.t](obj_fields, a.ty);
        }
3117 3118

        // Synthesize an obj body type.
3119 3120 3121
        let @ty.t fields_ty = ty.plain_ty(ty.ty_tup(obj_fields));
        let TypeRef llfields_ty = type_of(bcx.fcx.ccx, fields_ty);
        let TypeRef llobj_body_ty =
3122
            T_ptr(T_box(T_struct(vec(T_ptr(T_tydesc()),
3123
                                     llfields_ty))));
3124 3125

        // Malloc a box for the body.
3126 3127 3128 3129 3130 3131 3132 3133 3134
        auto r = trans_malloc_inner(bcx, llobj_body_ty);
        auto box = r.val;
        auto rc = r.bcx.build.GEP(box,
                                  vec(C_int(0),
                                      C_int(abi.box_rc_field_refcnt)));
        auto body = r.bcx.build.GEP(box,
                                    vec(C_int(0),
                                        C_int(abi.box_rc_field_body)));
        r.bcx.build.Store(C_int(1), rc);
3135

3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153
        // Store body tydesc.
        auto body_tydesc =
            r.bcx.build.GEP(body,
                            vec(C_int(0),
                                C_int(abi.obj_body_elt_tydesc)));

        auto fields_tydesc = get_tydesc(r.bcx, fields_ty);
        r.bcx.build.Store(fields_tydesc, body_tydesc);

        // Copy args into body fields.
        auto body_fields =
            r.bcx.build.GEP(body,
                            vec(C_int(0),
                                C_int(abi.obj_body_elt_fields)));

        let int i = 0;
        for (ast.obj_field f in ob.fields) {
            auto arg = r.bcx.fcx.llargs.get(f.id);
3154
            arg = load_scalar_or_boxed(r.bcx, arg, arg_tys.(i).ty);
3155 3156 3157 3158 3159
            auto field = r.bcx.build.GEP(body_fields,
                                         vec(C_int(0),C_int(i)));
            r = copy_ty(r.bcx, true, field, arg, arg_tys.(i).ty);
            i += 1;
        }
3160

3161
        // Store box ptr in outer pair.
3162 3163 3164
        auto p = r.bcx.build.PointerCast(box, llbox_ty);
        r.bcx.build.Store(p, pair_box);
    }
3165
    bcx.build.Ret(bcx.build.Load(pair));
3166 3167
}

3168
fn trans_tag_variant(@crate_ctxt cx, ast.def_id tag_id,
3169 3170
                     &ast.variant variant, int index,
                     &vec[ast.ty_param] ty_params) {
3171
    if (_vec.len[ast.variant_arg](variant.args) == 0u) {
3172 3173 3174
        ret;    // nullary constructors are just constants
    }

3175 3176 3177 3178 3179 3180 3181 3182 3183 3184
    // 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));
    }

3185
    check (cx.item_ids.contains_key(variant.id));
3186 3187
    let ValueRef llfndecl = cx.item_ids.get(variant.id);

3188
    auto fcx = new_fn_ctxt(cx, cx.path, llfndecl);
3189 3190
    create_llargs_for_fn_args(fcx, none[TypeRef], ret_ty_of_fn(variant.ann),
                              fn_args, ty_params);
3191

3192 3193 3194
    auto bcx = new_top_block_ctxt(fcx);

    auto arg_tys = arg_tys_of_fn(variant.ann);
3195
    copy_args_to_allocas(bcx, none[TypeRef], fn_args, arg_tys);
3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211

    auto info = cx.tags.get(tag_id);

    auto lltagty = T_struct(vec(T_int(), T_array(T_i8(), info.size)));

    // FIXME: better name.
    llvm.LLVMAddTypeName(cx.llmod, _str.buf("tag"), lltagty);

    auto lltagptr = bcx.build.Alloca(lltagty);
    auto lldiscrimptr = bcx.build.GEP(lltagptr, vec(C_int(0), C_int(0)));
    bcx.build.Store(C_int(index), lldiscrimptr);

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

    // First, generate the union type.
    let vec[TypeRef] llargtys = vec();
3212
    for (ty.arg arg in arg_tys) {
3213 3214 3215 3216 3217 3218 3219 3220
        llargtys += vec(type_of(cx, arg.ty));
    }

    auto llunionty = T_struct(llargtys);
    auto llunionptr = bcx.build.TruncOrBitCast(llblobptr, T_ptr(llunionty));

    i = 0u;
    for (ast.variant_arg va in variant.args) {
3221
        auto llargval = bcx.build.Load(fcx.llargs.get(va.id));
3222 3223 3224 3225 3226 3227 3228 3229 3230 3231
        auto lldestptr = bcx.build.GEP(llunionptr,
                                       vec(C_int(0), C_int(i as int)));

        bcx.build.Store(llargval, lldestptr);
        i += 1u;
    }

    auto lltagval = bcx.build.Load(lltagptr);
    bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
    bcx.build.Ret(lltagval);
3232 3233
}

3234
impure fn trans_item(@crate_ctxt cx, &ast.item item) {
3235
    alt (item.node) {
3236
        case (ast.item_fn(?name, ?f, ?tps, ?fid, ?ann)) {
3237
            auto sub_cx = @rec(path=cx.path + "." + name with *cx);
3238
            trans_fn(sub_cx, f, fid, none[TypeRef], tps, ann);
3239
        }
3240
        case (ast.item_obj(?name, ?ob, ?tps, ?oid, ?ann)) {
3241 3242
            auto sub_cx = @rec(path=cx.path + "." + name,
                               obj_fields=ob.fields with *cx);
3243
            trans_obj(sub_cx, ob, oid, tps, ann);
3244
        }
3245 3246
        case (ast.item_mod(?name, ?m, _)) {
            auto sub_cx = @rec(path=cx.path + "." + name with *cx);
3247
            trans_mod(sub_cx, m);
3248
        }
3249
        case (ast.item_tag(?name, ?variants, ?tps, ?tag_id)) {
3250
            auto sub_cx = @rec(path=cx.path + "." + name with *cx);
3251
            auto i = 0;
3252
            for (ast.variant variant in variants) {
3253
                trans_tag_variant(sub_cx, tag_id, variant, i, tps);
3254
                i += 1;
3255 3256
            }
        }
3257
        case (_) { /* fall through */ }
3258 3259 3260
    }
}

3261
impure fn trans_mod(@crate_ctxt cx, &ast._mod m) {
3262 3263
    for (@ast.item item in m.items) {
        trans_item(cx, *item);
3264 3265 3266
    }
}

3267 3268 3269 3270 3271 3272 3273 3274
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));
}

3275 3276 3277 3278 3279 3280 3281
fn decl_fn_and_pair(@crate_ctxt cx,
                    str kind,
                    str name,
                    &ast.ann ann,
                    ast.def_id id) {

    auto llpairty = node_type(cx, ann);
3282
    auto llfty = get_pair_fn_ty(llpairty);
3283 3284 3285 3286 3287 3288 3289 3290 3291 3292

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

    // Declare the global constant pair that points to it.
    let str ps = cx.names.next("_rust_" + kind + "_pair") + "." + name;
    let ValueRef gvar = llvm.LLVMAddGlobal(cx.llmod, llpairty,
                                           _str.buf(ps));
    auto pair = C_struct(vec(llfn,
3293
                             C_null(T_opaque_closure_ptr())));
3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304

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

    cx.item_ids.insert(id, llfn);
    cx.fn_pairs.insert(id, gvar);
}

3305

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

3308
    alt (i.node) {
3309 3310
        case (ast.item_fn(?name, ?f, _, ?fid, ?ann)) {
            // TODO: type-params
3311
            cx.items.insert(fid, i);
3312 3313 3314
            if (! cx.obj_methods.contains_key(fid)) {
                decl_fn_and_pair(cx, "fn", name, ann, fid);
            }
3315 3316
        }

3317 3318 3319
        case (ast.item_obj(?name, ?ob, _, ?oid, ?ann)) {
            // TODO: type-params
            cx.items.insert(oid, i);
3320 3321 3322 3323
            decl_fn_and_pair(cx, "obj_ctor", name, ann, oid);
            for (@ast.method m in ob.methods) {
                cx.obj_methods.insert(m.node.id, ());
            }
3324 3325
        }

3326 3327 3328 3329
        case (ast.item_const(?name, _, _, ?cid, _)) {
            cx.items.insert(cid, i);
        }

3330 3331 3332
        case (ast.item_mod(?name, ?m, ?mid)) {
            cx.items.insert(mid, i);
        }
3333 3334 3335 3336

        case (ast.item_tag(_, ?variants, _, ?tag_id)) {
            auto vi = new_def_hash[uint]();
            auto navi = new_def_hash[uint]();
3337 3338
            let vec[tup(ast.def_id,arity)] variant_info = vec();
            cx.tags.insert(tag_id, @rec(th=mk_type_handle(),
3339 3340
                                        mutable variants=variant_info,
                                        mutable size=0u));
3341
            cx.items.insert(tag_id, i);
3342 3343
        }

3344
        case (_) { /* fall through */ }
3345 3346 3347 3348 3349
    }
    ret cx;
}


3350
fn collect_items(@crate_ctxt cx, @ast.crate crate) {
3351

3352 3353
    let fold.ast_fold[@crate_ctxt] fld =
        fold.new_identity_fold[@crate_ctxt]();
3354 3355 3356 3357

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

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

3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390
fn collect_tag_ctor(&@crate_ctxt cx, @ast.item i) -> @crate_ctxt {

    alt (i.node) {

        case (ast.item_tag(_, ?variants, _, _)) {
            for (ast.variant variant in variants) {
                if (_vec.len[ast.variant_arg](variant.args) != 0u) {
                    decl_fn_and_pair(cx, "tag", variant.name,
                                     variant.ann, variant.id);
                }
            }
        }

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


3391 3392 3393 3394 3395 3396
// The tag type resolution pass, which determines all the LLVM types that
// correspond to each tag type in the crate.

fn resolve_tag_types_for_item(&@crate_ctxt cx, @ast.item i) -> @crate_ctxt {
    alt (i.node) {
        case (ast.item_tag(_, ?variants, _, ?tag_id)) {
3397 3398
            auto max_align = 0u;
            auto max_size = 0u;
3399 3400 3401 3402 3403 3404

            auto info = cx.tags.get(tag_id);
            let vec[tup(ast.def_id,arity)] variant_info = vec();

            for (ast.variant variant in variants) {
                auto arity_info;
3405
                if (_vec.len[ast.variant_arg](variant.args) > 0u) {
3406 3407 3408 3409 3410 3411 3412
                    auto llvariantty = type_of_variant(cx, variant);
                    auto align = llvm.LLVMPreferredAlignmentOfType(cx.td.lltd,
                                                                 llvariantty);
                    auto size = llvm.LLVMStoreSizeOfType(cx.td.lltd,
                                                         llvariantty) as uint;
                    if (max_align < align) { max_align = align; }
                    if (max_size < size) { max_size = size; }
3413 3414 3415 3416 3417 3418 3419 3420 3421 3422

                    arity_info = n_ary;
                } else {
                    arity_info = nullary;
                }

                variant_info += vec(tup(variant.id, arity_info));
            }

            info.variants = variant_info;
3423
            info.size = max_size;
3424

3425 3426 3427
            // FIXME: alignment is wrong here, manually insert padding I
            // guess :(
            auto tag_ty = T_struct(vec(T_int(), T_array(T_i8(), max_size)));
3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438
            auto th = cx.tags.get(tag_id).th.llth;
            llvm.LLVMRefineType(llvm.LLVMResolveTypeHandle(th), tag_ty);
        }
        case (_) {
            // fall through
        }
    }

    ret cx;
}

3439 3440 3441 3442 3443 3444 3445 3446 3447 3448
fn resolve_tag_types(@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 resolve_tag_types_for_item(_,_)
                with *fld );

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

3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467
// 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 info = cx.tags.get(tag_id);

            auto tag_ty = llvm.LLVMResolveTypeHandle(info.th.llth);
            check (llvm.LLVMCountStructElementTypes(tag_ty) == 2u);
            auto elts = vec(0 as TypeRef, 0 as TypeRef);
            llvm.LLVMGetStructElementTypes(tag_ty, _vec.buf[TypeRef](elts));
            auto union_ty = elts.(1);

            auto i = 0u;
            while (i < _vec.len[tup(ast.def_id,arity)](info.variants)) {
                auto variant_info = info.variants.(i);
                alt (variant_info._1) {
                    case (nullary) {
                        // Nullary tags become constants.
3468
                        auto union_val = C_zero_byte_arr(info.size as uint);
3469
                        auto val = C_struct(vec(C_int(i as int), union_val));
G
Graydon Hoare 已提交
3470

3471 3472 3473 3474 3475
                        // FIXME: better name
                        auto gvar = llvm.LLVMAddGlobal(cx.llmod, val_ty(val),
                                                       _str.buf("tag"));
                        llvm.LLVMSetInitializer(gvar, val);
                        llvm.LLVMSetGlobalConstant(gvar, True);
3476 3477 3478
                        llvm.LLVMSetLinkage(gvar,
                                            lib.llvm.LLVMPrivateLinkage
                                            as llvm.Linkage);
3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489
                        cx.item_ids.insert(variant_info._0, gvar);
                    }
                    case (n_ary) {
                        // N-ary tags are treated as functions and generated
                        // later.
                    }
                }

                i += 1u;
            }
        }
3490 3491 3492 3493 3494 3495 3496 3497

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

3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514
        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);
}

3515 3516 3517 3518
fn p2i(ValueRef v) -> ValueRef {
    ret llvm.LLVMConstPtrToInt(v, T_int());
}

3519
fn trans_exit_task_glue(@crate_ctxt cx) {
3520 3521 3522 3523 3524 3525 3526
    let vec[TypeRef] T_args = vec();
    let vec[ValueRef] V_args = vec();

    auto llfn = cx.glues.exit_task_glue;
    let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 0u);
    auto fcx = @rec(llfn=llfn,
                    lltaskptr=lltaskptr,
3527
                    llclosure=C_null(T_opaque_closure_ptr()),
3528
                    mutable llself=none[ValueRef],
3529
                    mutable llretptr=none[ValueRef],
3530
                    llargs=new_def_hash[ValueRef](),
3531
                    llobjfields=new_def_hash[ValueRef](),
3532
                    lllocals=new_def_hash[ValueRef](),
3533
                    lltydescs=new_def_hash[ValueRef](),
3534
                    ccx=cx);
3535

3536
    auto bcx = new_top_block_ctxt(fcx);
3537
    trans_upcall(bcx, "upcall_exit", V_args);
3538
    bcx.build.RetVoid();
3539 3540
}

3541 3542 3543
fn create_typedefs(@crate_ctxt cx) {
    llvm.LLVMAddTypeName(cx.llmod, _str.buf("rust_crate"), T_crate());
    llvm.LLVMAddTypeName(cx.llmod, _str.buf("rust_task"), T_task());
3544
    llvm.LLVMAddTypeName(cx.llmod, _str.buf("rust_tydesc"), T_tydesc());
3545 3546
}

3547
fn crate_constant(@crate_ctxt cx) -> ValueRef {
3548 3549

    let ValueRef crate_ptr =
3550
        llvm.LLVMAddGlobal(cx.llmod, T_crate(),
3551 3552 3553 3554 3555 3556 3557 3558 3559 3560
                           _str.buf("rust_crate"));

    let ValueRef crate_addr = p2i(crate_ptr);

    let ValueRef activate_glue_off =
        llvm.LLVMConstSub(p2i(cx.glues.activate_glue), crate_addr);

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

3561 3562
    let ValueRef exit_task_glue_off =
        llvm.LLVMConstSub(p2i(cx.glues.exit_task_glue), crate_addr);
3563 3564 3565

    let ValueRef crate_val =
        C_struct(vec(C_null(T_int()),     // ptrdiff_t image_base_off
3566
                     p2i(crate_ptr),      // uintptr_t self_addr
3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584
                     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
                     C_null(T_int())      // int n_libs
                     ));

    llvm.LLVMSetInitializer(crate_ptr, crate_val);
    ret crate_ptr;
}

3585
fn trans_main_fn(@crate_ctxt cx, ValueRef llcrate) {
3586 3587 3588
    auto T_main_args = vec(T_int(), T_int());
    auto T_rust_start_args = vec(T_int(), T_int(), T_int(), T_int());

3589 3590 3591 3592 3593 3594 3595
    auto main_name;
    if (_str.eq(std.os.target_os(), "win32")) {
        main_name = "WinMain@16";
    } else {
        main_name = "main";
    }

3596
    auto llmain =
3597
        decl_cdecl_fn(cx.llmod, main_name, T_fn(T_main_args, T_int()));
3598

3599 3600
    auto llrust_start = decl_cdecl_fn(cx.llmod, "rust_start",
                                      T_fn(T_rust_start_args, T_int()));
3601 3602 3603

    auto llargc = llvm.LLVMGetParam(llmain, 0u);
    auto llargv = llvm.LLVMGetParam(llmain, 1u);
3604 3605
    check (cx.item_names.contains_key("_rust.main"));
    auto llrust_main = cx.item_names.get("_rust.main");
3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616

    //
    // 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(""));
3617
    auto b = new_builder(llbb);
3618 3619 3620 3621 3622 3623

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

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

3624 3625
fn declare_intrinsics(ModuleRef llmod) -> hashmap[str,ValueRef] {

3626
    let vec[TypeRef] T_trap_args = vec();
3627 3628 3629 3630
    let vec[TypeRef] T_memcpy32_args = vec(T_ptr(T_i8()), T_ptr(T_i8()),
                                           T_i32(), T_i32(), T_i1());
    let vec[TypeRef] T_memcpy64_args = vec(T_ptr(T_i8()), T_ptr(T_i8()),
                                           T_i32(), T_i32(), T_i1());
3631 3632
    auto trap = decl_cdecl_fn(llmod, "llvm.trap",
                              T_fn(T_trap_args, T_void()));
3633 3634 3635 3636
    auto memcpy32 = decl_cdecl_fn(llmod, "llvm.memcpy.p0i8.p0i8.i32",
                                  T_fn(T_memcpy32_args, T_void()));
    auto memcpy64 = decl_cdecl_fn(llmod, "llvm.memcpy.p0i8.p0i8.i64",
                                  T_fn(T_memcpy64_args, T_void()));
3637 3638 3639

    auto intrinsics = new_str_hash[ValueRef]();
    intrinsics.insert("llvm.trap", trap);
3640 3641
    intrinsics.insert("llvm.memcpy.p0i8.p0i8.i32", memcpy32);
    intrinsics.insert("llvm.memcpy.p0i8.p0i8.i64", memcpy64);
3642
    ret intrinsics;
3643 3644
}

3645 3646 3647 3648 3649 3650 3651 3652
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.
}

3653 3654 3655 3656 3657
fn make_no_op_type_glue(ModuleRef llmod) -> ValueRef {
    auto ty = T_fn(vec(T_taskptr(), T_ptr(T_i8())), T_void());
    auto fun = decl_fastcall_fn(llmod, "_rust_no_op_type_glue", ty);
    auto bb_name = _str.buf("_rust_no_op_type_glue_bb");
    auto llbb = llvm.LLVMAppendBasicBlock(fun, bb_name);
3658
    new_builder(llbb).RetVoid();
3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683
    ret fun;
}

fn make_glues(ModuleRef llmod) -> @glue_fns {
    ret @rec(activate_glue = decl_glue(llmod, abi.activate_glue_name()),
             yield_glue = decl_glue(llmod, abi.yield_glue_name()),
             /*
              * Note: the signature passed to decl_cdecl_fn here looks unusual
              * because it is. It corresponds neither to an upcall signature
              * nor a normal rust-ABI signature. In fact it is a fake
              * signature, that exists solely to acquire the task pointer as
              * an argument to the upcall. It so happens that the runtime sets
              * up the task pointer as the sole incoming argument to the frame
              * that we return into when returning to the exit task glue. So
              * this is the signature required to retrieve it.
              */
             exit_task_glue = decl_cdecl_fn(llmod, abi.exit_task_glue_name(),
                                            T_fn(vec(T_taskptr()), T_void())),

             upcall_glues =
              _vec.init_fn[ValueRef](bind decl_upcall(llmod, _),
                                     abi.n_upcall_glues as uint),
             no_op_type_glue = make_no_op_type_glue(llmod));
}

3684 3685
fn trans_crate(session.session sess, @ast.crate crate, str output,
               bool shared) {
3686 3687 3688 3689
    auto llmod =
        llvm.LLVMModuleCreateWithNameInContext(_str.buf("rust_out"),
                                               llvm.LLVMGetGlobalContext());

3690 3691
    llvm.LLVMSetDataLayout(llmod, _str.buf(x86.get_data_layout()));
    llvm.LLVMSetTarget(llmod, _str.buf(x86.get_target_triple()));
3692
    auto td = mk_target_data(x86.get_data_layout());
3693

3694 3695
    llvm.LLVMSetModuleInlineAsm(llmod, _str.buf(x86.get_module_asm()));

3696
    auto intrinsics = declare_intrinsics(llmod);
3697

3698
    auto glues = make_glues(llmod);
3699 3700 3701
    auto hasher = ty.hash_ty;
    auto eqer = ty.eq_ty;
    auto tydescs = map.mk_hashmap[@ty.t,ValueRef](hasher, eqer);
3702
    let vec[ast.obj_field] obj_fields = vec();
3703

3704 3705
    auto cx = @rec(sess = sess,
                   llmod = llmod,
3706
                   td = td,
3707
                   upcalls = new_str_hash[ValueRef](),
3708
                   intrinsics = intrinsics,
3709 3710
                   item_names = new_str_hash[ValueRef](),
                   item_ids = new_def_hash[ValueRef](),
3711
                   items = new_def_hash[@ast.item](),
3712
                   tags = new_def_hash[@tag_info](),
3713 3714
                   fn_pairs = new_def_hash[ValueRef](),
                   obj_methods = new_def_hash[()](),
3715
                   tydescs = tydescs,
3716
                   obj_fields = obj_fields,
3717
                   glues = glues,
3718
                   names = namegen(0),
3719
                   path = "_rust");
3720

3721 3722
    create_typedefs(cx);

3723
    collect_items(cx, crate);
3724
    resolve_tag_types(cx, crate);
3725
    collect_tag_ctors(cx, crate);
3726
    trans_constants(cx, crate);
3727

3728
    trans_mod(cx, crate.node.module);
3729
    trans_exit_task_glue(cx);
3730 3731 3732
    if (!shared) {
        trans_main_fn(cx, crate_constant(cx));
    }
3733

3734 3735
    check_module(llmod);

3736
    llvm.LLVMWriteBitcodeToFile(llmod, _str.buf(output));
3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749
    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
// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//