trans.rs 37.7 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
// 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).

660 661
fn trans_lval(@block_ctxt cx, &ast.expr e)
    -> tup(result, bool, ast.def_id) {
G
Graydon Hoare 已提交
662 663 664 665 666
    alt (e.node) {
        case (ast.expr_name(?n, ?dopt, _)) {
            alt (dopt) {
                case (some[ast.def](?def)) {
                    alt (def) {
667
                        case (ast.def_arg(?did)) {
668 669
                            ret tup(res(cx, cx.fcx.llargs.get(did)),
                                    false, did);
670
                        }
G
Graydon Hoare 已提交
671
                        case (ast.def_local(?did)) {
672 673
                            ret tup(res(cx, cx.fcx.lllocals.get(did)),
                                    true, did);
G
Graydon Hoare 已提交
674
                        }
675
                        case (ast.def_fn(?did)) {
676
                            ret tup(res(cx, cx.fcx.tcx.fn_ids.get(did)),
677
                                    false, did);
678
                        }
G
Graydon Hoare 已提交
679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
                        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;
}

694 695 696 697 698 699 700 701 702 703 704 705 706 707
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);
}

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

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

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

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

P
Patrick Walton 已提交
726
        case (ast.expr_block(?blk, _)) {
727 728 729 730 731 732 733 734 735
            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);
        }
736

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

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

754 755
        case (ast.expr_call(?f, ?args, _)) {
            auto f_res = trans_lval(cx, *f);
756
            check (! f_res._1);
757 758 759 760 761 762 763 764 765 766

            // FIXME: Revolting hack to get the type of the outptr. Can get a
            // variety of other ways; will wait until we have a typechecker
            // perhaps to pick a more tasteful one.
            auto outptr = cx.fcx.lloutptr;
            alt (cx.fcx.tcx.items.get(f_res._2).node) {
                case (ast.item_fn(_, ?ff, _)) {
                    outptr = cx.build.Alloca(type_of(cx.fcx.tcx, ff.output));
                }
            }
767
            auto args_res = trans_exprs(f_res._0.bcx, args);
768
            auto llargs = vec(outptr,
769 770 771
                              cx.fcx.lltaskptr);
            llargs += args_res._1;
            ret res(args_res._0,
772
                    cx.build.Call(f_res._0.val, llargs));
773 774
        }

775 776 777 778 779
    }
    cx.fcx.tcx.sess.unimpl("expr variant in trans_expr");
    fail;
}

780
fn trans_log(@block_ctxt cx, &ast.expr e) -> result {
781
    alt (e.node) {
P
Patrick Walton 已提交
782
        case (ast.expr_lit(?lit, _)) {
783
            alt (lit.node) {
784
                case (ast.lit_str(_)) {
785 786 787 788 789
                    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));
790
                }
791

792
                case (_) {
793 794 795 796
                    auto sub = trans_expr(cx, e);
                    ret trans_upcall(sub.bcx,
                                     "upcall_log_int",
                                     vec(sub.val));
797 798 799
                }
            }
        }
800

801
        case (_) {
802 803
            auto sub = trans_expr(cx, e);
            ret trans_upcall(sub.bcx, "upcall_log_int", vec(sub.val));
804 805
        }
    }
806 807
}

808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827
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());
}

828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843
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;
}

844 845
fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
    auto sub = res(cx, C_nil());
846
    alt (s.node) {
847
        case (ast.stmt_log(?a)) {
848 849 850
            sub.bcx = trans_log(cx, *a).bcx;
        }

851 852 853 854
        case (ast.stmt_check_expr(?a)) {
            sub.bcx = trans_check_expr(cx, *a).bcx;
        }

855 856 857 858
        case (ast.stmt_ret(?e)) {
            sub.bcx = trans_ret(cx, e).bcx;
        }

859 860
        case (ast.stmt_expr(?e)) {
            sub.bcx = trans_expr(cx, *e).bcx;
861
        }
862

863 864 865 866 867 868 869 870 871 872 873 874 875
        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);
                        }
                    }
                }
            }
        }
876
        case (_) {
877
            cx.fcx.tcx.sess.unimpl("stmt variant");
878 879
        }
    }
880
    ret sub;
881 882
}

883 884 885 886 887 888
fn new_builder(BasicBlockRef llbb) -> builder {
    let BuilderRef llbuild = llvm.LLVMCreateBuilder();
    llvm.LLVMPositionBuilderAtEnd(llbuild, llbb);
    ret builder(llbuild);
}

889 890 891 892
// 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 {
893
    let BasicBlockRef llbb =
894
        llvm.LLVMAppendBasicBlock(cx.llfn, _str.buf(""));
895 896 897
    ret @rec(llbb=llbb,
             build=new_builder(llbb),
             term=term,
898
             mutable cleanups=cleanups,
899 900 901
             fcx=cx);
}

902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920
// 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);

}

921 922 923
// 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).
924 925
fn new_empty_block_ctxt(@fn_ctxt fcx) -> @block_ctxt {
    fn terminate_no_op(@fn_ctxt cx, builder build) {
926
    }
927 928 929 930
    auto term = terminate_no_op;
    let vec[cleanup] cleanups = vec();
    ret new_block_ctxt(fcx, term, cleanups);
}
931

932 933 934
fn trans_block_cleanups(@block_ctxt cx) -> @block_ctxt {
    auto bcx = cx;
    for (cleanup c in cx.cleanups) {
935
        alt (c) {
936
            case (clean(?cfn)) {
937
                bcx = cfn(bcx).bcx;
938 939 940
            }
        }
    }
941 942 943
    ret bcx;
}

944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959
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;
                    }
                }
            }
        }
    }
}

960 961 962
fn trans_block(@block_ctxt cx, &ast.block b) -> result {
    auto bcx = cx;

963 964 965 966 967 968 969 970 971 972 973 974 975 976
    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);
    }

977
    for (@ast.stmt s in b.node.stmts) {
978 979
        bcx = trans_stmt(bcx, *s).bcx;
    }
980

981 982 983
    bcx = trans_block_cleanups(bcx);
    bcx.term(bcx.fcx, bcx.build);
    ret res(bcx, C_nil());
984 985
}

986 987
fn new_fn_ctxt(@trans_ctxt cx,
               str name,
988 989 990
               &ast._fn f,
               ast.def_id fid) -> @fn_ctxt {

991
    let ValueRef llfn = cx.fn_ids.get(fid);
992
    cx.fn_names.insert(cx.path, llfn);
993

994 995
    let ValueRef lloutptr = llvm.LLVMGetParam(llfn, 0u);
    let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 1u);
996

997
    let hashmap[ast.def_id, ValueRef] lllocals = new_def_hash[ValueRef]();
998 999
    let hashmap[ast.def_id, ValueRef] llargs = new_def_hash[ValueRef]();

1000
    let uint arg_n = 2u;
1001 1002 1003 1004 1005
    for (ast.arg arg in f.inputs) {
        llargs.insert(arg.id, llvm.LLVMGetParam(llfn, arg_n));
        arg_n += 1u;
    }

1006 1007 1008
    ret @rec(llfn=llfn,
             lloutptr=lloutptr,
             lltaskptr=lltaskptr,
1009
             llargs=llargs,
1010
             lllocals=lllocals,
1011 1012 1013
             tcx=cx);
}

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

1016
    auto fcx = new_fn_ctxt(cx, cx.path, f, fid);
1017

1018
    trans_block(new_top_block_ctxt(fcx), f.body);
1019 1020
}

1021
fn trans_item(@trans_ctxt cx, &ast.item item) {
1022
    alt (item.node) {
1023
        case (ast.item_fn(?name, ?f, ?fid)) {
1024
            auto sub_cx = @rec(path=cx.path + "." + name with *cx);
1025
            trans_fn(sub_cx, f, fid);
1026
        }
1027 1028
        case (ast.item_mod(?name, ?m, _)) {
            auto sub_cx = @rec(path=cx.path + "." + name with *cx);
1029
            trans_mod(sub_cx, m);
1030 1031 1032 1033
        }
    }
}

1034
fn trans_mod(@trans_ctxt cx, &ast._mod m) {
1035 1036
    for (@ast.item item in m.items) {
        trans_item(cx, *item);
1037 1038 1039
    }
}

1040

1041 1042 1043 1044
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);
G
Graydon Hoare 已提交
1045 1046 1047
            let vec[TypeRef] args =
                vec(T_ptr(type_of(cx, f.output)), // outptr.
                    T_taskptr()   // taskptr
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069
                                        );
            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) {

G
Graydon Hoare 已提交
1070 1071
    let fold.ast_fold[@trans_ctxt] fld =
        fold.new_identity_fold[@trans_ctxt]();
1072 1073 1074 1075 1076 1077 1078

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

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

1079 1080 1081 1082
fn p2i(ValueRef v) -> ValueRef {
    ret llvm.LLVMConstPtrToInt(v, T_int());
}

1083 1084 1085 1086 1087 1088 1089 1090 1091 1092
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,
1093
                    llargs=new_def_hash[ValueRef](),
1094
                    lllocals=new_def_hash[ValueRef](),
1095 1096
                    tcx=cx);

1097
    auto bcx = new_top_block_ctxt(fcx);
1098 1099 1100 1101
    trans_upcall(bcx, "upcall_exit", V_args);
    bcx.term(fcx, bcx.build);
}

1102 1103 1104
fn crate_constant(@trans_ctxt cx) -> ValueRef {

    let ValueRef crate_ptr =
1105
        llvm.LLVMAddGlobal(cx.llmod, T_crate(),
1106 1107 1108 1109 1110 1111 1112 1113 1114 1115
                           _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);

1116 1117
    let ValueRef exit_task_glue_off =
        llvm.LLVMConstSub(p2i(cx.glues.exit_task_glue), crate_addr);
1118 1119 1120

    let ValueRef crate_val =
        C_struct(vec(C_null(T_int()),     // ptrdiff_t image_base_off
1121
                     p2i(crate_ptr),      // uintptr_t self_addr
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
                     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;
}

1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
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);
1152
    auto llrust_main = cx.fn_names.get("_rust.main");
1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171

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

}

1172
fn trans_crate(session.session sess, @ast.crate crate, str output) {
1173 1174 1175 1176
    auto llmod =
        llvm.LLVMModuleCreateWithNameInContext(_str.buf("rust_out"),
                                               llvm.LLVMGetGlobalContext());

1177 1178
    llvm.LLVMSetModuleInlineAsm(llmod, _str.buf(x86.get_module_asm()));

1179 1180 1181
    auto glues = @rec(activate_glue = decl_glue(llmod,
                                                abi.activate_glue_name()),
                      yield_glue = decl_glue(llmod, abi.yield_glue_name()),
1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195
                      /*
                       * 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(),
1196
                                    vec(T_taskptr()), T_void()),
1197

1198 1199 1200 1201
                      upcall_glues =
                      _vec.init_fn[ValueRef](bind decl_upcall(llmod, _),
                                             abi.n_upcall_glues as uint));

1202 1203 1204
    auto cx = @rec(sess = sess,
                   llmod = llmod,
                   upcalls = new_str_hash[ValueRef](),
1205 1206
                   fn_names = new_str_hash[ValueRef](),
                   fn_ids = new_def_hash[ValueRef](),
1207
                   items = new_def_hash[@ast.item](),
1208
                   glues = glues,
1209
                   names = namegen(0),
1210
                   path = "_rust");
1211

1212
    collect_items(cx, crate);
1213
    trans_mod(cx, crate.node.module);
1214
    trans_exit_task_glue(cx);
1215 1216
    trans_main_fn(cx, crate_constant(cx));

1217
    llvm.LLVMWriteBitcodeToFile(llmod, _str.buf(output));
1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230
    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:
//