trans.rs 37.2 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.util.option;
import std.util.some;
import std.util.none;
9

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

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

import lib.llvm.llvm;
import lib.llvm.builder;
22 23 24 25 26
import lib.llvm.llvm.ModuleRef;
import lib.llvm.llvm.ValueRef;
import lib.llvm.llvm.TypeRef;
import lib.llvm.llvm.BuilderRef;
import lib.llvm.llvm.BasicBlockRef;
27

28 29
import lib.llvm.False;
import lib.llvm.True;
30

31 32 33 34 35 36 37
state obj namegen(mutable int i) {
    fn next(str prefix) -> str {
        i += 1;
        ret prefix + istr(i);
    }
}

38 39
type glue_fns = rec(ValueRef activate_glue,
                    ValueRef yield_glue,
40
                    ValueRef exit_task_glue,
41 42
                    vec[ValueRef] upcall_glues);

43 44
state type trans_ctxt = rec(session.session sess,
                            ModuleRef llmod,
45 46 47
                            hashmap[str, ValueRef] upcalls,
                            hashmap[str, ValueRef] fn_names,
                            hashmap[ast.def_id, ValueRef] fn_ids,
48
                            hashmap[ast.def_id, @ast.item] items,
49 50 51
                            @glue_fns glues,
                            namegen names,
                            str path);
52

53 54 55
state type fn_ctxt = rec(ValueRef llfn,
                         ValueRef lloutptr,
                         ValueRef lltaskptr,
56
                         hashmap[ast.def_id, ValueRef] llargs,
57
                         hashmap[ast.def_id, ValueRef] lllocals,
58
                         @trans_ctxt tcx);
59 60 61

type terminator = fn(@fn_ctxt cx, builder build);

62
tag cleanup {
63
    clean(fn(@block_ctxt cx) -> result);
64 65 66 67 68 69 70 71 72
}

state type block_ctxt = rec(BasicBlockRef llbb,
                            builder build,
                            terminator term,
                            mutable vec[cleanup] cleanups,
                            @fn_ctxt fcx);


73 74 75 76 77 78 79 80
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);
}

81 82 83 84 85 86 87 88 89 90 91
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));
}
92 93 94 95


// LLVM type constructors.

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

110 111 112 113 114
fn T_nil() -> TypeRef {
    // NB: See above in T_void().
    ret llvm.LLVMInt1Type();
}

115 116 117 118
fn T_i1() -> TypeRef {
    ret llvm.LLVMInt1Type();
}

119 120 121 122 123 124 125 126 127
fn T_i8() -> TypeRef {
    ret llvm.LLVMInt8Type();
}

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

fn T_i32() -> TypeRef {
128 129 130
    ret llvm.LLVMInt32Type();
}

131 132 133 134
fn T_i64() -> TypeRef {
    ret llvm.LLVMInt64Type();
}

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

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

143 144 145 146
fn T_bool() -> TypeRef {
    ret T_i1();
}

147 148 149 150 151
fn T_int() -> TypeRef {
    // FIXME: switch on target type.
    ret T_i32();
}

152 153 154 155
fn T_char() -> TypeRef {
    ret T_i32();
}

156 157 158 159
fn T_fn(vec[TypeRef] inputs, TypeRef output) -> TypeRef {
    ret llvm.LLVMFunctionType(output,
                              _vec.buf[TypeRef](inputs),
                              _vec.len[TypeRef](inputs),
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
                              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);
}

fn T_opaque() -> TypeRef {
    ret llvm.LLVMOpaqueType();
}

fn T_task() -> TypeRef {
    ret T_struct(vec(T_int(),      // Refcount
179 180 181 182 183 184 185 186 187 188
                     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
                     ));
}

189 190 191 192 193
fn T_array(TypeRef t, uint n) -> TypeRef {
    ret llvm.LLVMArrayType(t, n);
}

fn T_vec(TypeRef t, uint n) -> TypeRef {
194
    ret T_struct(vec(T_int(),      // Refcount
195 196 197
                     T_int(),      // Alloc
                     T_int(),      // Fill
                     T_array(t, n) // Body elements
198 199 200
                     ));
}

201 202 203 204
fn T_str(uint n) -> TypeRef {
    ret T_vec(T_i8(), n);
}

205 206 207 208
fn T_box(TypeRef t) -> TypeRef {
    ret T_struct(vec(T_int(), t));
}

209 210 211 212 213 214 215 216 217 218 219 220 221 222
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
223
                     T_int()       // int n_libs
224 225 226
                     ));
}

227 228 229 230 231 232
fn T_double() -> TypeRef {
    ret llvm.LLVMDoubleType();
}

fn T_taskptr() -> TypeRef {
    ret T_ptr(T_task());
233 234
}

235 236 237
fn type_of(@trans_ctxt cx, @ast.ty t) -> TypeRef {
    alt (t.node) {
        case (ast.ty_nil) { ret T_nil(); }
238
        case (ast.ty_bool) { ret T_bool(); }
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
        case (ast.ty_int) { ret T_int(); }
        case (ast.ty_uint) { ret T_int(); }
        case (ast.ty_machine(?tm)) {
            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(); }
            }
        }
        case (ast.ty_char) { ret T_char(); }
        case (ast.ty_str) { ret T_str(0u); }
        case (ast.ty_box(?t)) {
            ret T_ptr(T_box(type_of(cx, t)));
        }
        case (ast.ty_vec(?t)) {
            ret T_ptr(T_vec(type_of(cx, t), 0u));
        }
        case (ast.ty_tup(?elts)) {
            let vec[TypeRef] tys = vec();
            for (tup(bool, @ast.ty) elt in elts) {
                tys += type_of(cx, elt._1);
            }
            ret T_struct(tys);
        }
        case (ast.ty_path(?pth,  ?def)) {
            // FIXME: implement.
            cx.sess.unimpl("ty_path in trans.type_of");
        }
    }
    fail;
}

278 279 280 281 282 283
// LLVM constant constructors.

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

284
fn C_integral(int i, TypeRef t) -> ValueRef {
285 286 287 288 289 290
    // 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);
    //
291 292 293
    ret llvm.LLVMConstIntOfString(t, _str.buf(istr(i)), 10);
}

294 295 296 297 298
fn C_nil() -> ValueRef {
    // NB: See comment above in T_void().
    ret C_integral(0, T_i1());
}

299 300
fn C_bool(bool b) -> ValueRef {
    if (b) {
301
        ret C_integral(1, T_bool());
302
    } else {
303
        ret C_integral(0, T_bool());
304 305 306
    }
}

307 308
fn C_int(int i) -> ValueRef {
    ret C_integral(i, T_int());
309 310
}

311 312
fn C_str(@trans_ctxt cx, str s) -> ValueRef {
    auto sc = llvm.LLVMConstString(_str.buf(s), _str.byte_len(s), False);
313
    auto g = llvm.LLVMAddGlobal(cx.llmod, val_ty(sc),
314 315 316
                                _str.buf(cx.names.next("str")));
    llvm.LLVMSetInitializer(g, sc);
    ret g;
317 318 319 320 321 322 323 324
}

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

325 326 327 328 329 330 331 332 333 334
fn decl_cdecl_fn(ModuleRef llmod, str name,
                 vec[TypeRef] inputs, TypeRef output) -> ValueRef {
    let TypeRef llty = T_fn(inputs, output);
    let ValueRef llfn =
        llvm.LLVMAddFunction(llmod, _str.buf(name), llty);
    llvm.LLVMSetFunctionCallConv(llfn, lib.llvm.LLVMCCallConv);
    ret llfn;
}

fn decl_glue(ModuleRef llmod, str s) -> ValueRef {
335
    ret decl_cdecl_fn(llmod, s, vec(T_taskptr()), T_void());
336 337
}

338
fn decl_upcall(ModuleRef llmod, uint _n) -> ValueRef {
339 340 341 342
    // 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.
343
    let int n = _n as int;
344
    let str s = abi.upcall_glue_name(n);
345
    let vec[TypeRef] args =
346 347
        vec(T_taskptr(), // taskptr
            T_int())     // callee
348 349 350 351 352
        + _vec.init_elt[TypeRef](T_int(), n as uint);

    ret decl_cdecl_fn(llmod, s, args, T_int());
}

353
fn get_upcall(@trans_ctxt cx, str name, int n_args) -> ValueRef {
354 355 356
    if (cx.upcalls.contains_key(name)) {
        ret cx.upcalls.get(name);
    }
357
    auto inputs = vec(T_taskptr());
358
    inputs += _vec.init_elt[TypeRef](T_int(), n_args as uint);
359
    auto output = T_int();
360 361 362 363 364
    auto f = decl_cdecl_fn(cx.llmod, name, inputs, output);
    cx.upcalls.insert(name, f);
    ret f;
}

365
fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args) -> result {
366 367 368 369 370
    let int n = _vec.len[ValueRef](args) as int;
    let ValueRef llupcall = get_upcall(cx.fcx.tcx, name, n);
    llupcall = llvm.LLVMConstPointerCast(llupcall, T_int());

    let ValueRef llglue = cx.fcx.tcx.glues.upcall_glues.(n);
371 372 373 374
    let vec[ValueRef] call_args = vec(cx.fcx.lltaskptr, llupcall);
    for (ValueRef a in args) {
        call_args += cx.build.ZExtOrBitCast(a, T_int());
    }
375

376
    ret res(cx, cx.build.Call(llglue, call_args));
377 378
}

379 380 381
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)));
382 383
}

384 385
fn decr_refcnt_and_if_zero(@block_ctxt cx,
                           ValueRef box_ptr,
386 387
                           fn(@block_ctxt cx) -> result inner,
                           TypeRef t_else, ValueRef v_else) -> result {
388 389 390 391 392 393
    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);
    rc = cx.build.Sub(rc, C_int(1));
    cx.build.Store(rc, rc_ptr);
    auto test = cx.build.ICmp(lib.llvm.LLVMIntEQ, C_int(0), rc);
394 395 396 397 398 399 400 401 402
    auto next_cx = new_extension_block_ctxt(cx);
    auto then_cx = new_empty_block_ctxt(cx.fcx);
    auto then_res = inner(then_cx);
    then_res.bcx.build.Br(next_cx.llbb);
    cx.build.CondBr(test, then_res.bcx.llbb, next_cx.llbb);
    auto phi = next_cx.build.Phi(t_else,
                                 vec(v_else, then_res.val),
                                 vec(cx.llbb, then_res.bcx.llbb));
    ret res(next_cx, phi);
403 404
}

405 406 407 408
fn trans_drop_str(@block_ctxt cx, ValueRef v) -> result {
    ret decr_refcnt_and_if_zero(cx, v,
                                bind trans_non_gc_free(_, v),
                                T_int(), C_int(0));
409 410
}

411
fn trans_lit(@block_ctxt cx, &ast.lit lit) -> result {
412
    alt (lit.node) {
413
        case (ast.lit_int(?i)) {
414
            ret res(cx, C_int(i));
415 416
        }
        case (ast.lit_uint(?u)) {
417
            ret res(cx, C_int(u as int));
418 419
        }
        case (ast.lit_char(?c)) {
420
            ret res(cx, C_integral(c as int, T_char()));
421 422
        }
        case (ast.lit_bool(?b)) {
423 424 425 426
            ret res(cx, C_bool(b));
        }
        case (ast.lit_nil) {
            ret res(cx, C_nil());
427 428 429
        }
        case (ast.lit_str(?s)) {
            auto len = (_str.byte_len(s) as int) + 1;
430 431 432 433 434 435 436
            auto sub = trans_upcall(cx, "upcall_new_str",
                                    vec(p2i(C_str(cx.fcx.tcx, s)),
                                        C_int(len)));
            sub.val = sub.bcx.build.IntToPtr(sub.val,
                                             T_ptr(T_str(len as uint)));
            cx.cleanups += vec(clean(bind trans_drop_str(_, sub.val)));
            ret sub;
437 438 439 440
        }
    }
}

441 442 443 444
fn trans_unary(@block_ctxt cx, ast.unop op, &ast.expr e) -> result {

    auto sub = trans_expr(cx, e);

445 446
    alt (op) {
        case (ast.bitnot) {
447 448
            sub.val = cx.build.Not(sub.val);
            ret sub;
449 450
        }
        case (ast.not) {
451 452
            sub.val = cx.build.Not(sub.val);
            ret sub;
453 454 455
        }
        case (ast.neg) {
            // FIXME: switch by signedness.
456 457
            sub.val = cx.build.Neg(sub.val);
            ret sub;
458 459 460 461 462 463 464
        }
    }
    cx.fcx.tcx.sess.unimpl("expr variant in trans_unary");
    fail;
}

fn trans_binary(@block_ctxt cx, ast.binop op,
465 466
                &ast.expr a, &ast.expr b) -> result {

467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
    // First couple cases are lazy:

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

            auto rhs_cx = new_empty_block_ctxt(cx.fcx);
            auto rhs_res = trans_expr(rhs_cx, b);

            auto next_cx = new_extension_block_ctxt(cx);
            rhs_res.bcx.build.Br(next_cx.llbb);

            lhs_res.bcx.build.CondBr(lhs_res.val,
                                     rhs_cx.llbb,
                                     next_cx.llbb);
            auto phi = next_cx.build.Phi(T_bool(),
                                         vec(lhs_res.val,
                                             rhs_res.val),
                                         vec(lhs_res.bcx.llbb,
                                             rhs_res.bcx.llbb));
            ret res(next_cx, phi);
        }

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

            auto rhs_cx = new_empty_block_ctxt(cx.fcx);
            auto rhs_res = trans_expr(rhs_cx, b);

            auto next_cx = new_extension_block_ctxt(cx);
            rhs_res.bcx.build.Br(next_cx.llbb);

            lhs_res.bcx.build.CondBr(lhs_res.val,
                                     next_cx.llbb,
                                     rhs_cx.llbb);
            auto phi = next_cx.build.Phi(T_bool(),
                                         vec(lhs_res.val,
                                             rhs_res.val),
                                         vec(lhs_res.bcx.llbb,
                                             rhs_res.bcx.llbb));
            ret res(next_cx, phi);
        }
    }

    // Remaining cases are eager:

515 516 517
    auto lhs = trans_expr(cx, a);
    auto sub = trans_expr(lhs.bcx, b);

518 519
    alt (op) {
        case (ast.add) {
520 521
            sub.val = cx.build.Add(lhs.val, sub.val);
            ret sub;
522 523 524
        }

        case (ast.sub) {
525 526
            sub.val = cx.build.Sub(lhs.val, sub.val);
            ret sub;
527 528 529 530
        }

        case (ast.mul) {
            // FIXME: switch by signedness.
531 532
            sub.val = cx.build.Mul(lhs.val, sub.val);
            ret sub;
533 534 535 536
        }

        case (ast.div) {
            // FIXME: switch by signedness.
537 538
            sub.val = cx.build.SDiv(lhs.val, sub.val);
            ret sub;
539 540 541 542
        }

        case (ast.rem) {
            // FIXME: switch by signedness.
543 544
            sub.val = cx.build.SRem(lhs.val, sub.val);
            ret sub;
545 546 547
        }

        case (ast.bitor) {
548 549
            sub.val = cx.build.Or(lhs.val, sub.val);
            ret sub;
550 551 552
        }

        case (ast.bitand) {
553 554
            sub.val = cx.build.And(lhs.val, sub.val);
            ret sub;
555 556 557
        }

        case (ast.bitxor) {
558 559
            sub.val = cx.build.Xor(lhs.val, sub.val);
            ret sub;
560 561 562
        }

        case (ast.lsl) {
563 564
            sub.val = cx.build.Shl(lhs.val, sub.val);
            ret sub;
565 566 567
        }

        case (ast.lsr) {
568 569
            sub.val = cx.build.LShr(lhs.val, sub.val);
            ret sub;
570 571 572
        }

        case (ast.asr) {
573 574
            sub.val = cx.build.AShr(lhs.val, sub.val);
            ret sub;
575 576 577
        }

        case (ast.eq) {
578 579
            sub.val = cx.build.ICmp(lib.llvm.LLVMIntEQ, lhs.val, sub.val);
            ret sub;
580 581 582
        }

        case (ast.ne) {
583 584
            sub.val = cx.build.ICmp(lib.llvm.LLVMIntNE, lhs.val, sub.val);
            ret sub;
585 586 587 588
        }

        case (ast.lt) {
            // FIXME: switch by signedness.
589 590
            sub.val = cx.build.ICmp(lib.llvm.LLVMIntSLT, lhs.val, sub.val);
            ret sub;
591 592 593 594
        }

        case (ast.le) {
            // FIXME: switch by signedness.
595 596
            sub.val = cx.build.ICmp(lib.llvm.LLVMIntSLE, lhs.val, sub.val);
            ret sub;
597 598 599 600
        }

        case (ast.ge) {
            // FIXME: switch by signedness.
601 602
            sub.val = cx.build.ICmp(lib.llvm.LLVMIntSGE, lhs.val, sub.val);
            ret sub;
603 604 605 606
        }

        case (ast.gt) {
            // FIXME: switch by signedness.
607 608
            sub.val = cx.build.ICmp(lib.llvm.LLVMIntSGT, lhs.val, sub.val);
            ret sub;
609 610 611 612 613 614
        }
    }
    cx.fcx.tcx.sess.unimpl("expr variant in trans_binary");
    fail;
}

615 616 617 618 619 620 621 622 623 624 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 652 653 654 655
fn trans_if(@block_ctxt cx, &ast.expr cond,
            &ast.block thn, &option[ast.block] els) -> result {

    auto cond_res = trans_expr(cx, cond);

    auto then_cx = new_empty_block_ctxt(cx.fcx);
    auto then_res = trans_block(then_cx, thn);

    auto next_cx = new_extension_block_ctxt(cx);
    then_res.bcx.build.Br(next_cx.llbb);
    auto phi;

    alt (els) {
        case (some[ast.block](?eblk)) {
            auto else_cx = new_empty_block_ctxt(cx.fcx);
            auto else_res = trans_block(else_cx, eblk);
            cond_res.bcx.build.CondBr(cond_res.val,
                                      then_cx.llbb,
                                      else_cx.llbb);
            else_res.bcx.build.Br(next_cx.llbb);
            phi = next_cx.build.Phi(T_nil(),
                                    vec(then_res.val,
                                        else_res.val),
                                    vec(then_res.bcx.llbb,
                                        else_res.bcx.llbb));
        }

        case (_) {
            cond_res.bcx.build.CondBr(cond_res.val,
                                      then_cx.llbb,
                                      next_cx.llbb);
            phi = next_cx.build.Phi(T_nil(),
                                    vec(then_res.val, C_nil()),
                                    vec(then_res.bcx.llbb,
                                        cond_res.bcx.llbb));
        }
    }

    ret res(next_cx, phi);
}

656 657 658 659 660
// The additional bool returned indicates whether it's a local
// (that is represented as an alloca, hence needs a 'load' to be
// used as an rval).

fn trans_lval(@block_ctxt cx, &ast.expr e) -> tup(result, bool) {
G
Graydon Hoare 已提交
661 662 663 664 665
    alt (e.node) {
        case (ast.expr_name(?n, ?dopt, _)) {
            alt (dopt) {
                case (some[ast.def](?def)) {
                    alt (def) {
666 667 668
                        case (ast.def_arg(?did)) {
                            ret tup(res(cx, cx.fcx.llargs.get(did)), false);
                        }
G
Graydon Hoare 已提交
669
                        case (ast.def_local(?did)) {
670
                            ret tup(res(cx, cx.fcx.lllocals.get(did)), true);
G
Graydon Hoare 已提交
671
                        }
672
                        case (ast.def_fn(?did)) {
673 674
                            ret tup(res(cx, cx.fcx.tcx.fn_ids.get(did)),
                                    false);
675
                        }
G
Graydon Hoare 已提交
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
                        case (_) {
                            cx.fcx.tcx.sess.unimpl("def variant in trans");
                        }
                    }
                }
                case (none[ast.def]) {
                    cx.fcx.tcx.sess.err("unresolved expr_name in trans");
                }
            }
        }
    }
    cx.fcx.tcx.sess.unimpl("expr variant in trans_lval");
    fail;
}

691 692 693 694 695 696 697 698 699 700 701 702 703 704
fn trans_exprs(@block_ctxt cx, &vec[@ast.expr] es)
    -> tup(@block_ctxt, vec[ValueRef]) {
    let vec[ValueRef] vs = vec();
    let @block_ctxt bcx = cx;

    for (@ast.expr e in es) {
        auto res = trans_expr(bcx, *e);
        vs += res.val;
        bcx = res.bcx;
    }

    ret tup(bcx, vs);
}

705
fn trans_expr(@block_ctxt cx, &ast.expr e) -> result {
706
    alt (e.node) {
P
Patrick Walton 已提交
707
        case (ast.expr_lit(?lit, _)) {
708 709 710
            ret trans_lit(cx, *lit);
        }

P
Patrick Walton 已提交
711
        case (ast.expr_unary(?op, ?x, _)) {
712 713 714
            ret trans_unary(cx, op, *x);
        }

P
Patrick Walton 已提交
715
        case (ast.expr_binary(?op, ?x, ?y, _)) {
716
            ret trans_binary(cx, op, *x, *y);
717
        }
718

P
Patrick Walton 已提交
719
        case (ast.expr_if(?cond, ?thn, ?els, _)) {
720 721 722
            ret trans_if(cx, *cond, thn, els);
        }

P
Patrick Walton 已提交
723
        case (ast.expr_block(?blk, _)) {
724 725 726 727 728 729 730 731 732
            auto sub_cx = new_empty_block_ctxt(cx.fcx);
            auto next_cx = new_extension_block_ctxt(cx);
            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);
        }
733

G
Graydon Hoare 已提交
734 735
        case (ast.expr_name(_,_,_)) {
            auto sub = trans_lval(cx, e);
736 737 738 739 740
            if (sub._1) {
                ret res(sub._0.bcx, cx.build.Load(sub._0.val));
            } else {
                ret sub._0;
            }
G
Graydon Hoare 已提交
741 742 743 744
        }

        case (ast.expr_assign(?dst, ?src, _)) {
            auto lhs_res = trans_lval(cx, *dst);
745 746
            check (lhs_res._1);
            auto rhs_res = trans_expr(lhs_res._0.bcx, *src);
G
Graydon Hoare 已提交
747
            ret res(rhs_res.bcx,
748
                    cx.build.Store(rhs_res.val, lhs_res._0.val));
749
        }
G
Graydon Hoare 已提交
750

751 752
        case (ast.expr_call(?f, ?args, _)) {
            auto f_res = trans_lval(cx, *f);
753 754
            check (! f_res._1);
            auto args_res = trans_exprs(f_res._0.bcx, args);
755 756 757 758
            auto llargs = vec(cx.fcx.lloutptr,
                              cx.fcx.lltaskptr);
            llargs += args_res._1;
            ret res(args_res._0,
759
                    cx.build.Call(f_res._0.val, llargs));
760 761
        }

762 763 764 765 766
    }
    cx.fcx.tcx.sess.unimpl("expr variant in trans_expr");
    fail;
}

767
fn trans_log(@block_ctxt cx, &ast.expr e) -> result {
768
    alt (e.node) {
P
Patrick Walton 已提交
769
        case (ast.expr_lit(?lit, _)) {
770
            alt (lit.node) {
771
                case (ast.lit_str(_)) {
772 773 774 775 776
                    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));
777
                }
778

779
                case (_) {
780 781 782 783
                    auto sub = trans_expr(cx, e);
                    ret trans_upcall(sub.bcx,
                                     "upcall_log_int",
                                     vec(sub.val));
784 785 786
                }
            }
        }
787

788
        case (_) {
789 790
            auto sub = trans_expr(cx, e);
            ret trans_upcall(sub.bcx, "upcall_log_int", vec(sub.val));
791 792
        }
    }
793 794
}

795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814
fn trans_check_expr(@block_ctxt cx, &ast.expr e) -> result {
    auto cond_res = trans_expr(cx, e);

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

    auto fail_cx = new_empty_block_ctxt(cx.fcx);
    auto fail_res = trans_upcall(fail_cx, "upcall_fail", args);

    auto next_cx = new_extension_block_ctxt(cx);
    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());
}

815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830
fn trans_ret(@block_ctxt cx, &option[@ast.expr] e) -> result {
    auto r = res(cx, C_nil());
    alt (e) {
        case (some[@ast.expr](?x)) {
            r = trans_expr(cx, *x);
            r.bcx.build.Store(r.val, cx.fcx.lloutptr);
        }
    }
    // FIXME: if we actually ret here, the block structure falls apart;
    // need to do something more-clever with terminators and block cleanup.
    // Mean time 'ret' means 'copy result to output slot and keep going'.

    // r.val = r.bcx.build.RetVoid();
    ret r;
}

831 832
fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
    auto sub = res(cx, C_nil());
833
    alt (s.node) {
834
        case (ast.stmt_log(?a)) {
835 836 837
            sub.bcx = trans_log(cx, *a).bcx;
        }

838 839 840 841
        case (ast.stmt_check_expr(?a)) {
            sub.bcx = trans_check_expr(cx, *a).bcx;
        }

842 843 844 845
        case (ast.stmt_ret(?e)) {
            sub.bcx = trans_ret(cx, e).bcx;
        }

846 847
        case (ast.stmt_expr(?e)) {
            sub.bcx = trans_expr(cx, *e).bcx;
848
        }
849

850 851 852 853 854 855 856 857 858 859 860 861 862
        case (ast.stmt_decl(?d)) {
            alt (d.node) {
                case (ast.decl_local(?local)) {
                    alt (local.init) {
                        case (some[@ast.expr](?e)) {
                            auto llptr = cx.fcx.lllocals.get(local.id);
                            sub = trans_expr(cx, *e);
                            sub.val = sub.bcx.build.Store(sub.val, llptr);
                        }
                    }
                }
            }
        }
863
        case (_) {
864
            cx.fcx.tcx.sess.unimpl("stmt variant");
865 866
        }
    }
867
    ret sub;
868 869
}

870 871 872 873 874 875
fn new_builder(BasicBlockRef llbb) -> builder {
    let BuilderRef llbuild = llvm.LLVMCreateBuilder();
    llvm.LLVMPositionBuilderAtEnd(llbuild, llbb);
    ret builder(llbuild);
}

876 877 878 879
// You probably don't want to use this one. See the
// next three functions instead.
fn new_block_ctxt(@fn_ctxt cx, terminator term,
                  vec[cleanup] cleanups) -> @block_ctxt {
880
    let BasicBlockRef llbb =
881
        llvm.LLVMAppendBasicBlock(cx.llfn, _str.buf(""));
882 883 884
    ret @rec(llbb=llbb,
             build=new_builder(llbb),
             term=term,
885
             mutable cleanups=cleanups,
886 887 888
             fcx=cx);
}

889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907
// Use this when you are making a block_ctxt to replace the
// current one, i.e. when chaining together sequences of stmts
// or making sub-blocks you will branch back out of and wish to
// "carry on" in the parent block's context.
fn new_extension_block_ctxt(@block_ctxt bcx) -> @block_ctxt {
    ret new_block_ctxt(bcx.fcx, bcx.term, bcx.cleanups);
}

// 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 {
    fn terminate_ret_void(@fn_ctxt cx, builder build) {
        build.RetVoid();
    }
    auto term = terminate_ret_void;
    let vec[cleanup] cleanups = vec();
    ret new_block_ctxt(fcx, term, cleanups);

}

908 909 910
// Use this when you are making a block_ctxt that starts with a fresh
// terminator and empty cleanups (no locals, no implicit return when
// falling off the end).
911 912
fn new_empty_block_ctxt(@fn_ctxt fcx) -> @block_ctxt {
    fn terminate_no_op(@fn_ctxt cx, builder build) {
913
    }
914 915 916 917
    auto term = terminate_no_op;
    let vec[cleanup] cleanups = vec();
    ret new_block_ctxt(fcx, term, cleanups);
}
918

919 920 921
fn trans_block_cleanups(@block_ctxt cx) -> @block_ctxt {
    auto bcx = cx;
    for (cleanup c in cx.cleanups) {
922
        alt (c) {
923
            case (clean(?cfn)) {
924
                bcx = cfn(bcx).bcx;
925 926 927
            }
        }
    }
928 929 930
    ret bcx;
}

931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946
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;
                    }
                }
            }
        }
    }
}

947 948 949
fn trans_block(@block_ctxt cx, &ast.block b) -> result {
    auto bcx = cx;

950 951 952 953 954 955 956 957 958 959 960 961 962 963
    for each (@ast.local local in block_locals(b)) {
        auto ty = T_nil();
        alt (local.ty) {
            case (some[@ast.ty](?t)) {
                ty = type_of(cx.fcx.tcx, t);
            }
            case (none[@ast.ty]) {
                cx.fcx.tcx.sess.err("missing type for local " + local.ident);
            }
        }
        auto val = bcx.build.Alloca(ty);
        cx.fcx.lllocals.insert(local.id, val);
    }

964
    for (@ast.stmt s in b.node.stmts) {
965 966
        bcx = trans_stmt(bcx, *s).bcx;
    }
967

968 969 970
    bcx = trans_block_cleanups(bcx);
    bcx.term(bcx.fcx, bcx.build);
    ret res(bcx, C_nil());
971 972
}

973 974
fn new_fn_ctxt(@trans_ctxt cx,
               str name,
975 976 977
               &ast._fn f,
               ast.def_id fid) -> @fn_ctxt {

978
    let ValueRef llfn = cx.fn_ids.get(fid);
979
    cx.fn_names.insert(cx.path, llfn);
980

981 982
    let ValueRef lloutptr = llvm.LLVMGetParam(llfn, 0u);
    let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 1u);
983

984
    let hashmap[ast.def_id, ValueRef] lllocals = new_def_hash[ValueRef]();
985 986
    let hashmap[ast.def_id, ValueRef] llargs = new_def_hash[ValueRef]();

987
    let uint arg_n = 2u;
988 989 990 991 992
    for (ast.arg arg in f.inputs) {
        llargs.insert(arg.id, llvm.LLVMGetParam(llfn, arg_n));
        arg_n += 1u;
    }

993 994 995
    ret @rec(llfn=llfn,
             lloutptr=lloutptr,
             lltaskptr=lltaskptr,
996
             llargs=llargs,
997
             lllocals=lllocals,
998 999 1000
             tcx=cx);
}

1001
fn trans_fn(@trans_ctxt cx, &ast._fn f, ast.def_id fid) {
1002

1003
    auto fcx = new_fn_ctxt(cx, cx.path, f, fid);
1004

1005
    trans_block(new_top_block_ctxt(fcx), f.body);
1006 1007
}

1008
fn trans_item(@trans_ctxt cx, &ast.item item) {
1009
    alt (item.node) {
1010
        case (ast.item_fn(?name, ?f, ?fid)) {
1011
            auto sub_cx = @rec(path=cx.path + "." + name with *cx);
1012
            trans_fn(sub_cx, f, fid);
1013
        }
1014 1015
        case (ast.item_mod(?name, ?m, _)) {
            auto sub_cx = @rec(path=cx.path + "." + name with *cx);
1016
            trans_mod(sub_cx, m);
1017 1018 1019 1020
        }
    }
}

1021
fn trans_mod(@trans_ctxt cx, &ast._mod m) {
1022 1023
    for (@ast.item item in m.items) {
        trans_item(cx, *item);
1024 1025 1026
    }
}

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 1058 1059 1060 1061 1062 1063
fn collect_item(&@trans_ctxt cx, @ast.item i) -> @trans_ctxt {
    alt (i.node) {
        case (ast.item_fn(?name, ?f, ?fid)) {
            cx.items.insert(fid, i);
            let vec[TypeRef] args = vec(T_ptr(type_of(cx, f.output)), // outptr.
                                        T_taskptr()   // taskptr
                                        );
            let vec[TypeRef] T_explicit_args = vec();
            for (ast.arg arg in f.inputs) {
                T_explicit_args += type_of(cx, arg.ty);
            }
            args += T_explicit_args;

            let str s = cx.names.next("_rust_fn") + "." + name;
            let ValueRef llfn = decl_cdecl_fn(cx.llmod, s, args, T_void());
            cx.fn_ids.insert(fid, llfn);
        }

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


fn collect_items(@trans_ctxt cx, @ast.crate crate) {

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

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

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

1064 1065 1066 1067
fn p2i(ValueRef v) -> ValueRef {
    ret llvm.LLVMConstPtrToInt(v, T_int());
}

1068 1069 1070 1071 1072 1073 1074 1075 1076 1077
fn trans_exit_task_glue(@trans_ctxt cx) {
    let vec[TypeRef] T_args = vec();
    let vec[ValueRef] V_args = vec();

    auto llfn = cx.glues.exit_task_glue;
    let ValueRef lloutptr = C_null(T_int());
    let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 0u);
    auto fcx = @rec(llfn=llfn,
                    lloutptr=lloutptr,
                    lltaskptr=lltaskptr,
1078
                    llargs=new_def_hash[ValueRef](),
1079
                    lllocals=new_def_hash[ValueRef](),
1080 1081
                    tcx=cx);

1082
    auto bcx = new_top_block_ctxt(fcx);
1083 1084 1085 1086
    trans_upcall(bcx, "upcall_exit", V_args);
    bcx.term(fcx, bcx.build);
}

1087 1088 1089
fn crate_constant(@trans_ctxt cx) -> ValueRef {

    let ValueRef crate_ptr =
1090
        llvm.LLVMAddGlobal(cx.llmod, T_crate(),
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100
                           _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);

1101 1102
    let ValueRef exit_task_glue_off =
        llvm.LLVMConstSub(p2i(cx.glues.exit_task_glue), crate_addr);
1103 1104 1105

    let ValueRef crate_val =
        C_struct(vec(C_null(T_int()),     // ptrdiff_t image_base_off
1106
                     p2i(crate_ptr),      // uintptr_t self_addr
1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124
                     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;
}

1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136
fn trans_main_fn(@trans_ctxt cx, ValueRef llcrate) {
    auto T_main_args = vec(T_int(), T_int());
    auto T_rust_start_args = vec(T_int(), T_int(), T_int(), T_int());

    auto llmain =
        decl_cdecl_fn(cx.llmod, "main", T_main_args, T_int());

    auto llrust_start =
        decl_cdecl_fn(cx.llmod, "rust_start", T_rust_start_args, T_int());

    auto llargc = llvm.LLVMGetParam(llmain, 0u);
    auto llargv = llvm.LLVMGetParam(llmain, 1u);
1137
    auto llrust_main = cx.fn_names.get("_rust.main");
1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156

    //
    // 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(""));
    auto b = new_builder(llbb);

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

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

}

1157
fn trans_crate(session.session sess, @ast.crate crate, str output) {
1158 1159 1160 1161
    auto llmod =
        llvm.LLVMModuleCreateWithNameInContext(_str.buf("rust_out"),
                                               llvm.LLVMGetGlobalContext());

1162 1163
    llvm.LLVMSetModuleInlineAsm(llmod, _str.buf(x86.get_module_asm()));

1164 1165 1166
    auto glues = @rec(activate_glue = decl_glue(llmod,
                                                abi.activate_glue_name()),
                      yield_glue = decl_glue(llmod, abi.yield_glue_name()),
1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180
                      /*
                       * 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(),
1181
                                    vec(T_taskptr()), T_void()),
1182

1183 1184 1185 1186
                      upcall_glues =
                      _vec.init_fn[ValueRef](bind decl_upcall(llmod, _),
                                             abi.n_upcall_glues as uint));

1187 1188 1189
    auto cx = @rec(sess = sess,
                   llmod = llmod,
                   upcalls = new_str_hash[ValueRef](),
1190 1191
                   fn_names = new_str_hash[ValueRef](),
                   fn_ids = new_def_hash[ValueRef](),
1192
                   items = new_def_hash[@ast.item](),
1193
                   glues = glues,
1194
                   names = namegen(0),
1195
                   path = "_rust");
1196

1197
    collect_items(cx, crate);
1198
    trans_mod(cx, crate.node.module);
1199
    trans_exit_task_glue(cx);
1200 1201
    trans_main_fn(cx, crate_constant(cx));

1202
    llvm.LLVMWriteBitcodeToFile(llmod, _str.buf(output));
1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215
    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:
//