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

10
import front.ast;
11
import driver.session;
12
import middle.typeck;
13
import back.x86;
14 15
import back.abi;

16
import util.common;
17
import util.common.istr;
18
import util.common.new_def_hash;
19
import util.common.new_str_hash;
20 21 22

import lib.llvm.llvm;
import lib.llvm.builder;
23 24
import lib.llvm.type_handle;
import lib.llvm.mk_type_handle;
25 26 27
import lib.llvm.llvm.ModuleRef;
import lib.llvm.llvm.ValueRef;
import lib.llvm.llvm.TypeRef;
28
import lib.llvm.llvm.TypeHandleRef;
29 30
import lib.llvm.llvm.BuilderRef;
import lib.llvm.llvm.BasicBlockRef;
31

32 33
import lib.llvm.False;
import lib.llvm.True;
34

35 36 37 38 39 40 41
state obj namegen(mutable int i) {
    fn next(str prefix) -> str {
        i += 1;
        ret prefix + istr(i);
    }
}

42 43
type glue_fns = rec(ValueRef activate_glue,
                    ValueRef yield_glue,
44
                    ValueRef exit_task_glue,
45 46
                    vec[ValueRef] upcall_glues);

47
tag arity { nullary; n_ary; }
48
type tag_info = rec(type_handle th,
49
                    mutable vec[tup(ast.def_id,arity)] variants);
50

51
state type crate_ctxt = rec(session.session sess,
52
                            ModuleRef llmod,
53
                            hashmap[str, ValueRef] upcalls,
54
                            hashmap[str, ValueRef] intrinsics,
55 56
                            hashmap[str, ValueRef] item_names,
                            hashmap[ast.def_id, ValueRef] item_ids,
57
                            hashmap[ast.def_id, @ast.item] items,
58
                            hashmap[ast.def_id, @tag_info] tags,
59 60 61
                            @glue_fns glues,
                            namegen names,
                            str path);
62

63 64
state type fn_ctxt = rec(ValueRef llfn,
                         ValueRef lltaskptr,
65
                         hashmap[ast.def_id, ValueRef] llargs,
66
                         hashmap[ast.def_id, ValueRef] lllocals,
67
                         @crate_ctxt ccx);
68

69
tag cleanup {
70
    clean(fn(@block_ctxt cx) -> result);
71 72 73 74
}

state type block_ctxt = rec(BasicBlockRef llbb,
                            builder build,
75
                            block_parent parent,
76 77 78
                            mutable vec[cleanup] cleanups,
                            @fn_ctxt fcx);

79 80 81 82 83 84 85 86
// 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);
}

87

88 89 90 91 92 93 94 95
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);
}

96 97 98 99 100 101 102 103 104 105 106
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));
}
107 108 109 110


// LLVM type constructors.

111 112 113 114 115 116 117 118 119 120 121
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.
122 123 124
    ret llvm.LLVMVoidType();
}

125 126 127 128 129
fn T_nil() -> TypeRef {
    // NB: See above in T_void().
    ret llvm.LLVMInt1Type();
}

130 131 132 133
fn T_i1() -> TypeRef {
    ret llvm.LLVMInt1Type();
}

134 135 136 137 138 139 140 141 142
fn T_i8() -> TypeRef {
    ret llvm.LLVMInt8Type();
}

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

fn T_i32() -> TypeRef {
143 144 145
    ret llvm.LLVMInt32Type();
}

146 147 148 149
fn T_i64() -> TypeRef {
    ret llvm.LLVMInt64Type();
}

150 151 152 153 154 155 156 157
fn T_f32() -> TypeRef {
    ret llvm.LLVMFloatType();
}

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

158 159 160 161
fn T_bool() -> TypeRef {
    ret T_i1();
}

162 163 164 165 166
fn T_int() -> TypeRef {
    // FIXME: switch on target type.
    ret T_i32();
}

167 168 169 170
fn T_char() -> TypeRef {
    ret T_i32();
}

171 172 173 174
fn T_fn(vec[TypeRef] inputs, TypeRef output) -> TypeRef {
    ret llvm.LLVMFunctionType(output,
                              _vec.buf[TypeRef](inputs),
                              _vec.len[TypeRef](inputs),
175 176 177 178 179 180 181 182 183 184 185 186 187
                              False);
}

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

188 189 190 191 192
fn T_union(vec[TypeRef] elts) -> TypeRef {
    ret llvm.LLVMUnionType(_vec.buf[TypeRef](elts),
                           _vec.len[TypeRef](elts));
}

193 194 195 196 197 198
fn T_opaque() -> TypeRef {
    ret llvm.LLVMOpaqueType();
}

fn T_task() -> TypeRef {
    ret T_struct(vec(T_int(),      // Refcount
199 200 201 202 203 204 205 206 207 208
                     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
                     ));
}

209 210 211 212
fn T_array(TypeRef t, uint n) -> TypeRef {
    ret llvm.LLVMArrayType(t, n);
}

213 214 215 216 217
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
218 219 220
                     ));
}

221 222
fn T_str() -> TypeRef {
    ret T_vec(T_i8());
223 224
}

225 226 227 228
fn T_box(TypeRef t) -> TypeRef {
    ret T_struct(vec(T_int(), t));
}

229 230 231 232 233 234 235 236 237 238 239 240 241 242
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
243
                     T_int()       // int n_libs
244 245 246
                     ));
}

247 248 249 250 251 252
fn T_double() -> TypeRef {
    ret llvm.LLVMDoubleType();
}

fn T_taskptr() -> TypeRef {
    ret T_ptr(T_task());
253 254
}

255
fn type_of(@crate_ctxt cx, @typeck.ty t) -> TypeRef {
256 257 258 259 260
    let TypeRef llty = type_of_inner(cx, t);
    check (llty as int != 0);
    ret llty;
}

261
fn type_of_inner(@crate_ctxt cx, @typeck.ty t) -> TypeRef {
262 263 264 265 266 267
    alt (t.struct) {
        case (typeck.ty_nil) { ret T_nil(); }
        case (typeck.ty_bool) { ret T_bool(); }
        case (typeck.ty_int) { ret T_int(); }
        case (typeck.ty_uint) { ret T_int(); }
        case (typeck.ty_machine(?tm)) {
268 269 270 271 272 273 274 275 276 277 278 279 280
            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(); }
            }
        }
281
        case (typeck.ty_char) { ret T_char(); }
282
        case (typeck.ty_str) { ret T_ptr(T_str()); }
283 284 285
        case (typeck.ty_tag(?tag_id)) {
            ret llvm.LLVMResolveTypeHandle(cx.tags.get(tag_id).th.llth);
        }
286
        case (typeck.ty_box(?t)) {
287 288
            ret T_ptr(T_box(type_of(cx, t)));
        }
289
        case (typeck.ty_vec(?t)) {
290
            ret T_ptr(T_vec(type_of(cx, t)));
291
        }
292
        case (typeck.ty_tup(?elts)) {
293
            let vec[TypeRef] tys = vec();
294 295
            for (@typeck.ty elt in elts) {
                tys += type_of(cx, elt);
296 297 298
            }
            ret T_struct(tys);
        }
299 300 301 302 303 304 305
        case (typeck.ty_rec(?fields)) {
            let vec[TypeRef] tys = vec();
            for (typeck.field f in fields) {
                tys += type_of(cx, f.ty);
            }
            ret T_struct(tys);
        }
306
        case (typeck.ty_fn(?args, ?out)) {
307
            let vec[TypeRef] atys = vec(T_taskptr());
308 309 310 311 312 313
            for (typeck.arg arg in args) {
                let TypeRef t = type_of(cx, arg.ty);
                alt (arg.mode) {
                    case (ast.alias) {
                        t = T_ptr(t);
                    }
314
                    case (_) { /* fall through */  }
315 316 317 318 319
                }
                atys += t;
            }
            ret T_fn(atys, type_of(cx, out));
        }
320
        case (typeck.ty_var(_)) {
321
            // FIXME: implement.
322 323
            log "ty_var in trans.type_of";
            ret T_i8();
324 325 326 327 328
        }
    }
    fail;
}

329 330 331 332 333 334
// LLVM constant constructors.

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

335
fn C_integral(int i, TypeRef t) -> ValueRef {
336 337 338 339 340 341
    // 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);
    //
342 343 344
    ret llvm.LLVMConstIntOfString(t, _str.buf(istr(i)), 10);
}

345 346 347 348 349
fn C_nil() -> ValueRef {
    // NB: See comment above in T_void().
    ret C_integral(0, T_i1());
}

350 351
fn C_bool(bool b) -> ValueRef {
    if (b) {
352
        ret C_integral(1, T_bool());
353
    } else {
354
        ret C_integral(0, T_bool());
355 356 357
    }
}

358 359
fn C_int(int i) -> ValueRef {
    ret C_integral(i, T_int());
360 361
}

362
fn C_str(@crate_ctxt cx, str s) -> ValueRef {
363
    auto sc = llvm.LLVMConstString(_str.buf(s), _str.byte_len(s), False);
364
    auto g = llvm.LLVMAddGlobal(cx.llmod, val_ty(sc),
365 366 367
                                _str.buf(cx.names.next("str")));
    llvm.LLVMSetInitializer(g, sc);
    ret g;
368 369 370 371 372 373 374 375
}

fn C_struct(vec[ValueRef] elts) -> ValueRef {
    ret llvm.LLVMConstStruct(_vec.buf[ValueRef](elts),
                             _vec.len[ValueRef](elts),
                             False);
}

376
fn C_tydesc(TypeRef t) -> ValueRef {
377 378 379 380 381 382 383 384 385 386
    ret C_struct(vec(C_null(T_ptr(T_opaque())),        // first_param
                     llvm.LLVMSizeOf(t),               // size
                     llvm.LLVMAlignOf(t),              // align
                     C_null(T_ptr(T_opaque())),        // copy_glue_off
                     C_null(T_ptr(T_opaque())),        // drop_glue_off
                     C_null(T_ptr(T_opaque())),        // free_glue_off
                     C_null(T_ptr(T_opaque())),        // sever_glue_off
                     C_null(T_ptr(T_opaque())),        // mark_glue_off
                     C_null(T_ptr(T_opaque())),        // obj_drop_glue_off
                     C_null(T_ptr(T_opaque()))));      // is_stateful
387 388
}

389
fn decl_fn(ModuleRef llmod, str name, uint cc, TypeRef llty) -> ValueRef {
390 391
    let ValueRef llfn =
        llvm.LLVMAddFunction(llmod, _str.buf(name), llty);
392
    llvm.LLVMSetFunctionCallConv(llfn, cc);
393 394 395
    ret llfn;
}

396 397
fn decl_cdecl_fn(ModuleRef llmod, str name, TypeRef llty) -> ValueRef {
    ret decl_fn(llmod, name, lib.llvm.LLVMCCallConv, llty);
398 399
}

400 401
fn decl_fastcall_fn(ModuleRef llmod, str name, TypeRef llty) -> ValueRef {
    ret decl_fn(llmod, name, lib.llvm.LLVMFastCallConv, llty);
402 403
}

404
fn decl_glue(ModuleRef llmod, str s) -> ValueRef {
405
    ret decl_cdecl_fn(llmod, s, T_fn(vec(T_taskptr()), T_void()));
406 407
}

408
fn decl_upcall(ModuleRef llmod, uint _n) -> ValueRef {
409 410 411 412
    // 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.
413
    let int n = _n as int;
414
    let str s = abi.upcall_glue_name(n);
415
    let vec[TypeRef] args =
416 417
        vec(T_taskptr(), // taskptr
            T_int())     // callee
418 419
        + _vec.init_elt[TypeRef](T_int(), n as uint);

420
    ret decl_fastcall_fn(llmod, s, T_fn(args, T_int()));
421 422
}

423
fn get_upcall(@crate_ctxt cx, str name, int n_args) -> ValueRef {
424 425 426
    if (cx.upcalls.contains_key(name)) {
        ret cx.upcalls.get(name);
    }
427
    auto inputs = vec(T_taskptr());
428
    inputs += _vec.init_elt[TypeRef](T_int(), n_args as uint);
429
    auto output = T_int();
430
    auto f = decl_cdecl_fn(cx.llmod, name, T_fn(inputs, output));
431 432 433 434
    cx.upcalls.insert(name, f);
    ret f;
}

435
fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args) -> result {
436
    let int n = _vec.len[ValueRef](args) as int;
437
    let ValueRef llupcall = get_upcall(cx.fcx.ccx, name, n);
438 439
    llupcall = llvm.LLVMConstPointerCast(llupcall, T_int());

440
    let ValueRef llglue = cx.fcx.ccx.glues.upcall_glues.(n);
441 442 443 444
    let vec[ValueRef] call_args = vec(cx.fcx.lltaskptr, llupcall);
    for (ValueRef a in args) {
        call_args += cx.build.ZExtOrBitCast(a, T_int());
    }
445
    ret res(cx, cx.build.FastCall(llglue, call_args));
446 447
}

448 449 450
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)));
451 452
}

453 454 455 456 457 458 459 460 461 462 463 464 465
fn trans_malloc(@block_ctxt cx, @typeck.ty t) -> result {
    auto ptr_ty = type_of(cx.fcx.ccx, t);
    auto body_ty = lib.llvm.llvm.LLVMGetElementType(ptr_ty);
    // FIXME: need a table to collect tydesc globals.
    auto tydesc = C_int(0);
    auto sz = cx.build.IntCast(lib.llvm.llvm.LLVMSizeOf(body_ty), T_int());
    auto sub = trans_upcall(cx, "upcall_malloc", vec(sz, tydesc));
    sub.val = sub.bcx.build.IntToPtr(sub.val, ptr_ty);
    sub.bcx.cleanups += clean(bind drop_ty(_, sub.val, t));
    ret sub;
}


466 467 468 469 470
fn incr_refcnt(@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);

471 472
    auto next_cx = new_sub_block_ctxt(cx, "next");
    auto rc_adj_cx = new_sub_block_ctxt(cx, "rc++");
473 474 475 476 477 478 479 480 481 482 483 484

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

485 486
fn decr_refcnt_and_if_zero(@block_ctxt cx,
                           ValueRef box_ptr,
487
                           fn(@block_ctxt cx) -> result inner,
488
                           str inner_name,
489
                           TypeRef t_else, ValueRef v_else) -> result {
490 491 492 493 494

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

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

    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.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);
506 507 508 509
    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);
510

511
    auto phi = next_cx.build.Phi(t_else,
512
                                 vec(v_else, v_else, inner_res.val),
513 514
                                 vec(cx.llbb,
                                     rc_adj_cx.llbb,
515 516
                                     inner_res.bcx.llbb));

517
    ret res(next_cx, phi);
518 519
}

520 521 522 523 524 525 526 527 528 529 530 531 532
type val_and_ty_fn =
    fn(@block_ctxt cx, ValueRef v, @typeck.ty t) -> result;

// Iterates through the elements of a tup, rec or tag.
fn iter_structural_ty(@block_ctxt cx,
                      ValueRef v,
                      @typeck.ty t,
                      val_and_ty_fn f)
    -> result {
    let result r = res(cx, C_nil());
    alt (t.struct) {
        case (typeck.ty_tup(?args)) {
            let int i = 0;
533
            for (@typeck.ty arg in args) {
534
                auto elt = r.bcx.build.GEP(v, vec(C_int(0), C_int(i)));
535
                r = f(r.bcx, elt, arg);
536 537 538
                i += 1;
            }
        }
539 540 541 542 543 544 545 546 547 548 549
        case (typeck.ty_rec(?fields)) {
            let int i = 0;
            for (typeck.field fld in fields) {
                auto llfld = r.bcx.build.GEP(v, vec(C_int(0), C_int(i)));
                r = f(r.bcx, llfld, fld.ty);
                i += 1;
            }
        }
        case (_) {
            cx.fcx.ccx.sess.unimpl("type in iter_structural_ty");
        }
550
        // FIXME: handle records and tags when we support them.
551
    }
552
    ret r;
553 554
}

555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603
// Iterates through the elements of a vec or str.
fn iter_sequence(@block_ctxt cx,
                 ValueRef v,
                 @typeck.ty ty,
                 val_and_ty_fn f) -> result {

    fn iter_sequence_body(@block_ctxt cx,
                          ValueRef v,
                          @typeck.ty elt_ty,
                          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)));
        auto len = cx.build.Load(lenptr);
        if (trailing_null) {
            len = cx.build.Sub(len, C_int(1));
        }

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

        auto cond_cx = new_sub_block_ctxt(cx, "sequence-iter cond");
        auto body_cx = new_sub_block_ctxt(cx, "sequence-iter body");
        auto next_cx = new_sub_block_ctxt(cx, "next");

        auto ix = cond_cx.build.Phi(T_int(), vec(C_int(0)), vec(cx.llbb));
        auto end_test = cond_cx.build.ICmp(lib.llvm.LLVMIntEQ, ix, len);
        cond_cx.build.CondBr(end_test, body_cx.llbb, next_cx.llbb);

        auto elt = body_cx.build.GEP(p0, vec(ix));
        auto body_res = f(body_cx, elt, elt_ty);
        auto next_ix = body_res.bcx.build.Add(ix, C_int(1));
        cond_cx.build.AddIncomingToPhi(ix, vec(next_ix),
                                       vec(body_res.bcx.llbb));

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

    alt (ty.struct) {
        case (typeck.ty_vec(?et)) {
            ret iter_sequence_body(cx, v, et, f, false);
        }
        case (typeck.ty_str) {
            auto et = typeck.plain_ty(typeck.ty_machine(common.ty_u8));
            ret iter_sequence_body(cx, v, et, f, false);
        }
604
        case (_) { fail; }
605
    }
606 607 608 609 610 611 612
    cx.fcx.ccx.sess.bug("bad type in trans.iter_sequence");
    fail;
}

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

614 615 616 617 618 619 620 621 622 623
    if (typeck.type_is_boxed(t)) {
        ret incr_refcnt(cx, v);

    } else if (typeck.type_is_binding(t)) {
        cx.fcx.ccx.sess.unimpl("binding type in trans.incr_all_refcnts");

    } else if (typeck.type_is_structural(t)) {
        ret iter_structural_ty(cx, v, t,
                               bind incr_all_refcnts(_, _, _));
    }
624
    ret res(cx, C_nil());
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651
}

fn drop_ty(@block_ctxt cx,
           ValueRef v,
           @typeck.ty t) -> result {

    alt (t.struct) {
        case (typeck.ty_str) {
            ret decr_refcnt_and_if_zero(cx, v,
                                        bind trans_non_gc_free(_, v),
                                        "free string",
                                        T_int(), C_int(0));
        }

        case (typeck.ty_vec(_)) {
            fn hit_zero(@block_ctxt cx, ValueRef v,
                        @typeck.ty t) -> result {
                auto res = iter_sequence(cx, v, t, bind drop_ty(_,_,_));
                // FIXME: switch gc/non-gc on stratum 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));
        }

652
        case (typeck.ty_box(?body_ty)) {
653
            fn hit_zero(@block_ctxt cx, ValueRef v,
654 655 656 657 658 659
                        @typeck.ty body_ty) -> result {
                auto body = cx.build.GEP(v,
                                         vec(C_int(0),
                                             C_int(abi.box_rc_field_body)));

                auto res = drop_ty(cx, body, body_ty);
660 661 662
                // FIXME: switch gc/non-gc on stratum of the type.
                ret trans_non_gc_free(res.bcx, v);
            }
663 664 665 666
            ret decr_refcnt_and_if_zero(cx, v,
                                        bind hit_zero(_, v, body_ty),
                                        "free box",
                                        T_int(), C_int(0));
667 668 669 670 671 672 673 674 675 676 677 678 679
        }

        case (_) {
            if (typeck.type_is_structural(t)) {
                ret iter_structural_ty(cx, v, t,
                                       bind drop_ty(_, _, _));

            } else if (typeck.type_is_binding(t)) {
                cx.fcx.ccx.sess.unimpl("binding type in trans.drop_ty");

            } else if (typeck.type_is_scalar(t) ||
                       typeck.type_is_nil(t)) {
                ret res(cx, C_nil());
680 681 682
            }
        }
    }
683 684 685 686 687 688 689 690
    cx.fcx.ccx.sess.bug("bad type in trans.drop_ty");
    fail;
}

fn build_memcpy(@block_ctxt cx,
                ValueRef dst,
                ValueRef src,
                TypeRef llty) -> result {
691 692 693
    // 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");
694 695
    auto src_ptr = cx.build.PointerCast(src, T_ptr(T_i8()));
    auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
G
Graydon Hoare 已提交
696 697
    auto size = cx.build.IntCast(lib.llvm.llvm.LLVMSizeOf(llty),
                                 T_i32());
698 699 700 701 702 703
    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.

704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735
    auto volatile = C_integral(0, T_i1());
    ret res(cx, cx.build.Call(memcpy,
                              vec(dst_ptr, src_ptr,
                                  size, align, volatile)));
}

fn copy_ty(@block_ctxt cx,
           bool is_init,
           ValueRef dst,
           ValueRef src,
           @typeck.ty t) -> result {
    if (typeck.type_is_scalar(t)) {
        ret res(cx, cx.build.Store(src, dst));

    } else if (typeck.type_is_nil(t)) {
        ret res(cx, C_nil());

    } else if (typeck.type_is_binding(t)) {
        cx.fcx.ccx.sess.unimpl("binding type in trans.copy_ty");

    } else if (typeck.type_is_boxed(t)) {
        auto r = incr_refcnt(cx, src);
        if (! is_init) {
            r = drop_ty(r.bcx, dst, t);
        }
        ret res(r.bcx, r.bcx.build.Store(src, dst));

    } else if (typeck.type_is_structural(t)) {
        auto r = incr_all_refcnts(cx, src, t);
        if (! is_init) {
            r = drop_ty(r.bcx, dst, t);
        }
736 737 738 739
        // In this one surprising case, we do a load/store on
        // structure types. This results in a memcpy. Usually
        // we talk about structures by pointers in this file.
        ret res(r.bcx, r.bcx.build.Store(r.bcx.build.Load(src), dst));
740 741 742 743
    }

    cx.fcx.ccx.sess.bug("unexpected type in trans.copy_ty: " +
                        typeck.ty_to_str(t));
744 745 746
    fail;
}

747 748 749
fn trans_drop_str(@block_ctxt cx, ValueRef v) -> result {
    ret decr_refcnt_and_if_zero(cx, v,
                                bind trans_non_gc_free(_, v),
750
                                "free string",
751
                                T_int(), C_int(0));
752 753
}

754
impure fn trans_lit(@block_ctxt cx, &ast.lit lit) -> result {
755
    alt (lit.node) {
756
        case (ast.lit_int(?i)) {
757
            ret res(cx, C_int(i));
758 759
        }
        case (ast.lit_uint(?u)) {
760
            ret res(cx, C_int(u as int));
761
        }
762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782
        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) {
                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(); }
                case (_) {
                    cx.fcx.ccx.sess.bug("bad mach int literal type");
                }
            }
            ret res(cx, C_integral(i, t));
        }
783
        case (ast.lit_char(?c)) {
784
            ret res(cx, C_integral(c as int, T_char()));
785 786
        }
        case (ast.lit_bool(?b)) {
787 788 789 790
            ret res(cx, C_bool(b));
        }
        case (ast.lit_nil) {
            ret res(cx, C_nil());
791 792 793
        }
        case (ast.lit_str(?s)) {
            auto len = (_str.byte_len(s) as int) + 1;
794
            auto sub = trans_upcall(cx, "upcall_new_str",
795
                                    vec(p2i(C_str(cx.fcx.ccx, s)),
796 797
                                        C_int(len)));
            sub.val = sub.bcx.build.IntToPtr(sub.val,
798
                                             T_ptr(T_str()));
799
            cx.cleanups += clean(bind trans_drop_str(_, sub.val));
800
            ret sub;
801 802 803 804
        }
    }
}

805 806 807 808 809 810 811 812 813 814
fn target_type(@crate_ctxt cx, @typeck.ty t) -> @typeck.ty {
    alt (t.struct) {
        case (typeck.ty_int) {
            auto tm = typeck.ty_machine(cx.sess.get_targ_cfg().int_type);
            ret @rec(struct=tm with *t);
        }
        case (typeck.ty_uint) {
            auto tm = typeck.ty_machine(cx.sess.get_targ_cfg().uint_type);
            ret @rec(struct=tm with *t);
        }
815
        case (_) { /* fall through */ }
816 817 818 819 820
    }
    ret t;
}

fn node_ann_type(@crate_ctxt cx, &ast.ann a) -> @typeck.ty {
821 822 823 824 825 826
    alt (a) {
        case (ast.ann_none) {
            log "missing type annotation";
            fail;
        }
        case (ast.ann_type(?t)) {
827
            ret target_type(cx, t);
828 829 830 831
        }
    }
}

832 833 834 835
fn node_type(@crate_ctxt cx, &ast.ann a) -> TypeRef {
    ret type_of(cx, node_ann_type(cx, a));
}

836
impure fn trans_unary(@block_ctxt cx, ast.unop op,
837
                      @ast.expr e, &ast.ann a) -> result {
838 839 840

    auto sub = trans_expr(cx, e);

841 842
    alt (op) {
        case (ast.bitnot) {
843 844
            sub.val = cx.build.Not(sub.val);
            ret sub;
845 846
        }
        case (ast.not) {
847 848
            sub.val = cx.build.Not(sub.val);
            ret sub;
849 850 851
        }
        case (ast.neg) {
            // FIXME: switch by signedness.
852 853
            sub.val = cx.build.Neg(sub.val);
            ret sub;
854
        }
855
        case (ast.box) {
856 857 858 859 860
            auto e_ty = typeck.expr_ty(e);
            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,
861 862
                                        vec(C_int(0),
                                            C_int(abi.box_rc_field_refcnt)));
863 864 865 866 867 868
            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);
869
        }
870 871 872
        case (_) {
            cx.fcx.ccx.sess.unimpl("expr variant in trans_unary");
        }
873 874 875 876
    }
    fail;
}

877
impure fn trans_binary(@block_ctxt cx, ast.binop op,
878
                       @ast.expr a, @ast.expr b) -> result {
879

880 881 882 883 884 885 886
    // First couple cases are lazy:

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

887
            auto rhs_cx = new_sub_block_ctxt(cx, "rhs");
888 889
            auto rhs_res = trans_expr(rhs_cx, b);

890 891
            auto lhs_false_cx = new_sub_block_ctxt(cx, "lhs false");
            auto lhs_false_res = res(lhs_false_cx, C_bool(false));
892 893 894

            lhs_res.bcx.build.CondBr(lhs_res.val,
                                     rhs_cx.llbb,
895 896 897 898
                                     lhs_false_cx.llbb);

            ret join_results(cx, T_bool(),
                             vec(lhs_false_res, rhs_res));
899 900 901 902 903 904
        }

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

905
            auto rhs_cx = new_sub_block_ctxt(cx, "rhs");
906 907
            auto rhs_res = trans_expr(rhs_cx, b);

908 909
            auto lhs_true_cx = new_sub_block_ctxt(cx, "lhs true");
            auto lhs_true_res = res(lhs_true_cx, C_bool(true));
910 911

            lhs_res.bcx.build.CondBr(lhs_res.val,
912
                                     lhs_true_cx.llbb,
913
                                     rhs_cx.llbb);
914 915 916

            ret join_results(cx, T_bool(),
                             vec(lhs_true_res, rhs_res));
917
        }
918 919

        case (_) { /* fall through */ }
920 921 922 923
    }

    // Remaining cases are eager:

924 925 926
    auto lhs = trans_expr(cx, a);
    auto sub = trans_expr(lhs.bcx, b);

927 928
    alt (op) {
        case (ast.add) {
929 930
            sub.val = cx.build.Add(lhs.val, sub.val);
            ret sub;
931 932 933
        }

        case (ast.sub) {
934 935
            sub.val = cx.build.Sub(lhs.val, sub.val);
            ret sub;
936 937 938 939
        }

        case (ast.mul) {
            // FIXME: switch by signedness.
940 941
            sub.val = cx.build.Mul(lhs.val, sub.val);
            ret sub;
942 943 944 945
        }

        case (ast.div) {
            // FIXME: switch by signedness.
946 947
            sub.val = cx.build.SDiv(lhs.val, sub.val);
            ret sub;
948 949 950 951
        }

        case (ast.rem) {
            // FIXME: switch by signedness.
952 953
            sub.val = cx.build.SRem(lhs.val, sub.val);
            ret sub;
954 955 956
        }

        case (ast.bitor) {
957 958
            sub.val = cx.build.Or(lhs.val, sub.val);
            ret sub;
959 960 961
        }

        case (ast.bitand) {
962 963
            sub.val = cx.build.And(lhs.val, sub.val);
            ret sub;
964 965 966
        }

        case (ast.bitxor) {
967 968
            sub.val = cx.build.Xor(lhs.val, sub.val);
            ret sub;
969 970 971
        }

        case (ast.lsl) {
972 973
            sub.val = cx.build.Shl(lhs.val, sub.val);
            ret sub;
974 975 976
        }

        case (ast.lsr) {
977 978
            sub.val = cx.build.LShr(lhs.val, sub.val);
            ret sub;
979 980 981
        }

        case (ast.asr) {
982 983
            sub.val = cx.build.AShr(lhs.val, sub.val);
            ret sub;
984 985 986
        }

        case (ast.eq) {
987 988
            sub.val = cx.build.ICmp(lib.llvm.LLVMIntEQ, lhs.val, sub.val);
            ret sub;
989 990 991
        }

        case (ast.ne) {
992 993
            sub.val = cx.build.ICmp(lib.llvm.LLVMIntNE, lhs.val, sub.val);
            ret sub;
994 995 996 997
        }

        case (ast.lt) {
            // FIXME: switch by signedness.
998 999
            sub.val = cx.build.ICmp(lib.llvm.LLVMIntSLT, lhs.val, sub.val);
            ret sub;
1000 1001 1002 1003
        }

        case (ast.le) {
            // FIXME: switch by signedness.
1004 1005
            sub.val = cx.build.ICmp(lib.llvm.LLVMIntSLE, lhs.val, sub.val);
            ret sub;
1006 1007 1008 1009
        }

        case (ast.ge) {
            // FIXME: switch by signedness.
1010 1011
            sub.val = cx.build.ICmp(lib.llvm.LLVMIntSGE, lhs.val, sub.val);
            ret sub;
1012 1013 1014 1015
        }

        case (ast.gt) {
            // FIXME: switch by signedness.
1016 1017
            sub.val = cx.build.ICmp(lib.llvm.LLVMIntSGT, lhs.val, sub.val);
            ret sub;
1018
        }
1019 1020 1021 1022

        case (_) {
            cx.fcx.ccx.sess.unimpl("operator in trans_binary");
        }
1023 1024 1025 1026
    }
    fail;
}

1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057
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);
        }
1058 1059

        case (_) { /* fall through */ }
1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070
    }

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

1071
impure fn trans_if(@block_ctxt cx, @ast.expr cond,
1072
                   &ast.block thn, &option.t[ast.block] els) -> result {
1073 1074 1075

    auto cond_res = trans_expr(cx, cond);

1076
    auto then_cx = new_sub_block_ctxt(cx, "then");
1077 1078
    auto then_res = trans_block(then_cx, thn);

1079 1080
    auto else_cx = new_sub_block_ctxt(cx, "else");
    auto else_res = res(else_cx, C_nil());
1081 1082 1083

    alt (els) {
        case (some[ast.block](?eblk)) {
1084
            else_res = trans_block(else_cx, eblk);
1085
        }
1086
        case (_) { /* fall through */ }
1087 1088
    }

1089 1090 1091 1092 1093 1094 1095
    cond_res.bcx.build.CondBr(cond_res.val,
                              then_res.bcx.llbb,
                              else_res.bcx.llbb);

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

1098
impure fn trans_while(@block_ctxt cx, @ast.expr cond,
1099 1100
                      &ast.block body) -> result {

1101 1102 1103
    auto cond_cx = new_sub_block_ctxt(cx, "while cond");
    auto body_cx = new_sub_block_ctxt(cx, "while loop body");
    auto next_cx = new_sub_block_ctxt(cx, "next");
1104 1105

    auto body_res = trans_block(body_cx, body);
1106 1107 1108 1109 1110 1111 1112 1113
    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);
1114 1115 1116 1117
    ret res(next_cx, C_nil());
}

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

1120 1121
    auto body_cx = new_sub_block_ctxt(cx, "do-while loop body");
    auto next_cx = new_sub_block_ctxt(cx, "next");
1122 1123

    auto body_res = trans_block(body_cx, body);
1124 1125 1126 1127 1128 1129
    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);
1130 1131 1132
    ret res(next_cx, body_res.val);
}

1133 1134 1135
// 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).
1136

1137 1138 1139 1140 1141 1142 1143 1144
fn trans_name(@block_ctxt cx, &ast.name n, &option.t[ast.def] dopt)
    -> tup(result, bool) {
    alt (dopt) {
        case (some[ast.def](?def)) {
            alt (def) {
                case (ast.def_arg(?did)) {
                    check (cx.fcx.llargs.contains_key(did));
                    ret tup(res(cx, cx.fcx.llargs.get(did)),
1145
                            true);
1146 1147 1148 1149 1150
                }
                case (ast.def_local(?did)) {
                    check (cx.fcx.lllocals.contains_key(did));
                    ret tup(res(cx, cx.fcx.lllocals.get(did)),
                            true);
G
Graydon Hoare 已提交
1151
                }
1152
                case (ast.def_fn(?did)) {
1153 1154
                    check (cx.fcx.ccx.item_ids.contains_key(did));
                    ret tup(res(cx, cx.fcx.ccx.item_ids.get(did)),
1155 1156
                            false);
                }
1157 1158 1159
                case (ast.def_variant(?tid, ?vid)) {
                    check (cx.fcx.ccx.tags.contains_key(tid));
                    auto info = cx.fcx.ccx.tags.get(tid);
1160 1161 1162 1163 1164 1165 1166 1167
                    auto i = 0;
                    for (tup(ast.def_id,arity) v in info.variants) {
                        if (vid == v._0) {
                            alt (v._1) {
                                case (nullary) {
                                    auto elems = vec(C_int(i));
                                    ret tup(res(cx, C_struct(elems)), false);
                                }
1168
                                case (n_ary) {
1169 1170 1171 1172 1173 1174 1175
                                    cx.fcx.ccx.sess.unimpl("n-ary tag " +
                                                           "constructor in " +
                                                           "trans");
                                }
                            }
                        }
                        i += 1;
1176 1177
                    }
                }
1178 1179
                case (_) {
                    cx.fcx.ccx.sess.unimpl("def variant in trans");
G
Graydon Hoare 已提交
1180 1181 1182
                }
            }
        }
1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200
        case (none[ast.def]) {
            cx.fcx.ccx.sess.err("unresolved expr_name in trans");
        }
    }
    fail;
}

fn trans_field(@block_ctxt cx, &ast.span sp, @ast.expr base,
               &ast.ident field, &ast.ann ann) -> tup(result, bool) {
    auto lv = trans_lval(cx, base);
    auto r = lv._0;
    auto ty = typeck.expr_ty(base);
    alt (ty.struct) {
        case (typeck.ty_tup(?fields)) {
            let uint ix = typeck.field_num(cx.fcx.ccx.sess, sp, field);
            auto v = r.bcx.build.GEP(r.val, vec(C_int(0), C_int(ix as int)));
            ret tup(res(r.bcx, v), lv._1);
        }
1201 1202 1203 1204 1205 1206
        case (typeck.ty_rec(?fields)) {
            let uint ix = typeck.field_idx(cx.fcx.ccx.sess, sp,
                                           field, fields);
            auto v = r.bcx.build.GEP(r.val, vec(C_int(0), C_int(ix as int)));
            ret tup(res(r.bcx, v), lv._1);
        }
1207
        case (_) { cx.fcx.ccx.sess.unimpl("field variant in trans_field"); }
1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219
    }
    fail;
}

fn trans_lval(@block_ctxt cx, @ast.expr e) -> tup(result, bool) {
    alt (e.node) {
        case (ast.expr_name(?n, ?dopt, _)) {
            ret trans_name(cx, n, dopt);
        }
        case (ast.expr_field(?base, ?ident, ?ann)) {
            ret trans_field(cx, e.span, base, ident, ann);
        }
1220
        case (_) { cx.fcx.ccx.sess.unimpl("expr variant in trans_lval"); }
G
Graydon Hoare 已提交
1221 1222 1223 1224
    }
    fail;
}

1225
impure fn trans_cast(@block_ctxt cx, @ast.expr e, &ast.ann ann) -> result {
1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255
    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);
    if (!typeck.type_is_fp(t)) {
        if (llvm.LLVMGetIntTypeWidth(lldsttype) >
            llvm.LLVMGetIntTypeWidth(llsrctype)) {
            if (typeck.type_is_signed(t)) {
                // 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;
}

1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275

impure fn trans_args(@block_ctxt cx, &vec[@ast.expr] es)
    -> tup(@block_ctxt, vec[ValueRef]) {
    let vec[ValueRef] vs = vec(cx.fcx.lltaskptr);
    let @block_ctxt bcx = cx;

    for (@ast.expr e in es) {
        auto res = trans_expr(bcx, e);
        // Until here we've been treating structures by pointer;
        // we are now passing it as an arg, so need to load it.
        if (typeck.type_is_structural(typeck.expr_ty(e))) {
            res.val = res.bcx.build.Load(res.val);
        }
        vs += res.val;
        bcx = res.bcx;
    }

    ret tup(bcx, vs);
}

1276
impure fn trans_call(@block_ctxt cx, @ast.expr f,
1277 1278 1279
                     vec[@ast.expr] args) -> result {
    auto f_res = trans_lval(cx, f);
    check (! f_res._1);
1280
    auto args_res = trans_args(f_res._0.bcx, args);
1281
    ret res(args_res._0,
1282
            args_res._0.build.FastCall(f_res._0.val, args_res._1));
1283 1284
}

1285
impure fn trans_tup(@block_ctxt cx, vec[ast.elt] elts,
G
Graydon Hoare 已提交
1286 1287 1288 1289 1290
                    &ast.ann ann) -> result {
    auto ty = node_type(cx.fcx.ccx, ann);
    auto tup_val = cx.build.Alloca(ty);
    let int i = 0;
    auto r = res(cx, C_nil());
1291 1292 1293
    for (ast.elt e in elts) {
        auto t = typeck.expr_ty(e.expr);
        auto src_res = trans_expr(r.bcx, e.expr);
G
Graydon Hoare 已提交
1294 1295 1296 1297 1298 1299 1300 1301
        auto dst_elt = r.bcx.build.GEP(tup_val, vec(C_int(0), C_int(i)));
        // FIXME: calculate copy init-ness in typestate.
        r = copy_ty(src_res.bcx, true, dst_elt, src_res.val, t);
        i += 1;
    }
    ret res(r.bcx, tup_val);
}

1302
impure fn trans_rec(@block_ctxt cx, vec[ast.field] fields,
1303 1304
                    &ast.ann ann) -> result {
    auto ty = node_type(cx.fcx.ccx, ann);
1305
    auto rec_val = cx.build.Alloca(ty);
1306 1307
    let int i = 0;
    auto r = res(cx, C_nil());
1308 1309 1310 1311
    for (ast.field f in fields) {
        auto t = typeck.expr_ty(f.expr);
        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)));
1312 1313 1314 1315
        // FIXME: calculate copy init-ness in typestate.
        r = copy_ty(src_res.bcx, true, dst_elt, src_res.val, t);
        i += 1;
    }
1316
    ret res(r.bcx, rec_val);
1317 1318
}

G
Graydon Hoare 已提交
1319

G
Graydon Hoare 已提交
1320

1321
impure fn trans_expr(@block_ctxt cx, @ast.expr e) -> result {
1322
    alt (e.node) {
P
Patrick Walton 已提交
1323
        case (ast.expr_lit(?lit, _)) {
1324 1325 1326
            ret trans_lit(cx, *lit);
        }

1327
        case (ast.expr_unary(?op, ?x, ?ann)) {
1328
            ret trans_unary(cx, op, x, ann);
1329 1330
        }

P
Patrick Walton 已提交
1331
        case (ast.expr_binary(?op, ?x, ?y, _)) {
1332
            ret trans_binary(cx, op, x, y);
1333
        }
1334

P
Patrick Walton 已提交
1335
        case (ast.expr_if(?cond, ?thn, ?els, _)) {
1336
            ret trans_if(cx, cond, thn, els);
1337 1338
        }

1339
        case (ast.expr_while(?cond, ?body, _)) {
1340
            ret trans_while(cx, cond, body);
1341 1342
        }

1343
        case (ast.expr_do_while(?body, ?cond, _)) {
1344
            ret trans_do_while(cx, body, cond);
1345 1346
        }

P
Patrick Walton 已提交
1347
        case (ast.expr_block(?blk, _)) {
1348 1349
            auto sub_cx = new_sub_block_ctxt(cx, "block-expr body");
            auto next_cx = new_sub_block_ctxt(cx, "next");
1350 1351 1352 1353 1354 1355 1356
            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);
        }
1357

1358
        case (ast.expr_assign(?dst, ?src, ?ann)) {
1359
            auto lhs_res = trans_lval(cx, dst);
1360
            check (lhs_res._1);
1361
            auto rhs_res = trans_expr(lhs_res._0.bcx, src);
1362
            auto t = node_ann_type(cx.fcx.ccx, ann);
G
Graydon Hoare 已提交
1363
            // FIXME: calculate copy init-ness in typestate.
1364
            ret copy_ty(rhs_res.bcx, true, lhs_res._0.val, rhs_res.val, t);
1365
        }
G
Graydon Hoare 已提交
1366

1367
        case (ast.expr_call(?f, ?args, _)) {
1368
            ret trans_call(cx, f, args);
1369 1370
        }

1371
        case (ast.expr_cast(?e, _, ?ann)) {
1372
            ret trans_cast(cx, e, ann);
1373
        }
G
Graydon Hoare 已提交
1374 1375 1376 1377

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

1379 1380 1381 1382
        case (ast.expr_rec(?args, ?ann)) {
            ret trans_rec(cx, args, ann);
        }

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

1386 1387 1388 1389 1390 1391 1392 1393 1394
        case (_) {
            auto t = typeck.expr_ty(e);
            auto sub = trans_lval(cx, e);
            if (sub._1 && ! typeck.type_is_structural(t)) {
                ret res(sub._0.bcx, cx.build.Load(sub._0.val));
            } else {
                ret sub._0;
            }
        }
1395
    }
1396
    cx.fcx.ccx.sess.unimpl("expr variant in trans_expr");
1397 1398 1399
    fail;
}

1400
impure fn trans_log(@block_ctxt cx, @ast.expr e) -> result {
1401
    alt (e.node) {
P
Patrick Walton 已提交
1402
        case (ast.expr_lit(?lit, _)) {
1403
            alt (lit.node) {
1404
                case (ast.lit_str(_)) {
1405 1406 1407 1408 1409
                    auto sub = trans_expr(cx, e);
                    auto v = sub.bcx.build.PtrToInt(sub.val, T_int());
                    ret trans_upcall(sub.bcx,
                                     "upcall_log_str",
                                     vec(v));
1410
                }
1411

1412
                case (_) {
1413 1414 1415 1416
                    auto sub = trans_expr(cx, e);
                    ret trans_upcall(sub.bcx,
                                     "upcall_log_int",
                                     vec(sub.val));
1417 1418 1419
                }
            }
        }
1420

1421
        case (_) {
1422 1423
            auto sub = trans_expr(cx, e);
            ret trans_upcall(sub.bcx, "upcall_log_int", vec(sub.val));
1424 1425
        }
    }
1426 1427
}

1428
impure fn trans_check_expr(@block_ctxt cx, @ast.expr e) -> result {
1429 1430 1431
    auto cond_res = trans_expr(cx, e);

    // FIXME: need pretty-printer.
1432 1433
    auto V_expr_str = p2i(C_str(cx.fcx.ccx, "<expr>"));
    auto V_filename = p2i(C_str(cx.fcx.ccx, e.span.filename));
1434 1435 1436
    auto V_line = e.span.lo.line as int;
    auto args = vec(V_expr_str, V_filename, C_int(V_line));

1437
    auto fail_cx = new_sub_block_ctxt(cx, "fail");
1438 1439
    auto fail_res = trans_upcall(fail_cx, "upcall_fail", args);

1440
    auto next_cx = new_sub_block_ctxt(cx, "next");
1441 1442 1443 1444 1445 1446 1447
    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());
}

1448
impure fn trans_ret(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
1449 1450 1451
    auto r = res(cx, C_nil());
    alt (e) {
        case (some[@ast.expr](?x)) {
1452
            r = trans_expr(cx, x);
1453
        }
1454
        case (_) { /* fall through */  }
1455 1456
    }

1457 1458
    // Run all cleanups and back out.
    let bool more_cleanups = true;
1459
    auto cleanup_cx = cx;
1460
    while (more_cleanups) {
1461 1462
        r.bcx = trans_block_cleanups(r.bcx, cleanup_cx);
        alt (cleanup_cx.parent) {
1463
            case (parent_some(?b)) {
1464
                cleanup_cx = b;
1465 1466 1467 1468 1469 1470 1471
            }
            case (parent_none) {
                more_cleanups = false;
            }
        }
    }

1472 1473 1474 1475 1476
    alt (e) {
        case (some[@ast.expr](_)) {
            r.val = r.bcx.build.Ret(r.val);
            ret r;
        }
1477
        case (_) { /* fall through */  }
1478 1479 1480 1481 1482
    }

    // FIXME: until LLVM has a unit type, we are moving around
    // C_nil values rather than their void type.
    r.val = r.bcx.build.Ret(C_nil());
1483 1484 1485
    ret r;
}

1486
impure fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
1487
    auto sub = res(cx, C_nil());
1488
    alt (s.node) {
1489
        case (ast.stmt_log(?a)) {
1490
            sub.bcx = trans_log(cx, a).bcx;
1491 1492
        }

1493
        case (ast.stmt_check_expr(?a)) {
1494
            sub.bcx = trans_check_expr(cx, a).bcx;
1495 1496
        }

1497 1498 1499 1500
        case (ast.stmt_ret(?e)) {
            sub.bcx = trans_ret(cx, e).bcx;
        }

1501
        case (ast.stmt_expr(?e)) {
1502
            sub.bcx = trans_expr(cx, e).bcx;
1503
        }
1504

1505 1506 1507 1508 1509
        case (ast.stmt_decl(?d)) {
            alt (d.node) {
                case (ast.decl_local(?local)) {
                    alt (local.init) {
                        case (some[@ast.expr](?e)) {
1510
                            check (cx.fcx.lllocals.contains_key(local.id));
1511
                            auto llptr = cx.fcx.lllocals.get(local.id);
1512 1513 1514
                            sub = trans_expr(cx, e);
                            copy_ty(sub.bcx, true, llptr, sub.val,
                                    typeck.expr_ty(e));
1515
                        }
1516
                        case (_) { /* fall through */  }
1517 1518 1519 1520
                    }
                }
            }
        }
1521
        case (_) {
1522
            cx.fcx.ccx.sess.unimpl("stmt variant");
1523 1524
        }
    }
1525
    ret sub;
1526 1527
}

1528
fn new_builder(BasicBlockRef llbb, str name) -> builder {
1529 1530 1531 1532 1533
    let BuilderRef llbuild = llvm.LLVMCreateBuilder();
    llvm.LLVMPositionBuilderAtEnd(llbuild, llbb);
    ret builder(llbuild);
}

1534 1535
// You probably don't want to use this one. See the
// next three functions instead.
1536 1537 1538
fn new_block_ctxt(@fn_ctxt cx, block_parent parent,
                  vec[cleanup] cleanups,
                  str name) -> @block_ctxt {
1539
    let BasicBlockRef llbb =
1540
        llvm.LLVMAppendBasicBlock(cx.llfn,
1541
                                  _str.buf(cx.ccx.names.next(name)));
1542

1543
    ret @rec(llbb=llbb,
1544 1545
             build=new_builder(llbb, name),
             parent=parent,
1546
             mutable cleanups=cleanups,
1547 1548 1549
             fcx=cx);
}

1550 1551 1552
// 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 {
    let vec[cleanup] cleanups = vec();
1553
    ret new_block_ctxt(fcx, parent_none, cleanups, "function top level");
1554 1555 1556

}

1557 1558
// Use this when you're making a block-within-a-block.
fn new_sub_block_ctxt(@block_ctxt bcx, str n) -> @block_ctxt {
1559
    let vec[cleanup] cleanups = vec();
1560
    ret new_block_ctxt(bcx.fcx, parent_some(bcx), cleanups, n);
1561
}
1562

1563

1564 1565
fn trans_block_cleanups(@block_ctxt cx,
                        @block_ctxt cleanup_cx) -> @block_ctxt {
1566
    auto bcx = cx;
1567
    for (cleanup c in cleanup_cx.cleanups) {
1568
        alt (c) {
1569
            case (clean(?cfn)) {
1570
                bcx = cfn(bcx).bcx;
1571 1572 1573
            }
        }
    }
1574 1575 1576
    ret bcx;
}

1577 1578 1579 1580 1581 1582 1583 1584 1585 1586
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;
                    }
1587
                    case (_) { /* fall through */ }
1588 1589
                }
            }
1590
            case (_) { /* fall through */ }
1591 1592 1593 1594
        }
    }
}

1595
impure fn trans_block(@block_ctxt cx, &ast.block b) -> result {
1596 1597
    auto bcx = cx;

1598
    for each (@ast.local local in block_locals(b)) {
1599
        auto ty = node_type(cx.fcx.ccx, local.ann);
1600 1601 1602
        auto val = bcx.build.Alloca(ty);
        cx.fcx.lllocals.insert(local.id, val);
    }
1603
    auto r = res(bcx, C_nil());
1604

1605
    for (@ast.stmt s in b.node.stmts) {
1606 1607
        r = trans_stmt(bcx, *s);
        bcx = r.bcx;
1608 1609 1610 1611 1612
        // 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;
        }
1613
    }
1614

1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627
    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());
        }
    }

1628
    bcx = trans_block_cleanups(bcx, bcx);
1629
    ret res(bcx, r.val);
1630 1631
}

1632
fn new_fn_ctxt(@crate_ctxt cx,
1633
               str name,
1634 1635 1636
               &ast._fn f,
               ast.def_id fid) -> @fn_ctxt {

1637 1638 1639
    check (cx.item_ids.contains_key(fid));
    let ValueRef llfn = cx.item_ids.get(fid);
    cx.item_names.insert(cx.path, llfn);
1640

1641 1642
    let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 0u);
    let uint arg_n = 1u;
1643

1644
    let hashmap[ast.def_id, ValueRef] lllocals = new_def_hash[ValueRef]();
1645 1646 1647
    let hashmap[ast.def_id, ValueRef] llargs = new_def_hash[ValueRef]();

    for (ast.arg arg in f.inputs) {
1648 1649 1650
        auto llarg = llvm.LLVMGetParam(llfn, arg_n);
        check (llarg as int != 0);
        llargs.insert(arg.id, llarg);
1651 1652 1653
        arg_n += 1u;
    }

1654 1655
    ret @rec(llfn=llfn,
             lltaskptr=lltaskptr,
1656
             llargs=llargs,
1657
             lllocals=lllocals,
1658
             ccx=cx);
1659 1660
}

1661 1662 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

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

fn copy_args_to_allocas(@block_ctxt cx, &ast._fn f, &ast.ann ann) {

    let vec[typeck.arg] arg_ts = vec();
    let @typeck.ty fty = node_ann_type(cx.fcx.ccx, ann);
    alt (fty.struct) {
        case (typeck.ty_fn(?a, _)) { arg_ts += a; }
    }

    let uint arg_n = 0u;

    for (ast.arg aarg in f.inputs) {
        auto arg = arg_ts.(arg_n);
        auto arg_t = type_of(cx.fcx.ccx, arg.ty);
        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);
        arg_n += 1u;
    }
}

1688 1689 1690 1691 1692
fn is_terminated(@block_ctxt cx) -> bool {
    auto inst = llvm.LLVMGetLastInstruction(cx.llbb);
    ret llvm.LLVMIsATerminatorInst(inst) as int != 0;
}

1693 1694
impure fn trans_fn(@crate_ctxt cx, &ast._fn f, ast.def_id fid,
                   &ast.ann ann) {
1695

1696
    auto fcx = new_fn_ctxt(cx, cx.path, f, fid);
1697
    auto bcx = new_top_block_ctxt(fcx);
1698 1699 1700

    copy_args_to_allocas(bcx, f, ann);

1701 1702
    auto res = trans_block(bcx, f.body);
    if (!is_terminated(res.bcx)) {
1703 1704 1705
        // FIXME: until LLVM has a unit type, we are moving around
        // C_nil values rather than their void type.
        res.bcx.build.Ret(C_nil());
1706
    }
1707 1708
}

1709 1710 1711 1712 1713 1714 1715 1716 1717
fn trans_tag_variant(@crate_ctxt cx, ast.def_id tag_id,
                     &ast.variant variant) {
    if (_vec.len[@ast.ty](variant.args) == 0u) {
        ret;    // nullary constructors are just constants
    }

    // TODO
}

1718
impure fn trans_item(@crate_ctxt cx, &ast.item item) {
1719
    alt (item.node) {
1720
        case (ast.item_fn(?name, ?f, _, ?fid, ?ann)) {
1721
            auto sub_cx = @rec(path=cx.path + "." + name with *cx);
1722
            trans_fn(sub_cx, f, fid, ann);
1723
        }
1724 1725
        case (ast.item_mod(?name, ?m, _)) {
            auto sub_cx = @rec(path=cx.path + "." + name with *cx);
1726
            trans_mod(sub_cx, m);
1727
        }
1728 1729 1730 1731 1732 1733
        case (ast.item_tag(?name, ?variants, _, ?tag_id)) {
            auto sub_cx = @rec(path=cx.path + "." + name with *cx);
            for (ast.variant variant in variants) {
                trans_tag_variant(sub_cx, tag_id, variant);
            }
        }
1734
        case (_) { /* fall through */ }
1735 1736 1737
    }
}

1738
impure fn trans_mod(@crate_ctxt cx, &ast._mod m) {
1739 1740
    for (@ast.item item in m.items) {
        trans_item(cx, *item);
1741 1742 1743
    }
}

1744

1745 1746 1747 1748 1749 1750
fn resolve_tag_types_for_item(&@crate_ctxt cx, @ast.item i) -> @crate_ctxt {
    alt (i.node) {
        case (ast.item_tag(_, ?variants, _, ?tag_id)) {
            let vec[TypeRef] variant_tys = vec();

            auto info = cx.tags.get(tag_id);
1751
            let vec[tup(ast.def_id,arity)] variant_info = vec();
1752 1753 1754 1755 1756

            auto tag_ty;
            if (_vec.len[ast.variant](variants) == 0u) {
                tag_ty = T_struct(vec(T_int()));
            } else {
1757
                auto n_ary_idx = 0u;
1758
                for (ast.variant variant in variants) {
1759
                    auto arity_info;
1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772
                    if (_vec.len[@ast.ty](variant.args) > 0u) {
                        let vec[TypeRef] lltys = vec();

                        alt (typeck.ann_to_type(variant.ann).struct) {
                            case (typeck.ty_fn(?args, _)) {
                                for (typeck.arg arg in args) {
                                    lltys += vec(type_of(cx, arg.ty));
                                }
                            }
                            case (_) { fail; }
                        }

                        variant_tys += vec(T_struct(lltys));
1773
                        arity_info = n_ary;
1774
                    } else {
1775
                        variant_tys += vec(T_nil());
1776
                        arity_info = nullary;
1777 1778
                    }

1779
                    variant_info += vec(tup(variant.id, arity_info));
1780 1781 1782 1783 1784
                }

                tag_ty = T_struct(vec(T_int(), T_union(variant_tys)));
            }

1785 1786
            info.variants = variant_info;

1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797
            auto th = cx.tags.get(tag_id).th.llth;
            llvm.LLVMRefineType(llvm.LLVMResolveTypeHandle(th), tag_ty);
        }
        case (_) {
            // fall through
        }
    }

    ret cx;
}

1798
fn collect_item(&@crate_ctxt cx, @ast.item i) -> @crate_ctxt {
1799
    alt (i.node) {
1800 1801
        case (ast.item_fn(?name, ?f, _, ?fid, ?ann)) {
            // TODO: type-params
1802 1803
            cx.items.insert(fid, i);
            auto llty = node_type(cx, ann);
1804
            let str s = cx.names.next("_rust_fn") + "." + name;
1805
            let ValueRef llfn = decl_fastcall_fn(cx.llmod, s, llty);
1806
            cx.item_ids.insert(fid, llfn);
1807 1808 1809 1810 1811
        }

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

        case (ast.item_tag(_, ?variants, _, ?tag_id)) {
            auto vi = new_def_hash[uint]();
            auto navi = new_def_hash[uint]();
1816 1817 1818
            let vec[tup(ast.def_id,arity)] variant_info = vec();
            cx.tags.insert(tag_id, @rec(th=mk_type_handle(),
                                        mutable variants=variant_info));
1819 1820
        }

1821
        case (_) { /* fall through */ }
1822 1823 1824 1825 1826
    }
    ret cx;
}


1827
fn collect_items(@crate_ctxt cx, @ast.crate crate) {
1828

1829 1830
    let fold.ast_fold[@crate_ctxt] fld =
        fold.new_identity_fold[@crate_ctxt]();
1831 1832 1833 1834

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

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

1838 1839 1840 1841 1842 1843 1844 1845 1846 1847
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);
}

1848 1849 1850 1851
fn p2i(ValueRef v) -> ValueRef {
    ret llvm.LLVMConstPtrToInt(v, T_int());
}

1852
fn trans_exit_task_glue(@crate_ctxt cx) {
1853 1854 1855 1856 1857 1858 1859
    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,
1860
                    llargs=new_def_hash[ValueRef](),
1861
                    lllocals=new_def_hash[ValueRef](),
1862
                    ccx=cx);
1863

1864
    auto bcx = new_top_block_ctxt(fcx);
1865
    trans_upcall(bcx, "upcall_exit", V_args);
1866
    bcx.build.RetVoid();
1867 1868
}

1869
fn crate_constant(@crate_ctxt cx) -> ValueRef {
1870 1871

    let ValueRef crate_ptr =
1872
        llvm.LLVMAddGlobal(cx.llmod, T_crate(),
1873 1874 1875 1876 1877 1878 1879 1880 1881 1882
                           _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);

1883 1884
    let ValueRef exit_task_glue_off =
        llvm.LLVMConstSub(p2i(cx.glues.exit_task_glue), crate_addr);
1885 1886 1887

    let ValueRef crate_val =
        C_struct(vec(C_null(T_int()),     // ptrdiff_t image_base_off
1888
                     p2i(crate_ptr),      // uintptr_t self_addr
1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906
                     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;
}

1907
fn trans_main_fn(@crate_ctxt cx, ValueRef llcrate) {
1908 1909 1910
    auto T_main_args = vec(T_int(), T_int());
    auto T_rust_start_args = vec(T_int(), T_int(), T_int(), T_int());

1911 1912 1913 1914 1915 1916 1917
    auto main_name;
    if (_str.eq(std.os.target_os(), "win32")) {
        main_name = "WinMain@16";
    } else {
        main_name = "main";
    }

1918
    auto llmain =
1919
        decl_cdecl_fn(cx.llmod, main_name, T_fn(T_main_args, T_int()));
1920

1921 1922
    auto llrust_start = decl_cdecl_fn(cx.llmod, "rust_start",
                                      T_fn(T_rust_start_args, T_int()));
1923 1924 1925

    auto llargc = llvm.LLVMGetParam(llmain, 0u);
    auto llargv = llvm.LLVMGetParam(llmain, 1u);
1926 1927
    check (cx.item_names.contains_key("_rust.main"));
    auto llrust_main = cx.item_names.get("_rust.main");
1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938

    //
    // 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(""));
1939
    auto b = new_builder(llbb, "");
1940 1941 1942 1943 1944 1945 1946

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

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

}

1947 1948
fn declare_intrinsics(ModuleRef llmod) -> hashmap[str,ValueRef] {

1949
    let vec[TypeRef] T_trap_args = vec();
1950 1951 1952 1953
    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());
1954 1955
    auto trap = decl_cdecl_fn(llmod, "llvm.trap",
                              T_fn(T_trap_args, T_void()));
1956 1957 1958 1959
    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()));
1960 1961 1962

    auto intrinsics = new_str_hash[ValueRef]();
    intrinsics.insert("llvm.trap", trap);
1963 1964
    intrinsics.insert("llvm.memcpy.p0i8.p0i8.i32", memcpy32);
    intrinsics.insert("llvm.memcpy.p0i8.p0i8.i64", memcpy64);
1965
    ret intrinsics;
1966 1967
}

1968
fn trans_crate(session.session sess, @ast.crate crate, str output) {
1969 1970 1971 1972
    auto llmod =
        llvm.LLVMModuleCreateWithNameInContext(_str.buf("rust_out"),
                                               llvm.LLVMGetGlobalContext());

1973 1974
    llvm.LLVMSetModuleInlineAsm(llmod, _str.buf(x86.get_module_asm()));

1975
    auto intrinsics = declare_intrinsics(llmod);
1976

1977 1978 1979
    auto glues = @rec(activate_glue = decl_glue(llmod,
                                                abi.activate_glue_name()),
                      yield_glue = decl_glue(llmod, abi.yield_glue_name()),
1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993
                      /*
                       * 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(),
1994
                                    T_fn(vec(T_taskptr()), T_void())),
1995

1996 1997 1998 1999
                      upcall_glues =
                      _vec.init_fn[ValueRef](bind decl_upcall(llmod, _),
                                             abi.n_upcall_glues as uint));

2000 2001 2002
    auto cx = @rec(sess = sess,
                   llmod = llmod,
                   upcalls = new_str_hash[ValueRef](),
2003
                   intrinsics = intrinsics,
2004 2005
                   item_names = new_str_hash[ValueRef](),
                   item_ids = new_def_hash[ValueRef](),
2006
                   items = new_def_hash[@ast.item](),
2007
                   tags = new_def_hash[@tag_info](),
2008
                   glues = glues,
2009
                   names = namegen(0),
2010
                   path = "_rust");
2011

2012
    collect_items(cx, crate);
2013 2014
    resolve_tag_types(cx, crate);

2015
    trans_mod(cx, crate.node.module);
2016
    trans_exit_task_glue(cx);
2017 2018
    trans_main_fn(cx, crate_constant(cx));

2019
    llvm.LLVMWriteBitcodeToFile(llmod, _str.buf(output));
2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032
    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:
//