trans.rs 299.5 KB
Newer Older
1 2


L
Lindsey Kuper 已提交
3 4 5 6 7 8
// trans.rs: Translate the completed AST to the LLVM IR.
//
// Some functions here, such as trans_block and trans_expr, return a value --
// the result of the translation to LLVM -- while others, such as trans_fn,
// trans_obj, and trans_item, are called only for the side effect of adding a
// particular definition to the LLVM IR output we're producing.
L
Lindsey Kuper 已提交
9 10
//
// Hopefully useful general knowledge about trans:
11
//
L
Lindsey Kuper 已提交
12 13 14 15 16
//   * There's no way to find out the ty::t type of a ValueRef.  Doing so
//     would be "trying to get the eggs out of an omelette" (credit:
//     pcwalton).  You can, instead, find out its TypeRef by calling val_ty,
//     but many TypeRefs correspond to one ty::t; for instance, tup(int, int,
//     int) and rec(x=int, y=int, z=int) will have the same TypeRef.
17 18 19 20 21 22
import std::int;
import std::str;
import std::uint;
import std::vec;
import std::str::rustrt::sbuf;
import std::vec::rustrt::vbuf;
23 24 25 26 27
import std::map;
import std::map::hashmap;
import std::option;
import std::option::some;
import std::option::none;
28
import std::fs;
29 30 31 32
import front::ast;
import front::creader;
import driver::session;
import middle::ty;
33
import back::link;
34 35 36 37
import back::x86;
import back::abi;
import back::upcall;
import middle::ty::pat_ty;
38
import visit::vt;
39 40 41 42
import util::common;
import util::common::istr;
import util::common::new_def_hash;
import util::common::new_str_hash;
43
import util::common::local_rhs_span;
44
import util::common::span;
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
import lib::llvm::llvm;
import lib::llvm::builder;
import lib::llvm::target_data;
import lib::llvm::type_handle;
import lib::llvm::type_names;
import lib::llvm::mk_target_data;
import lib::llvm::mk_type_handle;
import lib::llvm::mk_type_names;
import lib::llvm::llvm::ModuleRef;
import lib::llvm::llvm::ValueRef;
import lib::llvm::llvm::TypeRef;
import lib::llvm::llvm::TypeHandleRef;
import lib::llvm::llvm::BuilderRef;
import lib::llvm::llvm::BasicBlockRef;
import lib::llvm::False;
import lib::llvm::True;
import lib::llvm::Bool;
62 63 64 65 66 67 68 69
import link::mangle_internal_name_by_type_only;
import link::mangle_internal_name_by_seq;
import link::mangle_internal_name_by_path;
import link::mangle_internal_name_by_path_and_seq;
import link::mangle_exported_name;
import link::crate_meta_name;
import link::crate_meta_vers;
import link::crate_meta_extras_hash;
70 71 72
import pretty::ppaux::ty_to_str;
import pretty::ppaux::ty_to_short_str;
import pretty::pprust::expr_to_str;
73

74 75
obj namegen(mutable int i) {
    fn next(str prefix) -> str { i += 1; ret prefix + istr(i); }
76 77
}

78 79
type derived_tydesc_info = rec(ValueRef lltydesc, bool escapes);

80
type glue_fns = rec(ValueRef no_op_type_glue);
81

82 83 84 85 86 87 88 89 90 91 92
type tydesc_info =
    rec(ty::t ty,
        ValueRef tydesc,
        ValueRef size,
        ValueRef align,
        mutable option::t[ValueRef] take_glue,
        mutable option::t[ValueRef] drop_glue,
        mutable option::t[ValueRef] free_glue,
        mutable option::t[ValueRef] cmp_glue,
        vec[uint] ty_params);

93

94 95 96 97 98 99 100 101
/*
 * A note on nomenclature of linking: "upcall", "extern" and "native".
 *
 * An "extern" is an LLVM symbol we wind up emitting an undefined external
 * reference to. This means "we don't have the thing in this compilation unit,
 * please make sure you link it in at runtime". This could be a reference to
 * C code found in a C library, or rust code found in a rust crate.
 *
102
 * A "native" is an extern that references C code. Called with cdecl.
103 104 105 106 107 108
 *
 * An upcall is a native call generated by the compiler (not corresponding to
 * any user-written call in the code) into librustrt, to perform some helper
 * task such as bringing a task to life, allocating memory, etc.
 *
 */
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
type stats =
    rec(mutable uint n_static_tydescs,
        mutable uint n_derived_tydescs,
        mutable uint n_glues_created,
        mutable uint n_null_glues,
        mutable uint n_real_glues);

type crate_ctxt =
    rec(session::session sess,
        ModuleRef llmod,
        target_data td,
        type_names tn,
        hashmap[str, ValueRef] externs,
        hashmap[str, ValueRef] intrinsics,
        hashmap[ast::def_id, ValueRef] item_ids,
        hashmap[ast::def_id, @ast::item] items,
        hashmap[ast::def_id, @ast::native_item] native_items,
        hashmap[ast::def_id, str] item_symbols,
        mutable option::t[ValueRef] main_fn,
        str crate_meta_name,
        str crate_meta_vers,
        str crate_meta_extras_hash,

        // TODO: hashmap[tup(tag_id,subtys), @tag_info]
        hashmap[ty::t, uint] tag_sizes,
        hashmap[ast::def_id, ValueRef] discrims,
        hashmap[ast::def_id, str] discrim_symbols,
        hashmap[ast::def_id, ValueRef] fn_pairs,
        hashmap[ast::def_id, ValueRef] consts,
        hashmap[ast::def_id, ()] obj_methods,
        hashmap[ty::t, @tydesc_info] tydescs,
        hashmap[str, ValueRef] module_data,
        hashmap[ty::t, TypeRef] lltypes,
        @glue_fns glues,
        namegen names,
        std::sha1::sha1 sha,
        hashmap[ty::t, str] type_sha1s,
        hashmap[ty::t, metadata::ty_abbrev] type_abbrevs,
        hashmap[ty::t, str] type_short_names,
        ty::ctxt tcx,
        stats stats,
        @upcall::upcalls upcalls);

type local_ctxt =
    rec(vec[str] path,
        vec[str] module_path,
        vec[ast::ty_param] obj_typarams,
        vec[ast::obj_field] obj_fields,
        @crate_ctxt ccx);
158

159

L
Lindsey Kuper 已提交
160 161
// Types used for llself.
type val_self_pair = rec(ValueRef v, ty::t t);
162

L
Lindsey Kuper 已提交
163
type ty_self_pair = tup(TypeRef, ty::t);
164

165

166
// Function context.  Every LLVM function we create will have one of these.
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
type fn_ctxt =
    rec(
        // The ValueRef returned from a call to llvm::LLVMAddFunction; the
        // address of the first instruction in the sequence of instructions
        // for this function that will go in the .text section of the
        // executable we're generating.
        ValueRef llfn,

        // The three implicit arguments that arrive in the function we're
        // creating.  For instance, foo(int, int) is really foo(ret*, task*,
        // env*, int, int).  These are also available via
        // llvm::LLVMGetParam(llfn, uint) where uint = 1, 2, 0 respectively,
        // but we unpack them into these fields for convenience.
        ValueRef lltaskptr,
        ValueRef llenv,
        ValueRef llretptr,

        // The next three elements: "hoisted basic blocks" containing
        // administrative activities that have to happen in only one place in
        // the function, due to LLVM's quirks.

        // A block for all the function's allocas, so that LLVM will coalesce
        // them into a single alloca call.
        mutable BasicBlockRef llallocas,

        // A block containing code that copies incoming arguments to space
        // already allocated by code in the llallocas block.  (LLVM requires
        // that arguments be copied to local allocas before allowing most any
        // operation to be performed on them.)
        mutable BasicBlockRef llcopyargs,

        // A block containing derived tydescs received from the runtime.  See
        // description of derived_tydescs, below.
        mutable BasicBlockRef llderivedtydescs,

        // FIXME: Is llcopyargs actually the block containing the allocas for
        // incoming function arguments?  Or is it merely the block containing
        // code that copies incoming args to space already alloca'd by code in
        // llallocas?

        // The 'self' object currently in use in this function, if there is
        // one.
        mutable option::t[val_self_pair] llself,

        // If this function is actually a iter, a block containing the code
        // called whenever the iter calls 'put'.
        mutable option::t[ValueRef] lliterbody,

        // The next four items: hash tables mapping from AST def_ids to
        // LLVM-stuff-in-the-frame.

        // Maps arguments to allocas created for them in llallocas.
        hashmap[ast::def_id, ValueRef] llargs,

        // Maps fields in objects to pointers into the interior of llself's
        // body.
        hashmap[ast::def_id, ValueRef] llobjfields,

        // Maps the def_ids for local variables to the allocas created for
        // them in llallocas.
        hashmap[ast::def_id, ValueRef] lllocals,

        // The same as above, but for variables accessed via the frame pointer
        // we pass into an iter, for access to the static environment of the
        // iter-calling frame.
        hashmap[ast::def_id, ValueRef] llupvars,

        // For convenience, a vector of the incoming tydescs for each of this
        // functions type parameters, fetched via llvm::LLVMGetParam.  For
        // example, for a function foo[A, B, C](), lltydescs contains the
        // ValueRefs for the tydescs for A, B, and C.
        mutable vec[ValueRef] lltydescs,

        // Derived tydescs are tydescs created at runtime, for types that
        // involve type parameters inside type constructors.  For example,
        // suppose a function parameterized by T creates a vector of type
        // vec[T].  The function doesn't know what T is until runtime, and the
        // function's caller knows T but doesn't know that a vector is
        // involved.  So a tydesc for vec[T] can't be created until runtime,
        // when information about both "vec" and "T" are available.  When such
        // a tydesc is created, we cache it in the derived_tydescs table for
        // the next time that such a tydesc is needed.
        hashmap[ty::t, derived_tydesc_info] derived_tydescs,

        // The source span where this function comes from, for error
        // reporting.
        span sp,

        // This function's enclosing local context.
        @local_ctxt lcx);

tag cleanup { clean(fn(&@block_ctxt) -> result ); }
259

260
tag block_kind {
261

262 263 264 265
    // A scope block is a basic block created by translating a block { ... }
    // the the source language.  Since these blocks create variable scope, any
    // variables created in them that are still live at the end of the block
    // must be dropped and cleaned up when the block ends.
266
    SCOPE_BLOCK;
267 268 269 270 271

    // A basic block created from the body of a loop.  Contains pointers to
    // which block to jump to in the case of "continue" or "break", with the
    // "continue" block optional, because "while" and "do while" don't support
    // "continue" (TODO: is this intentional?)
272
    LOOP_SCOPE_BLOCK(option::t[@block_ctxt], @block_ctxt);
273 274 275 276 277

    // A non-scope block is a basic block created as a translation artifact
    // from translating code that expresses conditional logic rather than by
    // explicit { ... } block structure in the source language.  It's called a
    // non-scope block because it doesn't introduce a new variable scope.
278 279 280
    NON_SCOPE_BLOCK;
}

281

282 283 284 285 286
// Basic block context.  We create a block context for each basic block
// (single-entry, single-exit sequence of instructions) we generate from Rust
// code.  Each basic block we generate is attached to a function, typically
// with many basic blocks per function.  All the basic blocks attached to a
// function are organized as a directed graph.
287 288 289 290 291 292 293
type block_ctxt =
    rec(
        // The BasicBlockRef returned from a call to
        // llvm::LLVMAppendBasicBlock(llfn, name), which adds a basic block to
        // the function pointed to by llfn.  We insert instructions into that
        // block by way of this block context.
        BasicBlockRef llbb,
294

295 296 297
        // The llvm::builder object serving as an interface to LLVM's
        // LLVMBuild* functions.
        builder build,
298

299 300
        // The block pointing to this one in the function's digraph.
        block_parent parent,
301

302 303
        // The 'kind' of basic block this is.
        block_kind kind,
304

305 306 307 308
        // A list of functions that run at the end of translating this block,
        // cleaning up any variables that were introduced in the block and
        // need to go out of scope at the end of it.
        mutable vec[cleanup] cleanups,
309

310 311 312 313 314 315
        // The source span where this block comes from, for error reporting.
        span sp,

        // The function context for the function to which this block is
        // attached.
        @fn_ctxt fcx);
316

317

318
// FIXME: we should be able to use option::t[@block_parent] here but
319
// the infinite-tag check in rustboot gets upset.
320
tag block_parent { parent_none; parent_some(@block_ctxt); }
321

322
type result = rec(@block_ctxt bcx, ValueRef val);
323

G
Graydon Hoare 已提交
324
fn extend_path(@local_ctxt cx, &str name) -> @local_ctxt {
325
    ret @rec(path=cx.path + [name] with *cx);
326 327
}

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

330
fn ty_str(type_names tn, TypeRef t) -> str {
331
    ret lib::llvm::type_to_str(tn, t);
332 333
}

334 335 336
fn val_ty(ValueRef v) -> TypeRef { ret llvm::LLVMTypeOf(v); }

fn val_str(type_names tn, ValueRef v) -> str { ret ty_str(tn, val_ty(v)); }
337

338

339 340 341 342 343 344 345 346 347
// Returns the nth element of the given LLVM structure type.
fn struct_elt(TypeRef llstructty, uint n) -> TypeRef {
    auto elt_count = llvm::LLVMCountStructElementTypes(llstructty);
    assert (n < elt_count);
    auto elt_tys = vec::init_elt(T_nil(), elt_count);
    llvm::LLVMGetStructElementTypes(llstructty, vec::buf(elt_tys));
    ret llvm::LLVMGetElementType(elt_tys.(n));
}

348 349

// LLVM type constructors.
350 351 352 353 354 355 356 357 358 359 360
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.
361

362
    ret llvm::LLVMVoidType();
363 364
}

365 366 367
fn T_nil() -> TypeRef {
    // NB: See above in T_void().

368
    ret llvm::LLVMInt1Type();
369 370
}

371
fn T_i1() -> TypeRef { ret llvm::LLVMInt1Type(); }
372

373
fn T_i8() -> TypeRef { ret llvm::LLVMInt8Type(); }
374

375
fn T_i16() -> TypeRef { ret llvm::LLVMInt16Type(); }
376

377
fn T_i32() -> TypeRef { ret llvm::LLVMInt32Type(); }
378

379
fn T_i64() -> TypeRef { ret llvm::LLVMInt64Type(); }
380

381
fn T_f32() -> TypeRef { ret llvm::LLVMFloatType(); }
382

383 384 385
fn T_f64() -> TypeRef { ret llvm::LLVMDoubleType(); }

fn T_bool() -> TypeRef { ret T_i1(); }
386

387 388
fn T_int() -> TypeRef {
    // FIXME: switch on target type.
389

390 391 392
    ret T_i32();
}

393 394
fn T_float() -> TypeRef {
    // FIXME: switch on target type.
395

396 397 398
    ret T_f64();
}

399
fn T_char() -> TypeRef { ret T_i32(); }
400

401 402
fn T_size_t() -> TypeRef {
    // FIXME: switch on target type.
403

404 405 406
    ret T_i32();
}

407
fn T_fn(vec[TypeRef] inputs, TypeRef output) -> TypeRef {
408 409
    ret llvm::LLVMFunctionType(output, vec::buf[TypeRef](inputs),
                               vec::len[TypeRef](inputs), False);
410 411
}

G
Graydon Hoare 已提交
412
fn T_fn_pair(&type_names tn, TypeRef tfn) -> TypeRef {
413
    ret T_struct([T_ptr(tfn), T_opaque_closure_ptr(tn)]);
414 415
}

416
fn T_ptr(TypeRef t) -> TypeRef { ret llvm::LLVMPointerType(t, 0u); }
417

G
Graydon Hoare 已提交
418
fn T_struct(&vec[TypeRef] elts) -> TypeRef {
419 420
    ret llvm::LLVMStructType(vec::buf[TypeRef](elts), vec::len[TypeRef](elts),
                             False);
421 422
}

423
fn T_opaque() -> TypeRef { ret llvm::LLVMOpaqueType(); }
424

G
Graydon Hoare 已提交
425
fn T_task(&type_names tn) -> TypeRef {
426
    auto s = "task";
427 428 429 430 431 432 433 434 435 436 437
    if (tn.name_has_type(s)) { ret tn.get_type(s); }
    auto t =
        T_struct([T_int(), // Refcount
                   T_int(), // Delegate pointer
                   T_int(), // Stack segment pointer
                   T_int(), // Runtime SP
                   T_int(), // Rust SP
                   T_int(), // GC chain
                   T_int(), // Domain pointer
                    // Crate cache pointer
                  T_int()]);
438 439
    tn.associate(s, t);
    ret t;
440 441
}

G
Graydon Hoare 已提交
442
fn T_tydesc_field(&type_names tn, int field) -> TypeRef {
443
    // Bit of a kludge: pick the fn typeref out of the tydesc..
444

445
    let vec[TypeRef] tydesc_elts =
446
        vec::init_elt[TypeRef](T_nil(), abi::n_tydesc_fields as uint);
447
    llvm::LLVMGetStructElementTypes(T_tydesc(tn),
448
                                    vec::buf[TypeRef](tydesc_elts));
449
    auto t = llvm::LLVMGetElementType(tydesc_elts.(field));
450 451 452
    ret t;
}

G
Graydon Hoare 已提交
453
fn T_glue_fn(&type_names tn) -> TypeRef {
454
    auto s = "glue_fn";
455
    if (tn.name_has_type(s)) { ret tn.get_type(s); }
456
    auto t = T_tydesc_field(tn, abi::tydesc_field_drop_glue);
457 458 459 460
    tn.associate(s, t);
    ret t;
}

461
fn T_dtor(&@crate_ctxt ccx, &span sp, TypeRef llself_ty) -> TypeRef {
462
    ret type_of_fn_full(ccx, sp, ast::proto_fn, some[TypeRef](llself_ty),
463
                        vec::empty[ty::arg](), ty::mk_nil(ccx.tcx), 0u);
464 465
}

G
Graydon Hoare 已提交
466
fn T_cmp_glue_fn(&type_names tn) -> TypeRef {
467
    auto s = "cmp_glue_fn";
468
    if (tn.name_has_type(s)) { ret tn.get_type(s); }
469
    auto t = T_tydesc_field(tn, abi::tydesc_field_cmp_glue);
470 471
    tn.associate(s, t);
    ret t;
472 473
}

G
Graydon Hoare 已提交
474
fn T_tydesc(&type_names tn) -> TypeRef {
475
    auto s = "tydesc";
476
    if (tn.name_has_type(s)) { ret tn.get_type(s); }
477
    auto th = mk_type_handle();
478
    auto abs_tydesc = llvm::LLVMResolveTypeHandle(th.llth);
479
    auto tydescpp = T_ptr(T_ptr(abs_tydesc));
480
    auto pvoid = T_ptr(T_i8());
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
    auto glue_fn_ty =
        T_ptr(T_fn([T_ptr(T_nil()), T_taskptr(tn), T_ptr(T_nil()), tydescpp,
                    pvoid], T_void()));
    auto cmp_glue_fn_ty =
        T_ptr(T_fn([T_ptr(T_i1()), T_taskptr(tn), T_ptr(T_nil()), tydescpp,
                    pvoid, pvoid, T_i8()], T_void()));
    auto tydesc =
        T_struct([tydescpp, // first_param
                   T_int(), // size
                   T_int(), // align
                   glue_fn_ty, // take_glue
                   glue_fn_ty, // drop_glue
                   glue_fn_ty, // free_glue
                   glue_fn_ty, // sever_glue
                   glue_fn_ty, // mark_glue
                   glue_fn_ty, // obj_drop_glue
                   glue_fn_ty, // is_stateful
                   cmp_glue_fn_ty]); // cmp_glue
499

500 501
    llvm::LLVMRefineType(abs_tydesc, tydesc);
    auto t = llvm::LLVMResolveTypeHandle(th.llth);
502 503
    tn.associate(s, t);
    ret t;
504 505
}

506
fn T_array(TypeRef t, uint n) -> TypeRef { ret llvm::LLVMArrayType(t, n); }
507

508
fn T_vec(TypeRef t) -> TypeRef {
509 510 511 512 513 514
    ret T_struct([T_int(), // Refcount
                   T_int(), // Alloc
                   T_int(), // Fill
                   T_int(), // Pad
                    // Body elements
                  T_array(t, 0u)]);
515 516
}

517 518
fn T_opaque_vec_ptr() -> TypeRef { ret T_ptr(T_vec(T_int())); }

519

520 521 522
// Interior vector.
//
// TODO: Support user-defined vector sizes.
523
fn T_ivec(TypeRef t) -> TypeRef {
524 525 526 527
    ret T_struct([T_int(), // Length ("fill"; if zero, heapified)
                   T_int(), // Alloc
                   T_array(t, abi::ivec_default_length)]); // Body elements

528 529
}

530

531 532
// Note that the size of this one is in bytes.
fn T_opaque_ivec() -> TypeRef {
533 534 535 536
    ret T_struct([T_int(), // Length ("fill"; if zero, heapified)
                   T_int(), // Alloc
                   T_array(T_i8(), 0u)]); // Body elements

537 538
}

539
fn T_ivec_heap_part(TypeRef t) -> TypeRef {
540 541 542
    ret T_struct([T_int(), // Real length
                   T_array(t, 0u)]); // Body elements

543 544
}

545

546 547
// Interior vector on the heap, also known as the "stub". Cast to this when
// the allocated length (second element of T_ivec above) is zero.
548
fn T_ivec_heap(TypeRef t) -> TypeRef {
549 550 551 552
    ret T_struct([T_int(), // Length (zero)
                   T_int(), // Alloc
                   T_ptr(T_ivec_heap_part(t))]); // Pointer

553 554 555
}

fn T_opaque_ivec_heap_part() -> TypeRef {
556 557
    ret T_struct([T_int(), // Real length
                   T_array(T_i8(), 0u)]); // Body elements
558

559 560
}

561
fn T_opaque_ivec_heap() -> TypeRef {
562 563 564
    ret T_struct([T_int(), // Length (zero)
                   T_int(), // Alloc
                   T_ptr(T_opaque_ivec_heap_part())]); // Pointer
565

566 567
}

568 569 570
fn T_str() -> TypeRef { ret T_vec(T_i8()); }

fn T_box(TypeRef t) -> TypeRef { ret T_struct([T_int(), t]); }
571

B
Brian Anderson 已提交
572
fn T_port(TypeRef t) -> TypeRef {
573
    ret T_struct([T_int()]); // Refcount
574

B
Brian Anderson 已提交
575 576 577
}

fn T_chan(TypeRef t) -> TypeRef {
578
    ret T_struct([T_int()]); // Refcount
B
Brian Anderson 已提交
579

580 581
}

582 583 584
fn T_taskptr(&type_names tn) -> TypeRef { ret T_ptr(T_task(tn)); }


585
// This type must never be used directly; it must always be cast away.
G
Graydon Hoare 已提交
586
fn T_typaram(&type_names tn) -> TypeRef {
587
    auto s = "typaram";
588
    if (tn.name_has_type(s)) { ret tn.get_type(s); }
589
    auto t = T_i8();
590 591
    tn.associate(s, t);
    ret t;
592 593
}

594
fn T_typaram_ptr(&type_names tn) -> TypeRef { ret T_ptr(T_typaram(tn)); }
595

596
fn T_closure_ptr(&type_names tn, TypeRef lltarget_ty, TypeRef llbindings_ty,
597
                 uint n_ty_params) -> TypeRef {
598
    // NB: keep this in sync with code in trans_bind; we're making
599
    // an LLVM typeref structure that has the same "shape" as the ty::t
600
    // it constructs.
601 602 603

    ret T_ptr(T_box(T_struct([T_ptr(T_tydesc(tn)), lltarget_ty, llbindings_ty,
                              T_captured_tydescs(tn, n_ty_params)])));
604 605
}

G
Graydon Hoare 已提交
606
fn T_opaque_closure_ptr(&type_names tn) -> TypeRef {
607
    auto s = "*closure";
608 609 610 611
    if (tn.name_has_type(s)) { ret tn.get_type(s); }
    auto t =
        T_closure_ptr(tn, T_struct([T_ptr(T_nil()), T_ptr(T_nil())]), T_nil(),
                      0u);
612 613
    tn.associate(s, t);
    ret t;
614 615
}

G
Graydon Hoare 已提交
616
fn T_tag(&type_names tn, uint size) -> TypeRef {
617
    auto s = "tag_" + uint::to_str(size, 10u);
618
    if (tn.name_has_type(s)) { ret tn.get_type(s); }
619
    auto t = T_struct([T_int(), T_array(T_i8(), size)]);
620 621 622 623
    tn.associate(s, t);
    ret t;
}

G
Graydon Hoare 已提交
624
fn T_opaque_tag(&type_names tn) -> TypeRef {
625
    auto s = "opaque_tag";
626
    if (tn.name_has_type(s)) { ret tn.get_type(s); }
627
    auto t = T_struct([T_int(), T_i8()]);
628 629 630 631
    tn.associate(s, t);
    ret t;
}

G
Graydon Hoare 已提交
632
fn T_opaque_tag_ptr(&type_names tn) -> TypeRef {
633 634 635
    ret T_ptr(T_opaque_tag(tn));
}

G
Graydon Hoare 已提交
636
fn T_captured_tydescs(&type_names tn, uint n) -> TypeRef {
637
    ret T_struct(vec::init_elt[TypeRef](T_ptr(T_tydesc(tn)), n));
638 639
}

G
Graydon Hoare 已提交
640
fn T_obj_ptr(&type_names tn, uint n_captured_tydescs) -> TypeRef {
641 642
    // This function is not publicly exposed because it returns an incomplete
    // type. The dynamically-sized fields follow the captured tydescs.
643

644
    fn T_obj(type_names tn, uint n_captured_tydescs) -> TypeRef {
645
        ret T_struct([T_ptr(T_tydesc(tn)),
646
                      T_captured_tydescs(tn, n_captured_tydescs)]);
647 648
    }
    ret T_ptr(T_box(T_obj(tn, n_captured_tydescs)));
649 650
}

651
fn T_opaque_obj_ptr(&type_names tn) -> TypeRef { ret T_obj_ptr(tn, 0u); }
652

653
fn T_opaque_port_ptr() -> TypeRef { ret T_ptr(T_i8()); }
654

655
fn T_opaque_chan_ptr() -> TypeRef { ret T_ptr(T_i8()); }
656

657

658 659 660 661
// This function now fails if called on a type with dynamic size (as its
// return value was always meaningless in that case anyhow). Beware!
//
// TODO: Enforce via a predicate.
662
fn type_of(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef {
663
    if (ty::type_has_dynamic_size(cx.tcx, t)) {
664 665 666
        cx.sess.span_err(sp,
                         "type_of() called on a type with dynamic size: " +
                             ty_to_str(cx.tcx, t));
667
    }
668
    ret type_of_inner(cx, sp, t);
669 670
}

671 672
fn type_of_explicit_args(&@crate_ctxt cx, &span sp, &vec[ty::arg] inputs) ->
   vec[TypeRef] {
673
    let vec[TypeRef] atys = [];
674 675
    for (ty::arg arg in inputs) {
        if (ty::type_has_dynamic_size(cx.tcx, arg.ty)) {
676
            assert (arg.mode != ty::mo_val);
677
            atys += [T_typaram_ptr(cx.tn)];
678
        } else {
679
            let TypeRef t;
680
            alt (arg.mode) {
681
                case (ty::mo_alias(_)) {
682
                    t = T_ptr(type_of_inner(cx, sp, arg.ty));
683
                }
684
                case (_) { t = type_of_inner(cx, sp, arg.ty); }
685
            }
686
            atys += [t];
687 688 689 690
        }
    }
    ret atys;
}
691

692

693 694 695 696 697 698
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args
699 700 701
fn type_of_fn_full(&@crate_ctxt cx, &span sp, ast::proto proto,
                   &option::t[TypeRef] obj_self, &vec[ty::arg] inputs,
                   &ty::t output, uint ty_param_count) -> TypeRef {
702
    let vec[TypeRef] atys = [];
703
    // Arg 0: Output pointer.
704

705
    if (ty::type_has_dynamic_size(cx.tcx, output)) {
706
        atys += [T_typaram_ptr(cx.tn)];
707
    } else { atys += [T_ptr(type_of_inner(cx, sp, output))]; }
708
    // Arg 1: task pointer.
709

710
    atys += [T_taskptr(cx.tn)];
711
    // Arg 2: Env (closure-bindings / self-obj)
712

713
    alt (obj_self) {
714 715
        case (some(?t)) { assert (t as int != 0); atys += [t]; }
        case (_) { atys += [T_opaque_closure_ptr(cx.tn)]; }
716
    }
717
    // Args >3: ty params, if not acquired via capture...
718

719 720 721
    if (obj_self == none[TypeRef]) {
        auto i = 0u;
        while (i < ty_param_count) {
722
            atys += [T_ptr(T_tydesc(cx.tn))];
723 724
            i += 1u;
        }
725
    }
726
    if (proto == ast::proto_iter) {
727 728 729
        // If it's an iter, the 'output' type of the iter is actually the
        // *input* type of the function we're given as our iter-block
        // argument.
730

731
        atys +=
732
            [T_fn_pair(cx.tn,
733
                       type_of_fn_full(cx, sp, ast::proto_fn, none[TypeRef],
734
                                       [rec(mode=ty::mo_alias(false),
735 736
                                            ty=output)], ty::mk_nil(cx.tcx),
                                       0u))];
737
    }
738
    // ... then explicit args.
739

740
    atys += type_of_explicit_args(cx, sp, inputs);
741
    ret T_fn(atys, llvm::LLVMVoidType());
742 743
}

744 745 746
fn type_of_fn(&@crate_ctxt cx, &span sp, ast::proto proto,
              &vec[ty::arg] inputs, &ty::t output, uint ty_param_count) ->
   TypeRef {
747
    ret type_of_fn_full(cx, sp, proto, none[TypeRef], inputs, output,
748
                        ty_param_count);
749 750
}

751
fn type_of_native_fn(&@crate_ctxt cx, &span sp, ast::native_abi abi,
752 753
                     &vec[ty::arg] inputs, &ty::t output, uint ty_param_count)
   -> TypeRef {
754
    let vec[TypeRef] atys = [];
755
    if (abi == ast::native_abi_rust) {
756
        atys += [T_taskptr(cx.tn)];
757
        auto t = ty::ty_native_fn(abi, inputs, output);
758 759
        auto i = 0u;
        while (i < ty_param_count) {
760
            atys += [T_ptr(T_tydesc(cx.tn))];
761 762 763
            i += 1u;
        }
    }
764 765
    atys += type_of_explicit_args(cx, sp, inputs);
    ret T_fn(atys, type_of_inner(cx, sp, output));
766 767
}

768
fn type_of_inner(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef {
769 770
    // Check the cache.

771
    if (cx.lltypes.contains_key(t)) { ret cx.lltypes.get(t); }
772
    let TypeRef llty = 0 as TypeRef;
773 774 775
    alt (ty::struct(cx.tcx, t)) {
        case (ty::ty_native) { llty = T_ptr(T_i8()); }
        case (ty::ty_nil) { llty = T_nil(); }
776 777 778 779
        case (ty::ty_bot) {
            llty = T_nil(); /* ...I guess? */

        }
780 781 782 783 784
        case (ty::ty_bool) { llty = T_bool(); }
        case (ty::ty_int) { llty = T_int(); }
        case (ty::ty_float) { llty = T_float(); }
        case (ty::ty_uint) { llty = T_int(); }
        case (ty::ty_machine(?tm)) {
785
            alt (tm) {
786 787 788 789 790 791 792 793 794 795
                case (common::ty_i8) { llty = T_i8(); }
                case (common::ty_u8) { llty = T_i8(); }
                case (common::ty_i16) { llty = T_i16(); }
                case (common::ty_u16) { llty = T_i16(); }
                case (common::ty_i32) { llty = T_i32(); }
                case (common::ty_u32) { llty = T_i32(); }
                case (common::ty_i64) { llty = T_i64(); }
                case (common::ty_u64) { llty = T_i64(); }
                case (common::ty_f32) { llty = T_f32(); }
                case (common::ty_f64) { llty = T_f64(); }
796 797
            }
        }
798 799
        case (ty::ty_char) { llty = T_char(); }
        case (ty::ty_str) { llty = T_ptr(T_str()); }
800
        case (ty::ty_istr) { llty = T_ivec(T_i8()); }
801 802
        case (ty::ty_tag(_, _)) {
            if (ty::type_has_dynamic_size(cx.tcx, t)) {
803 804
                llty = T_opaque_tag(cx.tn);
            } else {
805
                auto size = static_size_of_tag(cx, sp, t);
806 807
                llty = T_tag(cx.tn, size);
            }
808
        }
809
        case (ty::ty_box(?mt)) {
810
            llty = T_ptr(T_box(type_of_inner(cx, sp, mt.ty)));
811
        }
812
        case (ty::ty_vec(?mt)) {
813
            llty = T_ptr(T_vec(type_of_inner(cx, sp, mt.ty)));
814
        }
815
        case (ty::ty_ivec(?mt)) {
816 817
            if (ty::type_has_dynamic_size(cx.tcx, mt.ty)) {
                llty = T_opaque_ivec();
818
            } else { llty = T_ivec(type_of_inner(cx, sp, mt.ty)); }
819
        }
820
        case (ty::ty_ptr(?mt)) { llty = T_ptr(type_of_inner(cx, sp, mt.ty)); }
821
        case (ty::ty_port(?t)) {
822
            llty = T_ptr(T_port(type_of_inner(cx, sp, t)));
B
Brian Anderson 已提交
823
        }
824
        case (ty::ty_chan(?t)) {
825
            llty = T_ptr(T_chan(type_of_inner(cx, sp, t)));
B
Brian Anderson 已提交
826
        }
827
        case (ty::ty_task) { llty = T_taskptr(cx.tn); }
828
        case (ty::ty_tup(?elts)) {
829
            let vec[TypeRef] tys = [];
830
            for (ty::mt elt in elts) {
831
                tys += [type_of_inner(cx, sp, elt.ty)];
832
            }
833
            llty = T_struct(tys);
834
        }
835
        case (ty::ty_rec(?fields)) {
836
            let vec[TypeRef] tys = [];
837
            for (ty::field f in fields) {
838
                tys += [type_of_inner(cx, sp, f.mt.ty)];
839
            }
840
            llty = T_struct(tys);
841
        }
842
        case (ty::ty_fn(?proto, ?args, ?out, _, _)) {
843
            llty = T_fn_pair(cx.tn, type_of_fn(cx, sp, proto, args, out, 0u));
844
        }
845
        case (ty::ty_native_fn(?abi, ?args, ?out)) {
846
            auto nft = native_fn_wrapper_type(cx, sp, 0u, t);
847
            llty = T_fn_pair(cx.tn, nft);
848
        }
849
        case (ty::ty_obj(?meths)) {
850
            auto th = mk_type_handle();
851
            auto self_ty = llvm::LLVMResolveTypeHandle(th.llth);
852
            let vec[TypeRef] mtys = [T_ptr(T_i8())];
853
            for (ty::method m in meths) {
854
                let TypeRef mty =
855
                    type_of_fn_full(cx, sp, m.proto, some[TypeRef](self_ty),
856
                                    m.inputs, m.output, 0u);
857
                mtys += [T_ptr(mty)];
858
            }
859
            let TypeRef vtbl = T_struct(mtys);
860 861
            let TypeRef pair =
                T_struct([T_ptr(vtbl), T_opaque_obj_ptr(cx.tn)]);
862 863 864
            auto abs_pair = llvm::LLVMResolveTypeHandle(th.llth);
            llvm::LLVMRefineType(abs_pair, pair);
            abs_pair = llvm::LLVMResolveTypeHandle(th.llth);
865
            llty = abs_pair;
866
        }
867
        case (ty::ty_var(_)) {
868
            cx.tcx.sess.span_err(sp, "trans::type_of called on ty_var");
869
        }
870
        case (ty::ty_param(_)) { llty = T_i8(); }
871
        case (ty::ty_type) { llty = T_ptr(T_tydesc(cx.tn)); }
872
    }
873
    assert (llty as int != 0);
874
    if (cx.sess.get_opts().save_temps) {
875 876
        llvm::LLVMAddTypeName(cx.llmod, str::buf(ty_to_short_str(cx.tcx, t)),
                              llty);
877
    }
878
    cx.lltypes.insert(t, llty);
879
    ret llty;
880 881
}

882
fn type_of_arg(@local_ctxt cx, &span sp, &ty::arg arg) -> TypeRef {
883 884
    alt (ty::struct(cx.ccx.tcx, arg.ty)) {
        case (ty::ty_param(_)) {
885
            if (arg.mode != ty::mo_val) { ret T_typaram_ptr(cx.ccx.tn); }
886 887 888
        }
        case (_) {
            // fall through
889

890 891
        }
    }
892
    auto typ;
893
    if (arg.mode != ty::mo_val) {
894
        typ = T_ptr(type_of_inner(cx.ccx, sp, arg.ty));
895
    } else { typ = type_of_inner(cx.ccx, sp, arg.ty); }
896
    ret typ;
897 898
}

899
fn type_of_ty_param_count_and_ty(@local_ctxt lcx, &span sp,
900 901
                                 &ty::ty_param_count_and_ty tpt) -> TypeRef {
    alt (ty::struct(lcx.ccx.tcx, tpt._1)) {
902
        case (ty::ty_fn(?proto, ?inputs, ?output, _, _)) {
903 904
            auto llfnty =
                type_of_fn(lcx.ccx, sp, proto, inputs, output, tpt._0);
905
            ret T_fn_pair(lcx.ccx.tn, llfnty);
906 907 908
        }
        case (_) {
            // fall through
909

910 911
        }
    }
912
    ret type_of(lcx.ccx, sp, tpt._1);
913 914
}

915
fn type_of_or_i8(&@block_ctxt bcx, ty::t typ) -> TypeRef {
916
    if (ty::type_has_dynamic_size(bcx.fcx.lcx.ccx.tcx, typ)) { ret T_i8(); }
917 918 919
    ret type_of(bcx.fcx.lcx.ccx, bcx.sp, typ);
}

920

921 922
// Name sanitation. LLVM will happily accept identifiers with weird names, but
// gas doesn't!
G
Graydon Hoare 已提交
923
fn sanitize(&str s) -> str {
924 925
    auto result = "";
    for (u8 c in s) {
926
        if (c == '@' as u8) {
927 928
            result += "boxed_";
        } else {
929
            if (c == ',' as u8) {
930 931
                result += "_";
            } else {
932
                if (c == '{' as u8 || c == '(' as u8) {
933 934
                    result += "_of_";
                } else {
935 936 937
                    if (c != 10u8 && c != '}' as u8 && c != ')' as u8 &&
                            c != ' ' as u8 && c != '\t' as u8 &&
                            c != ';' as u8) {
938
                        auto v = [c];
939
                        result += str::from_bytes(v);
940 941 942
                    }
                }
            }
943 944 945 946 947
        }
    }
    ret result;
}

948

949 950
// LLVM constant constructors.
fn C_null(TypeRef t) -> ValueRef { ret llvm::LLVMConstNull(t); }
951

952
fn C_integral(TypeRef t, uint u, Bool sign_extend) -> ValueRef {
953
    // FIXME: We can't use LLVM::ULongLong with our existing minimal native
954
    // API, which only knows word-sized args.
955
    //
956
    // ret llvm::LLVMConstInt(T_int(), t as LLVM::ULongLong, False);
957
    //
958

959
    ret llvm::LLVMRustConstSmallInt(t, u, sign_extend);
960 961
}

G
Graydon Hoare 已提交
962
fn C_float(&str s) -> ValueRef {
963
    ret llvm::LLVMConstRealOfString(T_float(), str::buf(s));
964 965
}

G
Graydon Hoare 已提交
966
fn C_floating(&str s, TypeRef t) -> ValueRef {
967
    ret llvm::LLVMConstRealOfString(t, str::buf(s));
968 969
}

970 971
fn C_nil() -> ValueRef {
    // NB: See comment above in T_void().
972

973
    ret C_integral(T_i1(), 0u, False);
974 975
}

976 977
fn C_bool(bool b) -> ValueRef {
    if (b) {
978
        ret C_integral(T_bool(), 1u, False);
979
    } else { ret C_integral(T_bool(), 0u, False); }
980 981
}

982
fn C_int(int i) -> ValueRef { ret C_integral(T_int(), i as uint, True); }
983

984 985 986
fn C_uint(uint i) -> ValueRef { ret C_integral(T_int(), i, False); }

fn C_u8(uint i) -> ValueRef { ret C_integral(T_i8(), i, False); }
987

988

989 990
// This is a 'c-like' raw string, which differs from
// our boxed-and-length-annotated strings.
G
Graydon Hoare 已提交
991
fn C_cstr(&@crate_ctxt cx, &str s) -> ValueRef {
992
    auto sc = llvm::LLVMConstString(str::buf(s), str::byte_len(s), False);
993 994 995
    auto g =
        llvm::LLVMAddGlobal(cx.llmod, val_ty(sc),
                            str::buf(cx.names.next("str")));
996 997
    llvm::LLVMSetInitializer(g, sc);
    llvm::LLVMSetGlobalConstant(g, True);
998
    llvm::LLVMSetLinkage(g, lib::llvm::LLVMInternalLinkage as llvm::Linkage);
999
    ret g;
1000 1001
}

1002

1003
// A rust boxed-and-length-annotated string.
G
Graydon Hoare 已提交
1004
fn C_str(&@crate_ctxt cx, &str s) -> ValueRef {
1005
    auto len = str::byte_len(s);
1006 1007 1008 1009 1010 1011 1012 1013 1014
    auto box =
        C_struct([C_int(abi::const_refcount as int),
                  C_int(len + 1u as int), // 'alloc'
                   C_int(len + 1u as int), // 'fill'
                   C_int(0), // 'pad'
                   llvm::LLVMConstString(str::buf(s), len, False)]);
    auto g =
        llvm::LLVMAddGlobal(cx.llmod, val_ty(box),
                            str::buf(cx.names.next("str")));
1015 1016
    llvm::LLVMSetInitializer(g, box);
    llvm::LLVMSetGlobalConstant(g, True);
1017
    llvm::LLVMSetLinkage(g, lib::llvm::LLVMInternalLinkage as llvm::Linkage);
1018
    ret llvm::LLVMConstPointerCast(g, T_ptr(T_str()));
1019 1020
}

1021 1022
fn C_zero_byte_arr(uint size) -> ValueRef {
    auto i = 0u;
1023
    let vec[ValueRef] elts = [];
1024
    while (i < size) { elts += [C_u8(0u)]; i += 1u; }
1025
    ret llvm::LLVMConstArray(T_i8(), vec::buf[ValueRef](elts),
1026
                             vec::len[ValueRef](elts));
1027 1028
}

G
Graydon Hoare 已提交
1029
fn C_struct(&vec[ValueRef] elts) -> ValueRef {
1030
    ret llvm::LLVMConstStruct(vec::buf[ValueRef](elts),
1031
                              vec::len[ValueRef](elts), False);
1032 1033
}

G
Graydon Hoare 已提交
1034
fn C_array(TypeRef ty, &vec[ValueRef] elts) -> ValueRef {
1035
    ret llvm::LLVMConstArray(ty, vec::buf[ValueRef](elts),
1036
                             vec::len[ValueRef](elts));
1037 1038
}

G
Graydon Hoare 已提交
1039
fn decl_fn(ModuleRef llmod, &str name, uint cc, TypeRef llty) -> ValueRef {
1040
    let ValueRef llfn = llvm::LLVMAddFunction(llmod, str::buf(name), llty);
1041
    llvm::LLVMSetFunctionCallConv(llfn, cc);
1042 1043 1044
    ret llfn;
}

G
Graydon Hoare 已提交
1045
fn decl_cdecl_fn(ModuleRef llmod, &str name, TypeRef llty) -> ValueRef {
1046
    ret decl_fn(llmod, name, lib::llvm::LLVMCCallConv, llty);
1047 1048
}

G
Graydon Hoare 已提交
1049
fn decl_fastcall_fn(ModuleRef llmod, &str name, TypeRef llty) -> ValueRef {
1050
    ret decl_fn(llmod, name, lib::llvm::LLVMFastCallConv, llty);
1051 1052
}

1053

1054 1055
// Only use this if you are going to actually define the function. It's
// not valid to simply declare a function as internal.
1056 1057
fn decl_internal_fastcall_fn(ModuleRef llmod, &str name, TypeRef llty) ->
   ValueRef {
1058
    auto llfn = decl_fn(llmod, name, lib::llvm::LLVMFastCallConv, llty);
1059 1060
    llvm::LLVMSetLinkage(llfn,
                         lib::llvm::LLVMInternalLinkage as llvm::Linkage);
1061 1062 1063
    ret llfn;
}

G
Graydon Hoare 已提交
1064
fn decl_glue(ModuleRef llmod, type_names tn, &str s) -> ValueRef {
1065
    ret decl_cdecl_fn(llmod, s, T_fn([T_taskptr(tn)], T_void()));
1066 1067
}

1068
fn get_extern_fn(&hashmap[str, ValueRef] externs, ModuleRef llmod, &str name,
1069
                 uint cc, TypeRef ty) -> ValueRef {
1070
    if (externs.contains_key(name)) { ret externs.get(name); }
1071
    auto f = decl_fn(llmod, name, cc, ty);
1072
    externs.insert(name, f);
1073 1074 1075
    ret f;
}

1076 1077 1078
fn get_extern_const(&hashmap[str, ValueRef] externs, ModuleRef llmod,
                    &str name, TypeRef ty) -> ValueRef {
    if (externs.contains_key(name)) { ret externs.get(name); }
1079
    auto c = llvm::LLVMAddGlobal(llmod, ty, str::buf(name));
1080 1081 1082 1083
    externs.insert(name, c);
    ret c;
}

1084 1085
fn get_simple_extern_fn(&hashmap[str, ValueRef] externs, ModuleRef llmod,
                        &str name, int n_args) -> ValueRef {
1086
    auto inputs = vec::init_elt[TypeRef](T_int(), n_args as uint);
1087 1088
    auto output = T_int();
    auto t = T_fn(inputs, output);
1089
    ret get_extern_fn(externs, llmod, name, lib::llvm::LLVMCCallConv, t);
1090 1091
}

G
Graydon Hoare 已提交
1092
fn trans_native_call(&builder b, @glue_fns glues, ValueRef lltaskptr,
1093 1094 1095 1096
                     &hashmap[str, ValueRef] externs, &type_names tn,
                     ModuleRef llmod, &str name, bool pass_task,
                     &vec[ValueRef] args) -> ValueRef {
    let int n = vec::len[ValueRef](args) as int;
1097
    let ValueRef llnative = get_simple_extern_fn(externs, llmod, name, n);
1098
    let vec[ValueRef] call_args = [];
1099
    for (ValueRef a in args) { call_args += [b.ZExtOrBitCast(a, T_int())]; }
1100
    ret b.Call(llnative, call_args);
1101 1102
}

G
Graydon Hoare 已提交
1103
fn trans_non_gc_free(&@block_ctxt cx, ValueRef v) -> result {
1104
    cx.build.Call(cx.fcx.lcx.ccx.upcalls.free,
1105 1106
                  [cx.fcx.lltaskptr, cx.build.PointerCast(v, T_ptr(T_i8())),
                   C_int(0)]);
1107
    ret res(cx, C_int(0));
1108 1109
}

G
Graydon Hoare 已提交
1110
fn find_scope_cx(&@block_ctxt cx) -> @block_ctxt {
1111
    if (cx.kind != NON_SCOPE_BLOCK) { ret cx; }
1112
    alt (cx.parent) {
1113
        case (parent_some(?b)) { be find_scope_cx(b); }
1114
        case (parent_none) {
1115 1116
            cx.fcx.lcx.ccx.sess.bug("trans::find_scope_cx() " +
                                        "called on parentless block_ctxt");
1117 1118
        }
    }
1119 1120
}

G
Graydon Hoare 已提交
1121
fn umax(&@block_ctxt cx, ValueRef a, ValueRef b) -> ValueRef {
1122
    auto cond = cx.build.ICmp(lib::llvm::LLVMIntULT, a, b);
1123 1124 1125
    ret cx.build.Select(cond, b, a);
}

G
Graydon Hoare 已提交
1126
fn umin(&@block_ctxt cx, ValueRef a, ValueRef b) -> ValueRef {
1127
    auto cond = cx.build.ICmp(lib::llvm::LLVMIntULT, a, b);
1128 1129 1130
    ret cx.build.Select(cond, a, b);
}

G
Graydon Hoare 已提交
1131
fn align_to(&@block_ctxt cx, ValueRef off, ValueRef align) -> ValueRef {
1132 1133 1134 1135 1136
    auto mask = cx.build.Sub(align, C_int(1));
    auto bumped = cx.build.Add(off, mask);
    ret cx.build.And(bumped, cx.build.Not(mask));
}

1137

1138
// Returns the real size of the given type for the current target.
G
Graydon Hoare 已提交
1139
fn llsize_of_real(&@crate_ctxt cx, TypeRef t) -> uint {
1140
    ret llvm::LLVMStoreSizeOfType(cx.td.lltd, t);
1141 1142
}

1143
fn llsize_of(TypeRef t) -> ValueRef {
1144 1145
    ret llvm::LLVMConstIntCast(lib::llvm::llvm::LLVMSizeOf(t), T_int(),
                               False);
1146 1147
}

1148
fn llalign_of(TypeRef t) -> ValueRef {
1149 1150
    ret llvm::LLVMConstIntCast(lib::llvm::llvm::LLVMAlignOf(t), T_int(),
                               False);
1151 1152
}

1153 1154
fn size_of(&@block_ctxt cx, &ty::t t) -> result {
    if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
1155
        ret res(cx, llsize_of(type_of(cx.fcx.lcx.ccx, cx.sp, t)));
1156 1157 1158 1159
    }
    ret dynamic_size_of(cx, t);
}

1160 1161
fn align_of(&@block_ctxt cx, &ty::t t) -> result {
    if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
1162
        ret res(cx, llalign_of(type_of(cx.fcx.lcx.ccx, cx.sp, t)));
1163 1164 1165 1166
    }
    ret dynamic_align_of(cx, t);
}

G
Graydon Hoare 已提交
1167
fn alloca(&@block_ctxt cx, TypeRef t) -> ValueRef {
1168 1169 1170
    ret new_builder(cx.fcx.llallocas).Alloca(t);
}

G
Graydon Hoare 已提交
1171
fn array_alloca(&@block_ctxt cx, TypeRef t, ValueRef n) -> ValueRef {
1172 1173 1174 1175
    ret new_builder(cx.fcx.llallocas).ArrayAlloca(t, n);
}


1176 1177 1178 1179
// Creates a simpler, size-equivalent type. The resulting type is guaranteed
// to have (a) the same size as the type that was passed in; (b) to be non-
// recursive. This is done by replacing all boxes in a type with boxed unit
// types.
1180 1181 1182 1183 1184
fn simplify_type(&@crate_ctxt ccx, &ty::t typ) -> ty::t {
    fn simplifier(@crate_ctxt ccx, ty::t typ) -> ty::t {
        alt (ty::struct(ccx.tcx, typ)) {
            case (ty::ty_box(_)) {
                ret ty::mk_imm_box(ccx.tcx, ty::mk_nil(ccx.tcx));
1185
            }
1186 1187 1188
            case (ty::ty_vec(_)) {
                ret ty::mk_imm_vec(ccx.tcx, ty::mk_nil(ccx.tcx));
            }
1189 1190 1191
            case (ty::ty_fn(_, _, _, _, _)) {
                ret ty::mk_imm_tup(ccx.tcx,
                                   [ty::mk_imm_box(ccx.tcx,
1192
                                                   ty::mk_nil(ccx.tcx)),
1193
                                    ty::mk_imm_box(ccx.tcx,
1194 1195 1196
                                                   ty::mk_nil(ccx.tcx))]);
            }
            case (ty::ty_obj(_)) {
1197 1198
                ret ty::mk_imm_tup(ccx.tcx,
                                   [ty::mk_imm_box(ccx.tcx,
1199
                                                   ty::mk_nil(ccx.tcx)),
1200
                                    ty::mk_imm_box(ccx.tcx,
1201 1202
                                                   ty::mk_nil(ccx.tcx))]);
            }
1203 1204 1205
            case (_) { ret typ; }
        }
    }
1206
    ret ty::fold_ty(ccx.tcx, ty::fm_general(bind simplifier(ccx, _)), typ);
1207 1208
}

1209

1210
// Computes the size of the data part of a non-dynamically-sized tag.
1211
fn static_size_of_tag(&@crate_ctxt cx, &span sp, &ty::t t) -> uint {
1212
    if (ty::type_has_dynamic_size(cx.tcx, t)) {
1213 1214 1215
        cx.tcx.sess.span_err(sp,
                             "dynamically sized type passed to " +
                                 "static_size_of_tag()");
1216
    }
1217
    if (cx.tag_sizes.contains_key(t)) { ret cx.tag_sizes.get(t); }
B
Brian Anderson 已提交
1218
    auto tid;
1219 1220
    let vec[ty::t] subtys;
    alt (ty::struct(cx.tcx, t)) {
1221
        case (ty::ty_tag(?tid_, ?subtys_)) { tid = tid_; subtys = subtys_; }
1222
        case (_) {
1223 1224 1225
            cx.tcx.sess.span_err(sp,
                                 "non-tag passed to " +
                                     "static_size_of_tag()");
1226 1227 1228
        }
    }
    // Compute max(variant sizes).
1229

1230
    auto max_size = 0u;
1231 1232
    auto variants = ty::tag_variants(cx.tcx, tid);
    for (ty::variant_info variant in variants) {
1233
        auto tup_ty = simplify_type(cx, ty::mk_imm_tup(cx.tcx, variant.args));
1234 1235
        // Perform any type parameter substitutions.

1236
        tup_ty = ty::substitute_type_params(cx.tcx, subtys, tup_ty);
1237 1238
        // Here we possibly do a recursive call.

1239 1240
        auto this_size = llsize_of_real(cx, type_of(cx, sp, tup_ty));
        if (max_size < this_size) { max_size = this_size; }
1241 1242 1243 1244 1245
    }
    cx.tag_sizes.insert(t, max_size);
    ret max_size;
}

1246 1247
fn dynamic_size_of(&@block_ctxt cx, ty::t t) -> result {
    fn align_elements(&@block_ctxt cx, &vec[ty::t] elts) -> result {
1248 1249 1250 1251 1252 1253 1254 1255
        //
        // C padding rules:
        //
        //
        //   - Pad after each element so that next element is aligned.
        //   - Pad after final structure member so that whole structure
        //     is aligned to max alignment of interior.
        //
1256

1257 1258 1259
        auto off = C_int(0);
        auto max_align = C_int(1);
        auto bcx = cx;
1260
        for (ty::t e in elts) {
1261 1262 1263 1264 1265
            auto elt_align = align_of(bcx, e);
            bcx = elt_align.bcx;
            auto elt_size = size_of(bcx, e);
            bcx = elt_size.bcx;
            auto aligned_off = align_to(bcx, off, elt_align.val);
1266
            off = bcx.build.Add(aligned_off, elt_size.val);
1267 1268 1269 1270 1271
            max_align = umax(bcx, max_align, elt_align.val);
        }
        off = align_to(bcx, off, max_align);
        ret res(bcx, off);
    }
1272 1273
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
        case (ty::ty_param(?p)) {
1274 1275
            auto szptr =
                field_of_tydesc(cx, t, false, abi::tydesc_field_size);
1276
            ret res(szptr.bcx, szptr.bcx.build.Load(szptr.val));
1277
        }
1278
        case (ty::ty_tup(?elts)) {
1279
            let vec[ty::t] tys = [];
1280
            for (ty::mt mt in elts) { tys += [mt.ty]; }
1281
            ret align_elements(cx, tys);
1282
        }
1283
        case (ty::ty_rec(?flds)) {
1284
            let vec[ty::t] tys = [];
1285
            for (ty::field f in flds) { tys += [f.mt.ty]; }
1286
            ret align_elements(cx, tys);
1287
        }
1288
        case (ty::ty_tag(?tid, ?tps)) {
1289 1290
            auto bcx = cx;
            // Compute max(variant sizes).
1291

1292
            let ValueRef max_size = alloca(bcx, T_int());
1293
            bcx.build.Store(C_int(0), max_size);
1294 1295
            auto variants = ty::tag_variants(bcx.fcx.lcx.ccx.tcx, tid);
            for (ty::variant_info variant in variants) {
1296
                // Perform type substitution on the raw argument types.
1297

1298
                let vec[ty::t] raw_tys = variant.args;
1299
                let vec[ty::t] tys = [];
1300
                for (ty::t raw_ty in raw_tys) {
1301 1302 1303
                    auto t =
                        ty::substitute_type_params(cx.fcx.lcx.ccx.tcx, tps,
                                                   raw_ty);
1304
                    tys += [t];
1305
                }
1306 1307 1308 1309 1310 1311
                auto rslt = align_elements(bcx, tys);
                bcx = rslt.bcx;
                auto this_size = rslt.val;
                auto old_max_size = bcx.build.Load(max_size);
                bcx.build.Store(umax(bcx, this_size, old_max_size), max_size);
            }
1312 1313 1314
            auto max_size_val = bcx.build.Load(max_size);
            auto total_size = bcx.build.Add(max_size_val, llsize_of(T_int()));
            ret res(bcx, total_size);
1315
        }
1316 1317 1318
    }
}

1319 1320 1321
fn dynamic_align_of(&@block_ctxt cx, &ty::t t) -> result {
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
        case (ty::ty_param(?p)) {
1322 1323
            auto aptr =
                field_of_tydesc(cx, t, false, abi::tydesc_field_align);
1324
            ret res(aptr.bcx, aptr.bcx.build.Load(aptr.val));
1325
        }
1326
        case (ty::ty_tup(?elts)) {
1327
            auto a = C_int(1);
1328
            auto bcx = cx;
1329
            for (ty::mt e in elts) {
1330
                auto align = align_of(bcx, e.ty);
1331 1332
                bcx = align.bcx;
                a = umax(bcx, a, align.val);
1333
            }
1334
            ret res(bcx, a);
1335
        }
1336
        case (ty::ty_rec(?flds)) {
1337
            auto a = C_int(1);
1338
            auto bcx = cx;
1339
            for (ty::field f in flds) {
1340
                auto align = align_of(bcx, f.mt.ty);
1341 1342
                bcx = align.bcx;
                a = umax(bcx, a, align.val);
1343
            }
1344
            ret res(bcx, a);
1345
        }
1346
        case (ty::ty_tag(_, _)) {
1347
            ret res(cx, C_int(1)); // FIXME: stub
1348

1349
        }
1350 1351 1352
    }
}

1353

1354
// Replacement for the LLVM 'GEP' instruction when field-indexing into a
1355
// tuple-like structure (tup, rec) with a static index. This one is driven off
1356
// ty::struct and knows what to do when it runs into a ty_param stuck in the
1357 1358
// middle of the thing it's GEP'ing into. Much like size_of and align_of,
// above.
1359 1360
fn GEP_tup_like(&@block_ctxt cx, &ty::t t, ValueRef base, &vec[int] ixs) ->
   result {
1361
    assert (ty::type_is_tup_like(cx.fcx.lcx.ccx.tcx, t));
1362 1363
    // It might be a static-known type. Handle this.

1364
    if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
1365
        let vec[ValueRef] v = [];
1366
        for (int i in ixs) { v += [C_int(i)]; }
1367
        ret res(cx, cx.build.GEP(base, v));
1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384
    }
    // It is a dynamic-containing type that, if we convert directly to an LLVM
    // TypeRef, will be all wrong; there's no proper LLVM type to represent
    // it, and the lowering function will stick in i8* values for each
    // ty_param, which is not right; the ty_params are all of some dynamic
    // size.
    //
    // What we must do instead is sadder. We must look through the indices
    // manually and split the input type into a prefix and a target. We then
    // measure the prefix size, bump the input pointer by that amount, and
    // cast to a pointer-to-target type.

    // Given a type, an index vector and an element number N in that vector,
    // calculate index X and the type that results by taking the first X-1
    // elements of the type and splitting the Xth off. Return the prefix as
    // well as the innermost Xth type.

1385 1386
    fn split_type(&@crate_ctxt ccx, &ty::t t, &vec[int] ixs, uint n) ->
       rec(vec[ty::t] prefix, ty::t target) {
1387
        let uint len = vec::len[int](ixs);
1388
        // We don't support 0-index or 1-index GEPs: The former is nonsense
1389 1390 1391
        // and the latter would only be meaningful if we supported non-0
        // values for the 0th index (we don't).

1392
        assert (len > 1u);
1393 1394 1395 1396
        if (n == 0u) {
            // Since we're starting from a value that's a pointer to a
            // *single* structure, the first index (in GEP-ese) should just be
            // 0, to yield the pointee.
1397

1398
            assert (ixs.(n) == 0);
1399
            ret split_type(ccx, t, ixs, n + 1u);
1400
        }
1401
        assert (n < len);
1402
        let int ix = ixs.(n);
1403
        let vec[ty::t] prefix = [];
1404 1405
        let int i = 0;
        while (i < ix) {
1406
            vec::push[ty::t](prefix,
1407 1408
                             ty::get_element_type(ccx.tcx, t, i as uint));
            i += 1;
1409
        }
1410
        auto selected = ty::get_element_type(ccx.tcx, t, i as uint);
1411
        if (n == len - 1u) {
1412 1413
            // We are at the innermost index.

1414
            ret rec(prefix=prefix, target=selected);
1415 1416 1417 1418
        } else {
            // Not the innermost index; call self recursively to dig deeper.
            // Once we get an inner result, append it current prefix and
            // return to caller.
1419 1420

            auto inner = split_type(ccx, selected, ixs, n + 1u);
1421 1422 1423 1424 1425 1426 1427 1428
            prefix += inner.prefix;
            ret rec(prefix=prefix with inner);
        }
    }
    // We make a fake prefix tuple-type here; luckily for measuring sizes
    // the tuple parens are associative so it doesn't matter that we've
    // flattened the incoming structure.

1429
    auto s = split_type(cx.fcx.lcx.ccx, t, ixs, 0u);
1430
    auto prefix_ty = ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, s.prefix);
1431 1432 1433 1434
    auto bcx = cx;
    auto sz = size_of(bcx, prefix_ty);
    bcx = sz.bcx;
    auto raw = bcx.build.PointerCast(base, T_ptr(T_i8()));
1435
    auto bumped = bcx.build.GEP(raw, [sz.val]);
1436
    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, s.target)) {
1437
        ret res(bcx, bumped);
1438
    }
1439
    auto typ = T_ptr(type_of(bcx.fcx.lcx.ccx, bcx.sp, s.target));
1440
    ret res(bcx, bcx.build.PointerCast(bumped, typ));
1441 1442
}

1443

1444 1445 1446 1447
// Replacement for the LLVM 'GEP' instruction when field indexing into a tag.
// This function uses GEP_tup_like() above and automatically performs casts as
// appropriate. @llblobptr is the data part of a tag value; its actual type is
// meaningless, as it will be cast away.
1448 1449 1450 1451
fn GEP_tag(@block_ctxt cx, ValueRef llblobptr, &ast::def_id tag_id,
           &ast::def_id variant_id, &vec[ty::t] ty_substs, int ix) -> result {
    auto variant =
        ty::tag_variant_with_id(cx.fcx.lcx.ccx.tcx, tag_id, variant_id);
1452 1453
    // Synthesize a tuple type so that GEP_tup_like() can work its magic.
    // Separately, store the type of the element we're interested in.
1454

1455
    auto arg_tys = variant.args;
1456
    auto elem_ty = ty::mk_nil(cx.fcx.lcx.ccx.tcx); // typestate infelicity
1457

1458
    auto i = 0;
1459
    let vec[ty::t] true_arg_tys = [];
1460
    for (ty::t aty in arg_tys) {
1461 1462
        auto arg_ty =
            ty::substitute_type_params(cx.fcx.lcx.ccx.tcx, ty_substs, aty);
1463
        true_arg_tys += [arg_ty];
1464
        if (i == ix) { elem_ty = arg_ty; }
1465 1466
        i += 1;
    }
1467
    auto tup_ty = ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, true_arg_tys);
1468 1469
    // Cast the blob pointer to the appropriate type, if we need to (i.e. if
    // the blob pointer isn't dynamically sized).
1470

1471
    let ValueRef llunionptr;
1472
    if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, tup_ty)) {
1473
        auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, tup_ty);
1474
        llunionptr = cx.build.TruncOrBitCast(llblobptr, T_ptr(llty));
1475
    } else { llunionptr = llblobptr; }
1476 1477
    // Do the GEP_tup_like().

1478
    auto rslt = GEP_tup_like(cx, tup_ty, llunionptr, [0, ix]);
1479
    // Cast the result to the appropriate type, if necessary.
1480

1481
    auto val;
1482
    if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, elem_ty)) {
1483
        auto llelemty = type_of(rslt.bcx.fcx.lcx.ccx, cx.sp, elem_ty);
1484
        val = rslt.bcx.build.PointerCast(rslt.val, T_ptr(llelemty));
1485
    } else { val = rslt.val; }
1486 1487 1488
    ret res(rslt.bcx, val);
}

1489

L
Lindsey Kuper 已提交
1490 1491
// trans_raw_malloc: expects a type indicating which pointer type we want and
// a size indicating how much space we want malloc'd.
1492 1493
fn trans_raw_malloc(&@block_ctxt cx, TypeRef llptr_ty, ValueRef llsize) ->
   result {
1494
    // FIXME: need a table to collect tydesc globals.
1495

1496
    auto tydesc = C_null(T_ptr(T_tydesc(cx.fcx.lcx.ccx.tn)));
1497 1498 1499
    auto rval =
        cx.build.Call(cx.fcx.lcx.ccx.upcalls.malloc,
                      [cx.fcx.lltaskptr, llsize, tydesc]);
1500
    ret res(cx, cx.build.PointerCast(rval, llptr_ty));
1501 1502
}

L
Lindsey Kuper 已提交
1503 1504 1505 1506

// trans_malloc_boxed: expects an unboxed type and returns a pointer to enough
// space for something of that type, along with space for a reference count;
// in other words, it allocates a box for something of that type.
1507
fn trans_malloc_boxed(&@block_ctxt cx, ty::t t) -> result {
1508 1509
    // Synthesize a fake box type structurally so we have something
    // to measure the size of.
L
Lindsey Kuper 已提交
1510 1511 1512 1513 1514

    // We synthesize two types here because we want both the type of the
    // pointer and the pointee.  boxed_body is the type that we measure the
    // size of; box_ptr is the type that's converted to a TypeRef and used as
    // the pointer cast target in trans_raw_malloc.
1515 1516 1517 1518 1519 1520

    auto boxed_body =
        ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx,
                       // The mk_int here is the space being
                       // reserved for the refcount.
                       [ty::mk_int(cx.fcx.lcx.ccx.tcx), t]);
1521
    auto box_ptr = ty::mk_imm_box(cx.fcx.lcx.ccx.tcx, t);
1522
    auto sz = size_of(cx, boxed_body);
L
Lindsey Kuper 已提交
1523 1524 1525
    // Grab the TypeRef type of box_ptr, because that's what trans_raw_malloc
    // wants.

1526
    auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, box_ptr);
1527
    ret trans_raw_malloc(sz.bcx, llty, sz.val);
1528 1529 1530
}


1531 1532 1533 1534 1535
// Type descriptor and type glue stuff

// Given a type and a field index into its corresponding type descriptor,
// returns an LLVM ValueRef of that field from the tydesc, generating the
// tydesc if necessary.
1536 1537
fn field_of_tydesc(&@block_ctxt cx, &ty::t t, bool escapes, int field) ->
   result {
1538 1539
    auto ti = none[@tydesc_info];
    auto tydesc = get_tydesc(cx, t, escapes, ti);
1540
    ret res(tydesc.bcx,
1541
            tydesc.bcx.build.GEP(tydesc.val, [C_int(0), C_int(field)]));
1542
}
1543

1544

1545
// Given a type containing ty params, build a vector containing a ValueRef for
1546 1547
// each of the ty params it uses (from the current frame) and a vector of the
// indices of the ty params present in the type. This is used solely for
1548
// constructing derived tydescs.
1549
fn linearize_ty_params(&@block_ctxt cx, &ty::t t) ->
1550
   tup(vec[uint], vec[ValueRef]) {
1551 1552
    let vec[ValueRef] param_vals = [];
    let vec[uint] param_defs = [];
1553 1554 1555 1556
    type rr =
        rec(@block_ctxt cx,
            mutable vec[ValueRef] vals,
            mutable vec[uint] defs);
1557

1558
    fn linearizer(@rr r, ty::t t) {
1559
        alt (ty::struct(r.cx.fcx.lcx.ccx.tcx, t)) {
1560
            case (ty::ty_param(?pid)) {
1561
                let bool seen = false;
1562
                for (uint d in r.defs) { if (d == pid) { seen = true; } }
1563
                if (!seen) {
1564 1565
                    r.vals += [r.cx.fcx.lltydescs.(pid)];
                    r.defs += [pid];
1566
                }
1567
            }
1568
            case (_) { }
1569 1570
        }
    }
1571
    auto x = @rec(cx=cx, mutable vals=param_vals, mutable defs=param_defs);
1572
    auto f = bind linearizer(x, _);
1573
    ty::walk_ty(cx.fcx.lcx.ccx.tcx, f, t);
1574 1575 1576
    ret tup(x.defs, x.vals);
}

G
Graydon Hoare 已提交
1577
fn trans_stack_local_derived_tydesc(&@block_ctxt cx, ValueRef llsz,
1578 1579
                                    ValueRef llalign, ValueRef llroottydesc,
                                    ValueRef llparamtydescs) -> ValueRef {
1580
    auto llmyroottydesc = alloca(cx, T_tydesc(cx.fcx.lcx.ccx.tn));
1581
    // By convention, desc 0 is the root descriptor.
1582

1583
    llroottydesc = cx.build.Load(llroottydesc);
1584
    cx.build.Store(llroottydesc, llmyroottydesc);
1585
    // Store a pointer to the rest of the descriptors.
1586

1587
    auto llfirstparam = cx.build.GEP(llparamtydescs, [C_int(0), C_int(0)]);
1588
    cx.build.Store(llfirstparam,
1589
                   cx.build.GEP(llmyroottydesc, [C_int(0), C_int(0)]));
1590
    cx.build.Store(llsz, cx.build.GEP(llmyroottydesc, [C_int(0), C_int(1)]));
1591
    cx.build.Store(llalign,
1592
                   cx.build.GEP(llmyroottydesc, [C_int(0), C_int(2)]));
1593
    ret llmyroottydesc;
1594 1595
}

1596 1597
fn get_derived_tydesc(&@block_ctxt cx, &ty::t t, bool escapes,
                      &mutable option::t[@tydesc_info] static_ti) -> result {
1598
    alt (cx.fcx.derived_tydescs.find(t)) {
1599
        case (some(?info)) {
1600

1601 1602 1603 1604
            // If the tydesc escapes in this context, the cached derived
            // tydesc also has to be one that was marked as escaping.
            if (!(escapes && !info.escapes)) { ret res(cx, info.lltydesc); }
        }
1605
        case (none) {/* fall through */ }
1606
    }
1607
    cx.fcx.lcx.ccx.stats.n_derived_tydescs += 1u;
1608
    auto bcx = new_raw_block_ctxt(cx.fcx, cx.fcx.llderivedtydescs);
1609
    let uint n_params = ty::count_ty_params(bcx.fcx.lcx.ccx.tcx, t);
1610
    auto tys = linearize_ty_params(bcx, t);
1611 1612
    assert (n_params == vec::len[uint](tys._0));
    assert (n_params == vec::len[ValueRef](tys._1));
1613 1614 1615 1616
    auto root_ti = get_static_tydesc(bcx, t, tys._0);
    static_ti = some[@tydesc_info](root_ti);
    lazily_emit_all_tydesc_glue(cx, static_ti);
    auto root = root_ti.tydesc;
1617 1618 1619 1620 1621 1622
    auto sz = size_of(bcx, t);
    bcx = sz.bcx;
    auto align = align_of(bcx, t);
    bcx = align.bcx;
    auto v;
    if (escapes) {
1623 1624 1625 1626
        auto tydescs =
            alloca(bcx, /* for root*/
                   T_array(T_ptr(T_tydesc(bcx.fcx.lcx.ccx.tn)),
                           1u + n_params));
1627
        auto i = 0;
1628
        auto tdp = bcx.build.GEP(tydescs, [C_int(0), C_int(i)]);
1629
        bcx.build.Store(root, tdp);
1630 1631
        i += 1;
        for (ValueRef td in tys._1) {
1632
            auto tdp = bcx.build.GEP(tydescs, [C_int(0), C_int(i)]);
1633
            bcx.build.Store(td, tdp);
1634 1635
            i += 1;
        }
1636 1637 1638 1639 1640 1641 1642 1643
        auto lltydescsptr =
            bcx.build.PointerCast(tydescs,
                                  T_ptr(T_ptr(T_tydesc(bcx.fcx.lcx.ccx.tn))));
        auto td_val =
            bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.get_type_desc,
                           [bcx.fcx.lltaskptr, C_null(T_ptr(T_nil())), sz.val,
                            align.val, C_int(1u + n_params as int),
                            lltydescsptr]);
1644
        v = td_val;
1645
    } else {
1646 1647 1648
        auto llparamtydescs =
            alloca(bcx,
                   T_array(T_ptr(T_tydesc(bcx.fcx.lcx.ccx.tn)), n_params));
1649 1650
        auto i = 0;
        for (ValueRef td in tys._1) {
1651
            auto tdp = bcx.build.GEP(llparamtydescs, [C_int(0), C_int(i)]);
1652 1653
            bcx.build.Store(td, tdp);
            i += 1;
1654
        }
1655 1656
        v =
            trans_stack_local_derived_tydesc(bcx, sz.val, align.val, root,
1657
                                             llparamtydescs);
1658
    }
1659 1660
    bcx.fcx.derived_tydescs.insert(t, rec(lltydesc=v, escapes=escapes));
    ret res(cx, v);
1661 1662
}

1663 1664
fn get_tydesc(&@block_ctxt cx, &ty::t t, bool escapes,
              &mutable option::t[@tydesc_info] static_ti) -> result {
1665
    // Is the supplied type a type param? If so, return the passed-in tydesc.
1666

1667
    alt (ty::type_param(cx.fcx.lcx.ccx.tcx, t)) {
1668
        case (some(?id)) { ret res(cx, cx.fcx.lltydescs.(id)); }
1669
        case (none) {/* fall through */ }
1670
    }
1671
    // Does it contain a type param? If so, generate a derived tydesc.
1672

1673
    if (ty::type_contains_params(cx.fcx.lcx.ccx.tcx, t)) {
1674
        ret get_derived_tydesc(cx, t, escapes, static_ti);
1675 1676
    }
    // Otherwise, generate a tydesc if necessary, and return it.
1677

1678
    let vec[uint] tps = [];
1679 1680 1681
    auto info = get_static_tydesc(cx, t, tps);
    static_ti = some[@tydesc_info](info);
    ret res(cx, info.tydesc);
1682 1683
}

1684 1685
fn get_static_tydesc(&@block_ctxt cx, &ty::t t, &vec[uint] ty_params) ->
   @tydesc_info {
1686
    alt (cx.fcx.lcx.ccx.tydescs.find(t)) {
1687
        case (some(?info)) { ret info; }
1688
        case (none) {
1689
            cx.fcx.lcx.ccx.stats.n_static_tydescs += 1u;
1690
            auto info = declare_tydesc(cx.fcx.lcx, cx.sp, t, ty_params);
1691
            cx.fcx.lcx.ccx.tydescs.insert(t, info);
1692 1693
            ret info;
        }
1694
    }
1695 1696
}

1697
fn set_no_inline(ValueRef f) {
1698 1699 1700
    llvm::LLVMAddFunctionAttr(f,
                              lib::llvm::LLVMNoInlineAttribute as
                                  lib::llvm::llvm::Attribute);
1701 1702
}

1703
fn set_uwtable(ValueRef f) {
1704 1705 1706
    llvm::LLVMAddFunctionAttr(f,
                              lib::llvm::LLVMUWTableAttribute as
                                  lib::llvm::llvm::Attribute);
1707 1708
}

1709
fn set_always_inline(ValueRef f) {
1710 1711 1712
    llvm::LLVMAddFunctionAttr(f,
                              lib::llvm::LLVMAlwaysInlineAttribute as
                                  lib::llvm::llvm::Attribute);
1713 1714 1715 1716 1717
}

fn set_glue_inlining(&@local_ctxt cx, ValueRef f, &ty::t t) {
    if (ty::type_is_structural(cx.ccx.tcx, t)) {
        set_no_inline(f);
1718
    } else { set_always_inline(f); }
1719 1720 1721
}


1722
// Generates the declaration for (but doesn't emit) a type descriptor.
1723 1724
fn declare_tydesc(&@local_ctxt cx, &span sp, &ty::t t, vec[uint] ty_params) ->
   @tydesc_info {
1725
    log "+++ declare_tydesc " + ty_to_str(cx.ccx.tcx, t);
1726
    auto ccx = cx.ccx;
1727 1728
    auto llsize;
    auto llalign;
1729
    if (!ty::type_has_dynamic_size(ccx.tcx, t)) {
1730
        auto llty = type_of(ccx, sp, t);
1731 1732 1733 1734 1735
        llsize = llsize_of(llty);
        llalign = llalign_of(llty);
    } else {
        // These will be overwritten as the derived tydesc is generated, so
        // we create placeholder values.
1736

1737 1738 1739
        llsize = C_int(0);
        llalign = C_int(0);
    }
1740 1741
    auto name;
    if (cx.ccx.sess.get_opts().debuginfo) {
1742
        name = mangle_internal_name_by_type_only(cx.ccx, t, "tydesc");
1743
        name = sanitize(name);
1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756
    } else { name = mangle_internal_name_by_seq(cx.ccx, "tydesc"); }
    auto gvar =
        llvm::LLVMAddGlobal(ccx.llmod, T_tydesc(ccx.tn), str::buf(name));
    auto info =
        @rec(ty=t,
             tydesc=gvar,
             size=llsize,
             align=llalign,
             mutable take_glue=none[ValueRef],
             mutable drop_glue=none[ValueRef],
             mutable free_glue=none[ValueRef],
             mutable cmp_glue=none[ValueRef],
             ty_params=ty_params);
1757
    log "--- declare_tydesc " + ty_to_str(cx.ccx.tcx, t);
1758
    ret info;
1759 1760
}

1761
tag make_generic_glue_helper_fn {
1762
    mgghf_single(fn(&@block_ctxt, ValueRef, &ty::t) );
1763
    mgghf_cmp;
1764 1765
}

1766 1767
fn declare_generic_glue(&@local_ctxt cx, &ty::t t, TypeRef llfnty, &str name)
   -> ValueRef {
1768
    auto fn_nm;
1769
    if (cx.ccx.sess.get_opts().debuginfo) {
1770
        fn_nm = mangle_internal_name_by_type_only(cx.ccx, t, "glue_" + name);
1771
        fn_nm = sanitize(fn_nm);
1772
    } else { fn_nm = mangle_internal_name_by_seq(cx.ccx, "glue_" + name); }
1773
    auto llfn = decl_cdecl_fn(cx.ccx.llmod, fn_nm, llfnty);
1774
    set_glue_inlining(cx, llfn, t);
1775
    ret llfn;
1776
}
1777

1778
fn make_generic_glue(&@local_ctxt cx, &span sp, &ty::t t, ValueRef llfn,
G
Graydon Hoare 已提交
1779 1780
                     &make_generic_glue_helper_fn helper,
                     &vec[uint] ty_params) -> ValueRef {
1781
    auto fcx = new_fn_ctxt(cx, sp, llfn);
1782 1783
    llvm::LLVMSetLinkage(llfn,
                         lib::llvm::LLVMInternalLinkage as llvm::Linkage);
1784
    cx.ccx.stats.n_glues_created += 1u;
1785 1786 1787 1788
    // Any nontrivial glue is with values passed *by alias*; this is a
    // requirement since in many contexts glue is invoked indirectly and
    // the caller has no idea if it's dealing with something that can be
    // passed by value.
1789

1790
    auto llty;
1791
    if (ty::type_has_dynamic_size(cx.ccx.tcx, t)) {
1792
        llty = T_ptr(T_i8());
1793
    } else { llty = T_ptr(type_of(cx.ccx, sp, t)); }
1794
    auto ty_param_count = vec::len[uint](ty_params);
1795
    auto lltyparams = llvm::LLVMGetParam(llfn, 3u);
1796
    auto copy_args_bcx = new_raw_block_ctxt(fcx, fcx.llcopyargs);
1797
    auto lltydescs = vec::empty_mut[ValueRef]();
1798 1799
    auto p = 0u;
    while (p < ty_param_count) {
1800
        auto llparam = copy_args_bcx.build.GEP(lltyparams, [C_int(p as int)]);
1801
        llparam = copy_args_bcx.build.Load(llparam);
1802
        vec::grow_set[ValueRef](lltydescs, ty_params.(p), 0 as ValueRef,
1803 1804 1805
                                llparam);
        p += 1u;
    }
1806
    fcx.lltydescs = vec::freeze[ValueRef](lltydescs);
1807 1808
    auto bcx = new_top_block_ctxt(fcx);
    auto lltop = bcx.llbb;
1809
    auto llrawptr0 = llvm::LLVMGetParam(llfn, 4u);
1810 1811
    auto llval0 = bcx.build.BitCast(llrawptr0, llty);
    alt (helper) {
1812
        case (mgghf_single(?single_fn)) { single_fn(bcx, llval0, t); }
1813
        case (mgghf_cmp) {
1814
            auto llrawptr1 = llvm::LLVMGetParam(llfn, 5u);
1815
            auto llval1 = bcx.build.BitCast(llrawptr1, llty);
1816
            auto llcmpval = llvm::LLVMGetParam(llfn, 6u);
1817
            make_cmp_glue(bcx, llval0, llval1, t, llcmpval);
1818
        }
1819
    }
1820
    finish_fn(fcx, lltop);
1821 1822 1823
    ret llfn;
}

1824 1825 1826 1827 1828
fn emit_tydescs(&@crate_ctxt ccx) {
    for each (@tup(ty::t, @tydesc_info) pair in ccx.tydescs.items()) {
        auto glue_fn_ty = T_ptr(T_glue_fn(ccx.tn));
        auto cmp_fn_ty = T_ptr(T_cmp_glue_fn(ccx.tn));
        auto ti = pair._1;
1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870
        auto take_glue =
            alt ({ ti.take_glue }) {
                case (none) {
                    ccx.stats.n_null_glues += 1u;
                    C_null(glue_fn_ty)
                }
                case (some(?v)) { ccx.stats.n_real_glues += 1u; v }
            };
        auto drop_glue =
            alt ({ ti.drop_glue }) {
                case (none) {
                    ccx.stats.n_null_glues += 1u;
                    C_null(glue_fn_ty)
                }
                case (some(?v)) { ccx.stats.n_real_glues += 1u; v }
            };
        auto free_glue =
            alt ({ ti.free_glue }) {
                case (none) {
                    ccx.stats.n_null_glues += 1u;
                    C_null(glue_fn_ty)
                }
                case (some(?v)) { ccx.stats.n_real_glues += 1u; v }
            };
        auto cmp_glue =
            alt ({ ti.cmp_glue }) {
                case (none) {
                    ccx.stats.n_null_glues += 1u;
                    C_null(cmp_fn_ty)
                }
                case (some(?v)) { ccx.stats.n_real_glues += 1u; v }
            };
        auto tydesc =
            C_struct([C_null(T_ptr(T_ptr(T_tydesc(ccx.tn)))), ti.size,
                      ti.align, take_glue, // take_glue
                       drop_glue, // drop_glue
                       free_glue, // free_glue
                       C_null(glue_fn_ty), // sever_glue
                       C_null(glue_fn_ty), // mark_glue
                       C_null(glue_fn_ty), // obj_drop_glue
                       C_null(glue_fn_ty), // is_stateful
                       cmp_glue]); // cmp_glue
1871 1872 1873 1874

        auto gvar = ti.tydesc;
        llvm::LLVMSetInitializer(gvar, tydesc);
        llvm::LLVMSetGlobalConstant(gvar, True);
1875 1876
        llvm::LLVMSetLinkage(gvar,
                             lib::llvm::LLVMInternalLinkage as llvm::Linkage);
1877 1878 1879
    }
}

1880
fn make_take_glue(&@block_ctxt cx, ValueRef v, &ty::t t) {
1881
    // NB: v is an *alias* of type t here, not a direct value.
1882

1883
    auto bcx;
1884
    if (ty::type_is_boxed(cx.fcx.lcx.ccx.tcx, t)) {
1885
        bcx = incr_refcnt_of_boxed(cx, cx.build.Load(v)).bcx;
1886
    } else if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, t)) {
1887 1888
        bcx = iter_structural_ty(cx, v, t, bind take_ty(_, _, _)).bcx;
    } else { bcx = cx; }
1889
    bcx.build.RetVoid();
1890 1891
}

G
Graydon Hoare 已提交
1892
fn incr_refcnt_of_boxed(&@block_ctxt cx, ValueRef box_ptr) -> result {
1893 1894
    auto rc_ptr =
        cx.build.GEP(box_ptr, [C_int(0), C_int(abi::box_rc_field_refcnt)]);
1895 1896 1897
    auto rc = cx.build.Load(rc_ptr);
    auto rc_adj_cx = new_sub_block_ctxt(cx, "rc++");
    auto next_cx = new_sub_block_ctxt(cx, "next");
1898 1899 1900
    auto const_test =
        cx.build.ICmp(lib::llvm::LLVMIntEQ, C_int(abi::const_refcount as int),
                      rc);
1901 1902 1903 1904 1905 1906 1907
    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());
}

1908 1909
fn make_free_glue(&@block_ctxt cx, ValueRef v0, &ty::t t) {
    // NB: v is an *alias* of type t here, not a direct value.
1910

1911
    auto rslt;
1912 1913
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
        case (ty::ty_str) {
1914
            auto v = cx.build.Load(v0);
1915
            rslt = trans_non_gc_free(cx, v);
1916
        }
1917
        case (ty::ty_vec(_)) {
1918
            auto v = cx.build.Load(v0);
1919
            auto res = iter_sequence(cx, v, t, bind drop_ty(_, _, _));
1920
            // FIXME: switch gc/non-gc on layer of the type.
1921

1922
            rslt = trans_non_gc_free(res.bcx, v);
1923
        }
1924
        case (ty::ty_box(?body_mt)) {
1925
            auto v = cx.build.Load(v0);
1926 1927
            auto body =
                cx.build.GEP(v, [C_int(0), C_int(abi::box_rc_field_body)]);
1928 1929 1930 1931
            auto body_ty = body_mt.ty;
            auto body_val = load_if_immediate(cx, body, body_ty);
            auto res = drop_ty(cx, body_val, body_ty);
            // FIXME: switch gc/non-gc on layer of the type.
1932

1933
            rslt = trans_non_gc_free(res.bcx, v);
1934
        }
1935
        case (ty::ty_port(_)) {
1936
            auto v = cx.build.Load(v0);
1937 1938
            cx.build.Call(cx.fcx.lcx.ccx.upcalls.del_port,
                          [cx.fcx.lltaskptr,
1939
                           cx.build.PointerCast(v, T_opaque_port_ptr())]);
1940
            rslt = res(cx, C_int(0));
B
Brian Anderson 已提交
1941
        }
1942
        case (ty::ty_chan(_)) {
1943
            auto v = cx.build.Load(v0);
1944 1945
            cx.build.Call(cx.fcx.lcx.ccx.upcalls.del_chan,
                          [cx.fcx.lltaskptr,
1946
                           cx.build.PointerCast(v, T_opaque_chan_ptr())]);
1947
            rslt = res(cx, C_int(0));
B
Brian Anderson 已提交
1948
        }
E
Eric Holk 已提交
1949 1950
        case (ty::ty_task) {
            // TODO: call upcall_kill
1951

E
Eric Holk 已提交
1952 1953
            rslt = res(cx, C_nil());
        }
1954
        case (ty::ty_obj(_)) {
1955
            auto box_cell =
1956
                cx.build.GEP(v0, [C_int(0), C_int(abi::obj_field_box)]);
1957 1958
            auto b = cx.build.Load(box_cell);
            auto body =
1959
                cx.build.GEP(b, [C_int(0), C_int(abi::box_rc_field_body)]);
1960 1961
            auto tydescptr =
                cx.build.GEP(body,
1962
                             [C_int(0), C_int(abi::obj_body_elt_tydesc)]);
1963 1964 1965
            auto tydesc = cx.build.Load(tydescptr);
            auto cx_ = maybe_call_dtor(cx, v0);
            // Call through the obj's own fields-drop glue first.
1966

1967 1968 1969 1970 1971
            auto ti = none[@tydesc_info];
            call_tydesc_glue_full(cx_, body, tydesc,
                                  abi::tydesc_field_drop_glue, ti);
            // Then free the body.
            // FIXME: switch gc/non-gc on layer of the type.
1972

1973
            rslt = trans_non_gc_free(cx_, b);
1974
        }
1975
        case (ty::ty_fn(_, _, _, _, _)) {
1976
            auto box_cell =
1977
                cx.build.GEP(v0, [C_int(0), C_int(abi::fn_field_box)]);
1978 1979
            auto v = cx.build.Load(box_cell);
            // Call through the closure's own fields-drop glue first.
1980

1981
            auto body =
1982
                cx.build.GEP(v, [C_int(0), C_int(abi::box_rc_field_body)]);
1983 1984
            auto bindings =
                cx.build.GEP(body,
1985
                             [C_int(0), C_int(abi::closure_elt_bindings)]);
1986 1987
            auto tydescptr =
                cx.build.GEP(body,
1988
                             [C_int(0), C_int(abi::closure_elt_tydesc)]);
1989 1990 1991 1992 1993
            auto ti = none[@tydesc_info];
            call_tydesc_glue_full(cx, bindings, cx.build.Load(tydescptr),
                                  abi::tydesc_field_drop_glue, ti);
            // Then free the body.
            // FIXME: switch gc/non-gc on layer of the type.
1994

1995 1996 1997 1998 1999 2000 2001
            rslt = trans_non_gc_free(cx, v);
        }
        case (_) { rslt = res(cx, C_nil()); }
    }
    rslt.bcx.build.RetVoid();
}

2002 2003
fn maybe_free_ivec_heap_part(&@block_ctxt cx, ValueRef v0, ty::t unit_ty) ->
   result {
2004
    auto llunitty = type_of_or_i8(cx, unit_ty);
2005 2006 2007 2008
    auto stack_len =
        cx.build.Load(cx.build.InBoundsGEP(v0,
                                           [C_int(0),
                                            C_uint(abi::ivec_elt_len)]));
2009 2010
    auto maybe_on_heap_cx = new_sub_block_ctxt(cx, "maybe_on_heap");
    auto next_cx = new_sub_block_ctxt(cx, "next");
2011 2012
    auto maybe_on_heap =
        cx.build.ICmp(lib::llvm::LLVMIntEQ, stack_len, C_int(0));
2013 2014 2015
    cx.build.CondBr(maybe_on_heap, maybe_on_heap_cx.llbb, next_cx.llbb);
    // Might be on the heap. Load the heap pointer and free it. (It's ok to
    // free a null pointer.)
2016 2017 2018 2019 2020 2021 2022 2023 2024

    auto stub_ptr =
        maybe_on_heap_cx.build.PointerCast(v0, T_ptr(T_ivec_heap(llunitty)));
    auto heap_ptr =
        {
            auto v = [C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)];
            auto m = maybe_on_heap_cx.build.InBoundsGEP(stub_ptr, v);
            maybe_on_heap_cx.build.Load(m)
        };
2025 2026 2027 2028 2029
    auto after_free_cx = trans_non_gc_free(maybe_on_heap_cx, heap_ptr).bcx;
    after_free_cx.build.Br(next_cx.llbb);
    ret res(next_cx, C_nil());
}

2030 2031
fn make_drop_glue(&@block_ctxt cx, ValueRef v0, &ty::t t) {
    // NB: v0 is an *alias* of type t here, not a direct value.
2032

2033 2034
    auto rslt;
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
2035 2036
        case (ty::ty_str) { rslt = decr_refcnt_maybe_free(cx, v0, v0, t); }
        case (ty::ty_vec(_)) { rslt = decr_refcnt_maybe_free(cx, v0, v0, t); }
2037 2038 2039 2040
        case (ty::ty_ivec(?tm)) {
            rslt = iter_structural_ty(cx, v0, t, drop_ty);
            rslt = maybe_free_ivec_heap_part(rslt.bcx, v0, tm.ty);
        }
2041
        case (ty::ty_box(_)) { rslt = decr_refcnt_maybe_free(cx, v0, v0, t); }
2042 2043 2044 2045 2046 2047
        case (ty::ty_port(_)) {
            rslt = decr_refcnt_maybe_free(cx, v0, v0, t);
        }
        case (ty::ty_chan(_)) {
            rslt = decr_refcnt_maybe_free(cx, v0, v0, t);
        }
2048
        case (ty::ty_task) { rslt = decr_refcnt_maybe_free(cx, v0, v0, t); }
2049 2050
        case (ty::ty_obj(_)) {
            auto box_cell =
2051
                cx.build.GEP(v0, [C_int(0), C_int(abi::obj_field_box)]);
2052 2053
            rslt = decr_refcnt_maybe_free(cx, box_cell, v0, t);
        }
2054
        case (ty::ty_fn(_, _, _, _, _)) {
2055
            auto box_cell =
2056
                cx.build.GEP(v0, [C_int(0), C_int(abi::fn_field_box)]);
2057
            rslt = decr_refcnt_maybe_free(cx, box_cell, v0, t);
2058
        }
2059
        case (_) {
2060
            if (ty::type_has_pointers(cx.fcx.lcx.ccx.tcx, t) &&
2061 2062 2063
                    ty::type_is_structural(cx.fcx.lcx.ccx.tcx, t)) {
                rslt = iter_structural_ty(cx, v0, t, bind drop_ty(_, _, _));
            } else { rslt = res(cx, C_nil()); }
2064 2065
        }
    }
2066
    rslt.bcx.build.RetVoid();
2067 2068
}

2069 2070
fn decr_refcnt_maybe_free(&@block_ctxt cx, ValueRef box_ptr_alias,
                          ValueRef full_alias, &ty::t t) -> result {
2071
    auto load_rc_cx = new_sub_block_ctxt(cx, "load rc");
2072
    auto rc_adj_cx = new_sub_block_ctxt(cx, "rc--");
2073
    auto free_cx = new_sub_block_ctxt(cx, "free");
2074
    auto next_cx = new_sub_block_ctxt(cx, "next");
2075
    auto box_ptr = cx.build.Load(box_ptr_alias);
2076 2077
    auto null_test = cx.build.IsNull(box_ptr);
    cx.build.CondBr(null_test, next_cx.llbb, load_rc_cx.llbb);
2078 2079 2080
    auto rc_ptr =
        load_rc_cx.build.GEP(box_ptr,
                             [C_int(0), C_int(abi::box_rc_field_refcnt)]);
2081 2082
    auto rc = load_rc_cx.build.Load(rc_ptr);
    auto const_test =
2083 2084
        load_rc_cx.build.ICmp(lib::llvm::LLVMIntEQ,
                              C_int(abi::const_refcount as int), rc);
2085
    load_rc_cx.build.CondBr(const_test, next_cx.llbb, rc_adj_cx.llbb);
2086 2087
    rc = rc_adj_cx.build.Sub(rc, C_int(1));
    rc_adj_cx.build.Store(rc, rc_ptr);
2088
    auto zero_test = rc_adj_cx.build.ICmp(lib::llvm::LLVMIntEQ, C_int(0), rc);
2089
    rc_adj_cx.build.CondBr(zero_test, free_cx.llbb, next_cx.llbb);
2090 2091
    auto free_res =
        free_ty(free_cx, load_if_immediate(free_cx, full_alias, t), t);
2092 2093 2094
    free_res.bcx.build.Br(next_cx.llbb);
    auto t_else = T_nil();
    auto v_else = C_nil();
2095 2096 2097 2098
    auto phi =
        next_cx.build.Phi(t_else, [v_else, v_else, v_else, free_res.val],
                          [cx.llbb, load_rc_cx.llbb, rc_adj_cx.llbb,
                           free_res.bcx.llbb]);
2099
    ret res(next_cx, phi);
2100 2101
}

2102

2103
// Structural comparison: a rather involved form of glue.
G
Graydon Hoare 已提交
2104
fn maybe_name_value(&@crate_ctxt cx, ValueRef v, &str s) {
2105
    if (cx.sess.get_opts().save_temps) {
2106
        llvm::LLVMSetValueName(v, str::buf(s));
2107 2108 2109
    }
}

2110
fn make_cmp_glue(&@block_ctxt cx, ValueRef lhs0, ValueRef rhs0, &ty::t t,
2111 2112 2113
                 ValueRef llop) {
    auto lhs = load_if_immediate(cx, lhs0, t);
    auto rhs = load_if_immediate(cx, rhs0, t);
2114
    if (ty::type_is_scalar(cx.fcx.lcx.ccx.tcx, t)) {
2115
        make_scalar_cmp_glue(cx, lhs, rhs, t, llop);
2116
    } else if (ty::type_is_box(cx.fcx.lcx.ccx.tcx, t)) {
2117 2118
        lhs = cx.build.GEP(lhs, [C_int(0), C_int(abi::box_rc_field_body)]);
        rhs = cx.build.GEP(rhs, [C_int(0), C_int(abi::box_rc_field_body)]);
2119 2120 2121 2122
        auto t_inner =
            alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
                case (ty::ty_box(?ti)) { ti.ty }
            };
2123
        auto rslt = call_cmp_glue(cx, lhs, rhs, t_inner, llop);
2124 2125
        rslt.bcx.build.Store(rslt.val, cx.fcx.llretptr);
        rslt.bcx.build.RetVoid();
2126 2127
    } else if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, t) ||
                   ty::type_is_sequence(cx.fcx.lcx.ccx.tcx, t)) {
2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138
        auto scx = new_sub_block_ctxt(cx, "structural compare start");
        auto next = new_sub_block_ctxt(cx, "structural compare end");
        cx.build.Br(scx.llbb);
        /*
         * We're doing lexicographic comparison here. We start with the
         * assumption that the two input elements are equal. Depending on
         * operator, this means that the result is either true or false;
         * equality produces 'true' for ==, <= and >=. It produces 'false' for
         * !=, < and >.
         *
         * We then move one element at a time through the structure checking
2139
         * for pairwise element equality: If we have equality, our assumption
2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155
         * about overall sequence equality is not modified, so we have to move
         * to the next element.
         *
         * If we do not have pairwise element equality, we have reached an
         * element that 'decides' the lexicographic comparison. So we exit the
         * loop with a flag that indicates the true/false sense of that
         * decision, by testing the element again with the operator we're
         * interested in.
         *
         * When we're lucky, LLVM should be able to fold some of these two
         * tests together (as they're applied to the same operands and in some
         * cases are sometimes redundant). But we don't bother trying to
         * optimize combinations like that, at this level.
         */

        auto flag = alloca(scx, T_i1());
2156
        maybe_name_value(cx.fcx.lcx.ccx, flag, "flag");
2157
        auto r;
2158
        if (ty::type_is_sequence(cx.fcx.lcx.ccx.tcx, t)) {
2159 2160
            // If we hit == all the way through the minimum-shared-length
            // section, default to judging the relative sequence lengths.
2161 2162 2163 2164

            r =
                compare_numerical_values(scx, vec_fill(scx, lhs),
                                         vec_fill(scx, rhs), unsigned_int,
2165
                                         llop);
2166 2167 2168 2169
            r.bcx.build.Store(r.val, flag);
        } else {
            // == and <= default to true if they find == all the way. <
            // defaults to false if it finds == all the way.
2170 2171 2172 2173

            auto result_if_equal =
                scx.build.ICmp(lib::llvm::LLVMIntNE, llop,
                               C_u8(abi::cmp_glue_op_lt));
2174 2175 2176
            scx.build.Store(result_if_equal, flag);
            r = res(scx, C_nil());
        }
2177 2178
        fn inner(@block_ctxt last_cx, bool load_inner, ValueRef flag,
                 ValueRef llop, &@block_ctxt cx, ValueRef av0, ValueRef bv0,
2179
                 ty::t t) -> result {
2180 2181 2182 2183 2184 2185 2186 2187 2188
            auto cnt_cx = new_sub_block_ctxt(cx, "continue_comparison");
            auto stop_cx = new_sub_block_ctxt(cx, "stop_comparison");
            auto av = av0;
            auto bv = bv0;
            if (load_inner) {
                // If `load_inner` is true, then the pointer type will always
                // be i8, because the data part of a vector always has type
                // i8[]. So we need to cast it to the proper type.

2189
                if (!ty::type_has_dynamic_size(last_cx.fcx.lcx.ccx.tcx, t)) {
2190 2191
                    auto llelemty =
                        T_ptr(type_of(last_cx.fcx.lcx.ccx, last_cx.sp, t));
2192 2193 2194 2195 2196 2197 2198 2199
                    av = cx.build.PointerCast(av, llelemty);
                    bv = cx.build.PointerCast(bv, llelemty);
                }
                av = load_if_immediate(cx, av, t);
                bv = load_if_immediate(cx, bv, t);
            }
            // First 'eq' comparison: if so, continue to next elts.

2200 2201 2202
            auto eq_r =
                call_cmp_glue(cx, av, bv, t, C_u8(abi::cmp_glue_op_eq));
            eq_r.bcx.build.CondBr(eq_r.val, cnt_cx.llbb, stop_cx.llbb);
2203
            // Second 'op' comparison: find out how this elt-pair decides.
2204

2205 2206 2207 2208 2209
            auto stop_r = call_cmp_glue(stop_cx, av, bv, t, llop);
            stop_r.bcx.build.Store(stop_r.val, flag);
            stop_r.bcx.build.Br(last_cx.llbb);
            ret res(cnt_cx, C_nil());
        }
2210
        if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, t)) {
2211 2212 2213 2214
            r =
                iter_structural_ty_full(r.bcx, lhs, rhs, t,
                                        bind inner(next, false, flag, llop, _,
                                                   _, _, _));
2215 2216 2217
        } else {
            auto lhs_p0 = vec_p0(r.bcx, lhs);
            auto rhs_p0 = vec_p0(r.bcx, rhs);
2218 2219
            auto min_len =
                umin(r.bcx, vec_fill(r.bcx, lhs), vec_fill(r.bcx, rhs));
2220
            auto rhs_lim = r.bcx.build.GEP(rhs_p0, [min_len]);
2221
            auto elt_ty = ty::sequence_element_type(cx.fcx.lcx.ccx.tcx, t);
2222
            r = size_of(r.bcx, elt_ty);
2223 2224 2225 2226
            r =
                iter_sequence_raw(r.bcx, lhs_p0, rhs_p0, rhs_lim, r.val,
                                  bind inner(next, true, flag, llop, _, _, _,
                                             elt_ty));
2227 2228 2229 2230 2231 2232 2233
        }
        r.bcx.build.Br(next.llbb);
        auto v = next.build.Load(flag);
        next.build.Store(v, cx.fcx.llretptr);
        next.build.RetVoid();
    } else {
        // FIXME: compare obj, fn by pointer?
2234

2235
        trans_fail(cx, none[common::span],
2236
                   "attempt to compare values of type " +
2237
                       ty_to_str(cx.fcx.lcx.ccx.tcx, t));
2238 2239 2240
    }
}

2241

2242
// Used only for creating scalar comparsion glue.
2243 2244
tag numerical_type { signed_int; unsigned_int; floating_point; }

2245

2246
// A helper function to create scalar comparison glue.
2247 2248
fn make_scalar_cmp_glue(&@block_ctxt cx, ValueRef lhs, ValueRef rhs, &ty::t t,
                        ValueRef llop) {
2249
    // assert ty::type_is_scalar(cx.fcx.lcx.ccx.tcx, t);
2250

2251 2252
    // In most cases, we need to know whether to do signed, unsigned, or float
    // comparison.
2253

2254
    auto f = bind make_numerical_cmp_glue(cx, lhs, rhs, _, llop);
2255

2256 2257 2258
    // FIXME: this could be a lot shorter if we could combine multiple cases
    // of alt expressions (issue #449).
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
2259
        case (ty::ty_nil) {
2260 2261 2262 2263 2264 2265 2266 2267
            cx.build.Store(C_bool(true), cx.fcx.llretptr);
            cx.build.RetVoid();
        }
        case (ty::ty_bool) { f(unsigned_int); }
        case (ty::ty_int) { f(signed_int); }
        case (ty::ty_float) { f(floating_point); }
        case (ty::ty_uint) { f(unsigned_int); }
        case (ty::ty_machine(_)) {
2268

2269 2270 2271
            // Floating point machine types
            if (ty::type_is_fp(cx.fcx.lcx.ccx.tcx, t)) {
                f(floating_point);
2272 2273 2274
            } else if (
             // Signed, integral machine types
             ty::type_is_signed(cx.fcx.lcx.ccx.tcx, t)) {
2275
                f(signed_int);
2276 2277 2278 2279
            } else 
             // Unsigned, integral machine types
             {
                f(unsigned_int);
2280 2281
            }
        }
2282 2283
        case (ty::ty_char) { f(unsigned_int); }
        case (ty::ty_type) {
2284 2285 2286 2287 2288 2289 2290 2291 2292
            trans_fail(cx, none[common::span],
                       "attempt to compare values of type type");
        }
        case (ty::ty_native) {
            trans_fail(cx, none[common::span],
                       "attempt to compare values of type native");
        }
        case (_) {
            // Should never get here, because t is scalar.
2293 2294 2295

            cx.fcx.lcx.ccx.sess.bug("non-scalar type passed to " +
                                        "make_scalar_cmp_glue");
2296
        }
2297 2298 2299
    }
}

2300

2301 2302 2303
// A helper function to compare numerical values.
fn compare_numerical_values(&@block_ctxt cx, ValueRef lhs, ValueRef rhs,
                            numerical_type nt, ValueRef llop) -> result {
2304 2305 2306
    auto eq_cmp;
    auto lt_cmp;
    auto le_cmp;
2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328
    alt (nt) {
        case (floating_point) {
            eq_cmp = lib::llvm::LLVMRealUEQ;
            lt_cmp = lib::llvm::LLVMRealULT;
            le_cmp = lib::llvm::LLVMRealULE;
        }
        case (signed_int) {
            eq_cmp = lib::llvm::LLVMIntEQ;
            lt_cmp = lib::llvm::LLVMIntSLT;
            le_cmp = lib::llvm::LLVMIntSLE;
        }
        case (unsigned_int) {
            eq_cmp = lib::llvm::LLVMIntEQ;
            lt_cmp = lib::llvm::LLVMIntULT;
            le_cmp = lib::llvm::LLVMIntULE;
        }
    }
    // FIXME: This wouldn't be necessary if we could bind methods off of
    // objects and therefore abstract over FCmp and ICmp (issue #435).  Then
    // we could just write, e.g., "cmp_fn = bind cx.build.FCmp(_, _, _);" in
    // the above, and "auto eq_result = cmp_fn(eq_cmp, lhs, rhs);" in the
    // below.
2329 2330 2331

    fn generic_cmp(&@block_ctxt cx, numerical_type nt, uint op, ValueRef lhs,
                   ValueRef rhs) -> ValueRef {
2332 2333 2334
        let ValueRef r;
        if (nt == floating_point) {
            r = cx.build.FCmp(op, lhs, rhs);
2335
        } else { r = cx.build.ICmp(op, lhs, rhs); }
2336
        ret r;
2337 2338 2339
    }
    auto last_cx = new_sub_block_ctxt(cx, "last");
    auto eq_cx = new_sub_block_ctxt(cx, "eq");
2340
    auto eq_result = generic_cmp(eq_cx, nt, eq_cmp, lhs, rhs);
2341 2342
    eq_cx.build.Br(last_cx.llbb);
    auto lt_cx = new_sub_block_ctxt(cx, "lt");
2343
    auto lt_result = generic_cmp(lt_cx, nt, lt_cmp, lhs, rhs);
2344 2345
    lt_cx.build.Br(last_cx.llbb);
    auto le_cx = new_sub_block_ctxt(cx, "le");
2346
    auto le_result = generic_cmp(le_cx, nt, le_cmp, lhs, rhs);
2347 2348 2349 2350
    le_cx.build.Br(last_cx.llbb);
    auto unreach_cx = new_sub_block_ctxt(cx, "unreach");
    unreach_cx.build.Unreachable();
    auto llswitch = cx.build.Switch(llop, unreach_cx.llbb, 3u);
2351 2352 2353
    llvm::LLVMAddCase(llswitch, C_u8(abi::cmp_glue_op_eq), eq_cx.llbb);
    llvm::LLVMAddCase(llswitch, C_u8(abi::cmp_glue_op_lt), lt_cx.llbb);
    llvm::LLVMAddCase(llswitch, C_u8(abi::cmp_glue_op_le), le_cx.llbb);
2354
    auto last_result =
2355 2356
        last_cx.build.Phi(T_i1(), [eq_result, lt_result, le_result],
                          [eq_cx.llbb, lt_cx.llbb, le_cx.llbb]);
2357 2358 2359
    ret res(last_cx, last_result);
}

2360

2361 2362
// A helper function to create numerical comparison glue.
fn make_numerical_cmp_glue(&@block_ctxt cx, ValueRef lhs, ValueRef rhs,
2363
                           numerical_type nt, ValueRef llop) {
2364
    auto r = compare_numerical_values(cx, lhs, rhs, nt, llop);
2365 2366
    r.bcx.build.Store(r.val, r.bcx.fcx.llretptr);
    r.bcx.build.RetVoid();
2367 2368
}

2369

2370 2371 2372
// Returns the length of an interior vector and a pointer to its first
// element, in that order.
fn get_ivec_len_and_data(&@block_ctxt bcx, ValueRef v, ty::t unit_ty) ->
2373
   tup(ValueRef, ValueRef, @block_ctxt) {
2374
    auto llunitty = type_of_or_i8(bcx, unit_ty);
2375 2376 2377 2378 2379 2380 2381 2382
    auto stack_len =
        bcx.build.Load(bcx.build.InBoundsGEP(v,
                                             [C_int(0),
                                              C_uint(abi::ivec_elt_len)]));
    auto stack_elem =
        bcx.build.InBoundsGEP(v,
                              [C_int(0), C_uint(abi::ivec_elt_elems),
                               C_int(0)]);
2383 2384 2385 2386
    auto on_heap = bcx.build.ICmp(lib::llvm::LLVMIntEQ, stack_len, C_int(0));
    auto on_heap_cx = new_sub_block_ctxt(bcx, "on_heap");
    auto next_cx = new_sub_block_ctxt(bcx, "next");
    bcx.build.CondBr(on_heap, on_heap_cx.llbb, next_cx.llbb);
2387 2388 2389 2390 2391 2392 2393
    auto heap_stub =
        on_heap_cx.build.PointerCast(v, T_ptr(T_ivec_heap(llunitty)));
    auto heap_ptr =
        {
            auto v = [C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)];
            on_heap_cx.build.Load(on_heap_cx.build.InBoundsGEP(heap_stub, v))
        };
2394 2395
    // Check whether the heap pointer is null. If it is, the vector length is
    // truly zero.
2396

2397 2398
    auto llstubty = T_ivec_heap(llunitty);
    auto llheapptrty = struct_elt(llstubty, abi::ivec_heap_stub_elt_ptr);
2399 2400 2401
    auto heap_ptr_is_null =
        on_heap_cx.build.ICmp(lib::llvm::LLVMIntEQ, heap_ptr,
                              C_null(T_ptr(llheapptrty)));
2402 2403 2404 2405 2406 2407
    auto zero_len_cx = new_sub_block_ctxt(bcx, "zero_len");
    auto nonzero_len_cx = new_sub_block_ctxt(bcx, "nonzero_len");
    on_heap_cx.build.CondBr(heap_ptr_is_null, zero_len_cx.llbb,
                            nonzero_len_cx.llbb);
    // Technically this context is unnecessary, but it makes this function
    // clearer.
2408

2409
    auto zero_len = C_int(0);
2410
    auto zero_elem = C_null(T_ptr(llunitty));
2411 2412
    zero_len_cx.build.Br(next_cx.llbb);
    // If we're here, then we actually have a heapified vector.
2413 2414 2415 2416 2417 2418 2419 2420

    auto heap_len =
        {
            auto v = [C_int(0), C_uint(abi::ivec_heap_elt_len)];
            auto m = nonzero_len_cx.build.InBoundsGEP(heap_ptr,v);
            nonzero_len_cx.build.Load(m)
        };
    auto heap_elem =
2421
        nonzero_len_cx.build.InBoundsGEP(heap_ptr,
2422 2423 2424
                                         [C_int(0),
                                          C_uint(abi::ivec_heap_elt_elems),
                                          C_int(0)]);
2425 2426 2427
    nonzero_len_cx.build.Br(next_cx.llbb);
    // Now we can figure out the length of `v` and get a pointer to its first
    // element.
2428 2429 2430 2431 2432 2433 2434

    auto len =
        next_cx.build.Phi(T_int(), [stack_len, zero_len, heap_len],
                          [bcx.llbb, zero_len_cx.llbb, nonzero_len_cx.llbb]);
    auto elem =
        next_cx.build.Phi(T_ptr(llunitty), [stack_elem, zero_elem, heap_elem],
                          [bcx.llbb, zero_len_cx.llbb, nonzero_len_cx.llbb]);
2435 2436 2437
    ret tup(len, elem, next_cx);
}

2438
type val_pair_fn = fn(&@block_ctxt, ValueRef, ValueRef) -> result ;
2439

2440
type val_and_ty_fn = fn(&@block_ctxt, ValueRef, ty::t) -> result ;
2441

2442
type val_pair_and_ty_fn =
2443 2444
    fn(&@block_ctxt, ValueRef, ValueRef, ty::t) -> result ;

2445

2446
// Iterates through the elements of a structural type.
2447 2448 2449
fn iter_structural_ty(&@block_ctxt cx, ValueRef v, &ty::t t, val_and_ty_fn f)
   -> result {
    fn adaptor_fn(val_and_ty_fn f, &@block_ctxt cx, ValueRef av, ValueRef bv,
2450
                  ty::t t) -> result {
2451 2452
        ret f(cx, av, t);
    }
2453
    be iter_structural_ty_full(cx, v, v, t, bind adaptor_fn(f, _, _, _, _));
2454 2455
}

2456 2457 2458
fn iter_structural_ty_full(&@block_ctxt cx, ValueRef av, ValueRef bv,
                           &ty::t t, &val_pair_and_ty_fn f) -> result {
    fn iter_boxpp(@block_ctxt cx, ValueRef box_a_cell, ValueRef box_b_cell,
G
Graydon Hoare 已提交
2459
                  &val_pair_and_ty_fn f) -> result {
2460 2461
        auto box_a_ptr = cx.build.Load(box_a_cell);
        auto box_b_ptr = cx.build.Load(box_b_cell);
2462 2463
        auto tnil = ty::mk_nil(cx.fcx.lcx.ccx.tcx);
        auto tbox = ty::mk_imm_box(cx.fcx.lcx.ccx.tcx, tnil);
2464 2465
        auto inner_cx = new_sub_block_ctxt(cx, "iter box");
        auto next_cx = new_sub_block_ctxt(cx, "next");
2466
        auto null_test = cx.build.IsNull(box_a_ptr);
2467
        cx.build.CondBr(null_test, next_cx.llbb, inner_cx.llbb);
2468
        auto r = f(inner_cx, box_a_ptr, box_b_ptr, tbox);
2469
        r.bcx.build.Br(next_cx.llbb);
2470
        ret res(next_cx, C_nil());
2471
    }
2472
    fn iter_ivec(@block_ctxt bcx, ValueRef av, ValueRef bv, ty::t unit_ty,
2473 2474
                 &val_pair_and_ty_fn f) -> result {
        // FIXME: "unimplemented rebinding existing function" workaround
2475

2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492
        fn adapter(&@block_ctxt bcx, ValueRef av, ValueRef bv, ty::t unit_ty,
                   val_pair_and_ty_fn f) -> result {
            ret f(bcx, av, bv, unit_ty);
        }
        auto llunitty = type_of_or_i8(bcx, unit_ty);
        auto rslt = size_of(bcx, unit_ty);
        auto unit_sz = rslt.val;
        bcx = rslt.bcx;
        auto a_len_and_data = get_ivec_len_and_data(bcx, av, unit_ty);
        auto a_len = a_len_and_data._0;
        auto a_elem = a_len_and_data._1;
        bcx = a_len_and_data._2;
        auto b_len_and_data = get_ivec_len_and_data(bcx, bv, unit_ty);
        auto b_len = b_len_and_data._0;
        auto b_elem = b_len_and_data._1;
        bcx = b_len_and_data._2;
        // Calculate the last pointer address we want to handle.
2493 2494
        // TODO: Optimize this when the size of the unit type is statically
        // known to not use pointer casts, which tend to confuse LLVM.
2495

2496 2497 2498 2499 2500
        auto len = umin(bcx, a_len, b_len);
        auto b_elem_i8 = bcx.build.PointerCast(b_elem, T_ptr(T_i8()));
        auto b_end_i8 = bcx.build.GEP(b_elem_i8, [len]);
        auto b_end = bcx.build.PointerCast(b_end_i8, T_ptr(llunitty));
        // Now perform the iteration.
2501

2502 2503 2504 2505
        auto vpf = bind adapter(_, _, _, unit_ty, f);
        ret iter_sequence_raw(bcx, a_elem, b_elem, b_end, unit_sz, vpf);
    }
    let result r = res(cx, C_nil());
2506 2507
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
        case (ty::ty_tup(?args)) {
2508
            let int i = 0;
2509
            for (ty::mt arg in args) {
2510
                r = GEP_tup_like(r.bcx, t, av, [0, i]);
2511
                auto elt_a = r.val;
2512
                r = GEP_tup_like(r.bcx, t, bv, [0, i]);
2513
                auto elt_b = r.val;
2514 2515 2516
                r =
                    f(r.bcx, load_if_immediate(r.bcx, elt_a, arg.ty),
                      load_if_immediate(r.bcx, elt_b, arg.ty), arg.ty);
2517 2518 2519
                i += 1;
            }
        }
2520
        case (ty::ty_rec(?fields)) {
2521
            let int i = 0;
2522
            for (ty::field fld in fields) {
2523
                r = GEP_tup_like(r.bcx, t, av, [0, i]);
2524
                auto llfld_a = r.val;
2525
                r = GEP_tup_like(r.bcx, t, bv, [0, i]);
2526
                auto llfld_b = r.val;
2527 2528
                r =
                    f(r.bcx, load_if_immediate(r.bcx, llfld_a, fld.mt.ty),
2529
                      load_if_immediate(r.bcx, llfld_b, fld.mt.ty),
2530
                      fld.mt.ty);
2531 2532 2533
                i += 1;
            }
        }
2534
        case (ty::ty_tag(?tid, ?tps)) {
2535 2536
            auto variants = ty::tag_variants(cx.fcx.lcx.ccx.tcx, tid);
            auto n_variants = vec::len[ty::variant_info](variants);
2537
            // Cast the tags to types we can GEP into.
2538

2539
            auto lltagty = T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn);
2540 2541
            auto av_tag = cx.build.PointerCast(av, lltagty);
            auto bv_tag = cx.build.PointerCast(bv, lltagty);
2542 2543
            auto lldiscrim_a_ptr = cx.build.GEP(av_tag, [C_int(0), C_int(0)]);
            auto llunion_a_ptr = cx.build.GEP(av_tag, [C_int(0), C_int(1)]);
2544
            auto lldiscrim_a = cx.build.Load(lldiscrim_a_ptr);
2545 2546
            auto lldiscrim_b_ptr = cx.build.GEP(bv_tag, [C_int(0), C_int(0)]);
            auto llunion_b_ptr = cx.build.GEP(bv_tag, [C_int(0), C_int(1)]);
2547
            auto lldiscrim_b = cx.build.Load(lldiscrim_b_ptr);
2548 2549 2550
            // NB: we must hit the discriminant first so that structural
            // comparison know not to proceed when the discriminants differ.

2551 2552 2553 2554
            auto bcx = cx;
            bcx =
                f(bcx, lldiscrim_a, lldiscrim_b,
                  ty::mk_int(cx.fcx.lcx.ccx.tcx)).bcx;
2555
            auto unr_cx = new_sub_block_ctxt(bcx, "tag-iter-unr");
2556
            unr_cx.build.Unreachable();
2557 2558
            auto llswitch =
                bcx.build.Switch(lldiscrim_a, unr_cx.llbb, n_variants);
2559
            auto next_cx = new_sub_block_ctxt(bcx, "tag-iter-next");
2560
            auto i = 0u;
2561
            for (ty::variant_info variant in variants) {
2562 2563 2564 2565
                auto variant_cx =
                    new_sub_block_ctxt(bcx,
                                       "tag-iter-variant-" +
                                           uint::to_str(i, 10u));
2566
                llvm::LLVMAddCase(llswitch, C_int(i as int), variant_cx.llbb);
2567
                if (vec::len[ty::t](variant.args) > 0u) {
2568
                    // N-ary variant.
2569

2570
                    auto fn_ty = variant.ctor_ty;
2571
                    alt (ty::struct(bcx.fcx.lcx.ccx.tcx, fn_ty)) {
2572
                        case (ty::ty_fn(_, ?args, _, _, _)) {
2573
                            auto j = 0;
2574
                            for (ty::arg a in args) {
2575
                                auto v = [C_int(0), C_int(j as int)];
2576 2577 2578
                                auto rslt =
                                    GEP_tag(variant_cx, llunion_a_ptr, tid,
                                            variant.id, tps, j);
2579 2580
                                auto llfldp_a = rslt.val;
                                variant_cx = rslt.bcx;
2581 2582 2583
                                rslt =
                                    GEP_tag(variant_cx, llunion_b_ptr, tid,
                                            variant.id, tps, j);
2584 2585
                                auto llfldp_b = rslt.val;
                                variant_cx = rslt.bcx;
2586 2587 2588 2589
                                auto tcx = cx.fcx.lcx.ccx.tcx;
                                auto ty_subst =
                                    ty::substitute_type_params(tcx,
                                                               tps, a.ty);
2590
                                auto llfld_a =
2591 2592
                                    load_if_immediate(variant_cx, llfldp_a,
                                                      ty_subst);
2593
                                auto llfld_b =
2594 2595 2596 2597
                                    load_if_immediate(variant_cx, llfldp_b,
                                                      ty_subst);
                                auto res =
                                    f(variant_cx, llfld_a, llfld_b, ty_subst);
2598
                                variant_cx = res.bcx;
2599
                                j += 1;
2600 2601
                            }
                        }
2602
                    }
2603 2604 2605
                    variant_cx.build.Br(next_cx.llbb);
                } else {
                    // Nullary variant; nothing to do.
2606

2607
                    variant_cx.build.Br(next_cx.llbb);
2608 2609 2610 2611 2612
                }
                i += 1u;
            }
            ret res(next_cx, C_nil());
        }
2613
        case (ty::ty_fn(_, _, _, _, _)) {
2614
            auto box_cell_a =
2615
                cx.build.GEP(av, [C_int(0), C_int(abi::fn_field_box)]);
2616
            auto box_cell_b =
2617
                cx.build.GEP(bv, [C_int(0), C_int(abi::fn_field_box)]);
2618
            ret iter_boxpp(cx, box_cell_a, box_cell_b, f);
2619
        }
2620
        case (ty::ty_obj(_)) {
2621
            auto box_cell_a =
2622
                cx.build.GEP(av, [C_int(0), C_int(abi::obj_field_box)]);
2623
            auto box_cell_b =
2624
                cx.build.GEP(bv, [C_int(0), C_int(abi::obj_field_box)]);
2625
            ret iter_boxpp(cx, box_cell_a, box_cell_b, f);
2626
        }
2627 2628 2629 2630 2631 2632 2633
        case (ty::ty_ivec(?unit_tm)) {
            ret iter_ivec(cx, av, bv, unit_tm.ty, f);
        }
        case (ty::ty_istr) {
            auto unit_ty = ty::mk_mach(cx.fcx.lcx.ccx.tcx, common::ty_u8);
            ret iter_ivec(cx, av, bv, unit_ty, f);
        }
2634
        case (_) {
2635
            cx.fcx.lcx.ccx.sess.unimpl("type in iter_structural_ty_full");
2636
        }
2637
    }
2638
    ret r;
2639 2640
}

2641

2642 2643 2644 2645 2646 2647 2648 2649
// Iterates through a pointer range, until the src* hits the src_lim*.
fn iter_sequence_raw(@block_ctxt cx, ValueRef dst,
                      // elt*
                         ValueRef src,
                      // elt*
                         ValueRef src_lim,
                      // elt*
                         ValueRef elt_sz, &val_pair_fn f) -> result {
2650
    auto bcx = cx;
2651
    let ValueRef dst_int = vp2i(bcx, dst);
2652 2653 2654 2655 2656 2657
    let ValueRef src_int = vp2i(bcx, src);
    let ValueRef src_lim_int = vp2i(bcx, src_lim);
    auto cond_cx = new_scope_block_ctxt(cx, "sequence-iter cond");
    auto body_cx = new_scope_block_ctxt(cx, "sequence-iter body");
    auto next_cx = new_sub_block_ctxt(cx, "next");
    bcx.build.Br(cond_cx.llbb);
2658 2659 2660 2661
    let ValueRef dst_curr = cond_cx.build.Phi(T_int(), [dst_int], [bcx.llbb]);
    let ValueRef src_curr = cond_cx.build.Phi(T_int(), [src_int], [bcx.llbb]);
    auto end_test =
        cond_cx.build.ICmp(lib::llvm::LLVMIntULT, src_curr, src_lim_int);
2662
    cond_cx.build.CondBr(end_test, body_cx.llbb, next_cx.llbb);
2663
    auto dst_curr_ptr = vi2p(body_cx, dst_curr, T_ptr(T_i8()));
2664
    auto src_curr_ptr = vi2p(body_cx, src_curr, T_ptr(T_i8()));
2665
    auto body_res = f(body_cx, dst_curr_ptr, src_curr_ptr);
2666
    body_cx = body_res.bcx;
2667
    auto dst_next = body_cx.build.Add(dst_curr, elt_sz);
2668
    auto src_next = body_cx.build.Add(src_curr, elt_sz);
2669
    body_cx.build.Br(cond_cx.llbb);
2670 2671
    cond_cx.build.AddIncomingToPhi(dst_curr, [dst_next], [body_cx.llbb]);
    cond_cx.build.AddIncomingToPhi(src_curr, [src_next], [body_cx.llbb]);
2672 2673 2674
    ret res(next_cx, C_nil());
}

2675 2676 2677 2678 2679 2680 2681
fn iter_sequence_inner(&@block_ctxt cx, ValueRef src,
                        // elt*
                           ValueRef src_lim,
                       & // elt*
                           ty::t elt_ty, &val_and_ty_fn f) -> result {
    fn adaptor_fn(val_and_ty_fn f, ty::t elt_ty, &@block_ctxt cx,
                  ValueRef dst, ValueRef src) -> result {
2682
        auto llptrty;
2683
        if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, elt_ty)) {
2684
            auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, elt_ty);
2685
            llptrty = T_ptr(llty);
2686
        } else { llptrty = T_ptr(T_ptr(T_i8())); }
2687
        auto p = cx.build.PointerCast(src, llptrty);
2688
        ret f(cx, load_if_immediate(cx, p, elt_ty), elt_ty);
2689
    }
2690
    auto elt_sz = size_of(cx, elt_ty);
2691 2692
    be iter_sequence_raw(elt_sz.bcx, src, src, src_lim, elt_sz.val,
                         bind adaptor_fn(f, elt_ty, _, _, _));
2693 2694 2695
}


2696
// Iterates through the elements of a vec or str.
2697 2698 2699 2700 2701 2702
fn iter_sequence(@block_ctxt cx, ValueRef v, &ty::t t, &val_and_ty_fn f) ->
   result {
    fn iter_sequence_body(@block_ctxt cx, ValueRef v, &ty::t elt_ty,
                          &val_and_ty_fn f, bool trailing_null) -> result {
        auto p0 = cx.build.GEP(v, [C_int(0), C_int(abi::vec_elt_data)]);
        auto lenptr = cx.build.GEP(v, [C_int(0), C_int(abi::vec_elt_fill)]);
2703
        auto llunit_ty;
2704
        if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, elt_ty)) {
2705
            llunit_ty = T_i8();
2706
        } else { llunit_ty = type_of(cx.fcx.lcx.ccx, cx.sp, elt_ty); }
2707 2708
        auto bcx = cx;
        auto len = bcx.build.Load(lenptr);
2709
        if (trailing_null) {
2710 2711
            auto unit_sz = size_of(bcx, elt_ty);
            bcx = unit_sz.bcx;
2712
            len = bcx.build.Sub(len, unit_sz.val);
2713
        }
2714 2715
        auto p1 =
            vi2p(bcx, bcx.build.Add(vp2i(bcx, p0), len), T_ptr(llunit_ty));
2716
        ret iter_sequence_inner(bcx, p0, p1, elt_ty, f);
2717
    }
2718 2719
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
        case (ty::ty_vec(?elt)) {
2720
            ret iter_sequence_body(cx, v, elt.ty, f, false);
2721
        }
2722 2723
        case (ty::ty_str) {
            auto et = ty::mk_mach(cx.fcx.lcx.ccx.tcx, common::ty_u8);
2724
            ret iter_sequence_body(cx, v, et, f, true);
2725
        }
2726 2727
        case (_) {
            cx.fcx.lcx.ccx.sess.bug("unexpected type in " +
2728 2729
                                        "trans::iter_sequence: " +
                                        ty_to_str(cx.fcx.lcx.ccx.tcx, t));
2730
        }
2731
    }
2732 2733
}

2734 2735 2736 2737
fn lazily_emit_all_tydesc_glue(&@block_ctxt cx,
                               &option::t[@tydesc_info] static_ti) {
    lazily_emit_tydesc_glue(cx, abi::tydesc_field_take_glue, static_ti);
    lazily_emit_tydesc_glue(cx, abi::tydesc_field_drop_glue, static_ti);
2738
    lazily_emit_tydesc_glue(cx, abi::tydesc_field_free_glue, static_ti);
2739 2740 2741 2742 2743
    lazily_emit_tydesc_glue(cx, abi::tydesc_field_cmp_glue, static_ti);
}

fn lazily_emit_all_generic_info_tydesc_glues(&@block_ctxt cx,
                                             &generic_info gi) {
2744
    for (option::t[@tydesc_info] ti in gi.static_tis) {
2745 2746 2747 2748 2749 2750 2751
        lazily_emit_all_tydesc_glue(cx, ti);
    }
}

fn lazily_emit_tydesc_glue(&@block_ctxt cx, int field,
                           &option::t[@tydesc_info] static_ti) {
    alt (static_ti) {
2752 2753
        case (none) { }
        case (some(?ti)) {
2754 2755 2756
            if (field == abi::tydesc_field_take_glue) {
                alt ({ ti.take_glue }) {
                    case (some(_)) { }
2757
                    case (none) {
2758
                        log #fmt("+++ lazily_emit_tydesc_glue TAKE %s",
2759
                                 ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
2760 2761 2762 2763 2764 2765 2766
                        auto lcx = cx.fcx.lcx;
                        auto glue_fn =
                            declare_generic_glue(lcx, ti.ty,
                                                 T_glue_fn(lcx.ccx.tn),
                                                 "take");
                        ti.take_glue = some[ValueRef](glue_fn);
                        auto tg = make_take_glue;
2767
                        make_generic_glue(lcx, cx.sp, ti.ty, glue_fn,
2768 2769
                                          mgghf_single(tg), ti.ty_params);
                        log #fmt("--- lazily_emit_tydesc_glue TAKE %s",
2770
                                 ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
2771 2772
                    }
                }
2773 2774
            } else if (field == abi::tydesc_field_drop_glue) {
                alt ({ ti.drop_glue }) {
2775 2776
                    case (some(_)) { }
                    case (none) {
2777
                        log #fmt("+++ lazily_emit_tydesc_glue DROP %s",
2778
                                 ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
2779 2780 2781 2782 2783 2784 2785
                        auto lcx = cx.fcx.lcx;
                        auto glue_fn =
                            declare_generic_glue(lcx, ti.ty,
                                                 T_glue_fn(lcx.ccx.tn),
                                                 "drop");
                        ti.drop_glue = some[ValueRef](glue_fn);
                        auto dg = make_drop_glue;
2786
                        make_generic_glue(lcx, cx.sp, ti.ty, glue_fn,
2787 2788
                                          mgghf_single(dg), ti.ty_params);
                        log #fmt("--- lazily_emit_tydesc_glue DROP %s",
2789
                                 ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
2790 2791
                    }
                }
2792 2793
            } else if (field == abi::tydesc_field_free_glue) {
                alt ({ ti.free_glue }) {
2794 2795
                    case (some(_)) { }
                    case (none) {
2796
                        log #fmt("+++ lazily_emit_tydesc_glue FREE %s",
2797
                                 ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
2798 2799 2800 2801 2802 2803 2804
                        auto lcx = cx.fcx.lcx;
                        auto glue_fn =
                            declare_generic_glue(lcx, ti.ty,
                                                 T_glue_fn(lcx.ccx.tn),
                                                 "free");
                        ti.free_glue = some[ValueRef](glue_fn);
                        auto dg = make_free_glue;
T
Tim Chevalier 已提交
2805
                        make_generic_glue(lcx, cx.sp, ti.ty, glue_fn,
2806 2807
                                          mgghf_single(dg), ti.ty_params);
                        log #fmt("--- lazily_emit_tydesc_glue FREE %s",
2808
                                 ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
2809 2810
                    }
                }
2811
            } else if (field == abi::tydesc_field_cmp_glue) {
2812
                alt ({ ti.cmp_glue }) {
2813 2814
                    case (some(_)) { }
                    case (none) {
2815
                        log #fmt("+++ lazily_emit_tydesc_glue CMP %s",
2816
                                 ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
2817 2818 2819 2820 2821 2822
                        auto lcx = cx.fcx.lcx;
                        auto glue_fn =
                            declare_generic_glue(lcx, ti.ty,
                                                 T_cmp_glue_fn(lcx.ccx.tn),
                                                 "cmp");
                        ti.cmp_glue = some[ValueRef](glue_fn);
2823
                        make_generic_glue(lcx, cx.sp, ti.ty, glue_fn,
2824 2825
                                          mgghf_cmp, ti.ty_params);
                        log #fmt("--- lazily_emit_tydesc_glue CMP %s",
2826
                                 ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
2827 2828 2829 2830 2831 2832 2833
                    }
                }
            }
        }
    }
}

2834 2835
fn call_tydesc_glue_full(&@block_ctxt cx, ValueRef v, ValueRef tydesc,
                         int field, &option::t[@tydesc_info] static_ti) {
2836
    lazily_emit_tydesc_glue(cx, field, static_ti);
2837
    auto llrawptr = cx.build.BitCast(v, T_ptr(T_i8()));
2838 2839 2840
    auto lltydescs =
        cx.build.GEP(tydesc,
                     [C_int(0), C_int(abi::tydesc_field_first_param)]);
2841
    lltydescs = cx.build.Load(lltydescs);
2842
    auto llfnptr = cx.build.GEP(tydesc, [C_int(0), C_int(field)]);
2843
    auto llfn = cx.build.Load(llfnptr);
2844 2845 2846
    cx.build.Call(llfn,
                  [C_null(T_ptr(T_nil())), cx.fcx.lltaskptr,
                   C_null(T_ptr(T_nil())), lltydescs, llrawptr]);
2847 2848
}

2849 2850
fn call_tydesc_glue(&@block_ctxt cx, ValueRef v, &ty::t t, int field) ->
   result {
2851
    let option::t[@tydesc_info] ti = none[@tydesc_info];
2852
    auto td = get_tydesc(cx, t, false, ti);
2853 2854
    call_tydesc_glue_full(td.bcx, spill_if_immediate(td.bcx, v, t), td.val,
                          field, ti);
2855
    ret res(td.bcx, C_nil());
2856 2857
}

G
Graydon Hoare 已提交
2858
fn maybe_call_dtor(&@block_ctxt cx, ValueRef v) -> @block_ctxt {
2859
    auto vtbl = cx.build.GEP(v, [C_int(0), C_int(abi::obj_field_vtbl)]);
2860
    vtbl = cx.build.Load(vtbl);
2861
    auto dtor_ptr = cx.build.GEP(vtbl, [C_int(0), C_int(0)]);
2862
    dtor_ptr = cx.build.Load(dtor_ptr);
2863
    auto self_t = llvm::LLVMGetElementType(val_ty(v));
2864 2865 2866
    dtor_ptr =
        cx.build.BitCast(dtor_ptr,
                         T_ptr(T_dtor(cx.fcx.lcx.ccx, cx.sp, self_t)));
2867 2868
    auto dtor_cx = new_sub_block_ctxt(cx, "dtor");
    auto after_cx = new_sub_block_ctxt(cx, "after_dtor");
2869 2870 2871
    auto test =
        cx.build.ICmp(lib::llvm::LLVMIntNE, dtor_ptr,
                      C_null(val_ty(dtor_ptr)));
2872
    cx.build.CondBr(test, dtor_cx.llbb, after_cx.llbb);
M
Marijn Haverbeke 已提交
2873
    auto me = dtor_cx.build.Load(v);
2874 2875
    dtor_cx.build.FastCall(dtor_ptr,
                           [C_null(T_ptr(T_nil())), cx.fcx.lltaskptr, me]);
2876 2877 2878 2879
    dtor_cx.build.Br(after_cx.llbb);
    ret after_cx;
}

2880
fn call_cmp_glue(&@block_ctxt cx, ValueRef lhs, ValueRef rhs, &ty::t t,
2881 2882 2883 2884 2885 2886 2887 2888
                 ValueRef llop) -> result {
    // We can't use call_tydesc_glue_full() and friends here because compare
    // glue has a special signature.

    auto lllhs = spill_if_immediate(cx, lhs, t);
    auto llrhs = spill_if_immediate(cx, rhs, t);
    auto llrawlhsptr = cx.build.BitCast(lllhs, T_ptr(T_i8()));
    auto llrawrhsptr = cx.build.BitCast(llrhs, T_ptr(T_i8()));
2889 2890 2891
    auto ti = none[@tydesc_info];
    auto r = get_tydesc(cx, t, false, ti);
    lazily_emit_tydesc_glue(cx, abi::tydesc_field_cmp_glue, ti);
2892
    auto lltydescs =
2893 2894
        r.bcx.build.GEP(r.val,
                        [C_int(0), C_int(abi::tydesc_field_first_param)]);
2895 2896
    lltydescs = r.bcx.build.Load(lltydescs);
    auto llfnptr =
2897
        r.bcx.build.GEP(r.val, [C_int(0), C_int(abi::tydesc_field_cmp_glue)]);
2898 2899
    auto llfn = r.bcx.build.Load(llfnptr);
    auto llcmpresultptr = r.bcx.build.Alloca(T_i1());
2900 2901 2902
    let vec[ValueRef] llargs =
        [llcmpresultptr, r.bcx.fcx.lltaskptr, C_null(T_ptr(T_nil())),
         lltydescs, llrawlhsptr, llrawrhsptr, llop];
2903
    r.bcx.build.Call(llfn, llargs);
2904 2905 2906
    ret res(r.bcx, r.bcx.build.Load(llcmpresultptr));
}

2907
fn take_ty(&@block_ctxt cx, ValueRef v, ty::t t) -> result {
2908
    if (ty::type_has_pointers(cx.fcx.lcx.ccx.tcx, t)) {
2909
        ret call_tydesc_glue(cx, v, t, abi::tydesc_field_take_glue);
2910
    }
2911
    ret res(cx, C_nil());
2912 2913
}

2914
fn drop_slot(&@block_ctxt cx, ValueRef slot, &ty::t t) -> result {
2915
    auto llptr = load_if_immediate(cx, slot, t);
2916 2917
    auto re = drop_ty(cx, llptr, t);
    auto llty = val_ty(slot);
2918
    auto llelemty = lib::llvm::llvm::LLVMGetElementType(llty);
2919 2920
    re.bcx.build.Store(C_null(llelemty), slot);
    ret re;
2921 2922
}

2923
fn drop_ty(&@block_ctxt cx, ValueRef v, ty::t t) -> result {
2924
    if (ty::type_has_pointers(cx.fcx.lcx.ccx.tcx, t)) {
2925
        ret call_tydesc_glue(cx, v, t, abi::tydesc_field_drop_glue);
2926
    }
2927
    ret res(cx, C_nil());
2928 2929
}

2930
fn free_ty(&@block_ctxt cx, ValueRef v, ty::t t) -> result {
2931
    if (ty::type_has_pointers(cx.fcx.lcx.ccx.tcx, t)) {
2932
        ret call_tydesc_glue(cx, v, t, abi::tydesc_field_free_glue);
2933 2934 2935 2936
    }
    ret res(cx, C_nil());
}

2937
fn call_memmove(&@block_ctxt cx, ValueRef dst, ValueRef src, ValueRef n_bytes,
G
Graydon Hoare 已提交
2938
                ValueRef align_bytes) -> result {
2939
    // FIXME: switch to the 64-bit variant when on such a platform.
2940

2941
    auto i = cx.fcx.lcx.ccx.intrinsics;
2942 2943
    assert (i.contains_key("llvm.memmove.p0i8.p0i8.i32"));
    auto memmove = i.get("llvm.memmove.p0i8.p0i8.i32");
2944 2945
    auto src_ptr = cx.build.PointerCast(src, T_ptr(T_i8()));
    auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
2946 2947
    auto size = cx.build.IntCast(n_bytes, T_i32());
    auto align =
2948 2949 2950
        if (lib::llvm::llvm::LLVMIsConstant(align_bytes) == True) {
            cx.build.IntCast(align_bytes, T_i32())
        } else { cx.build.IntCast(C_int(0), T_i32()) };
2951
    auto volatile = C_bool(false);
2952 2953 2954
    ret res(cx,
            cx.build.Call(memmove,
                          [dst_ptr, src_ptr, size, align, volatile]));
2955 2956
}

2957
fn call_bzero(&@block_ctxt cx, ValueRef dst, ValueRef n_bytes,
2958 2959
              ValueRef align_bytes) -> result {
    // FIXME: switch to the 64-bit variant when on such a platform.
2960

2961 2962 2963
    auto i = cx.fcx.lcx.ccx.intrinsics;
    assert (i.contains_key("llvm.memset.p0i8.i32"));
    auto memset = i.get("llvm.memset.p0i8.i32");
2964
    auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
2965 2966
    auto size = cx.build.IntCast(n_bytes, T_i32());
    auto align =
2967 2968 2969
        if (lib::llvm::llvm::LLVMIsConstant(align_bytes) == True) {
            cx.build.IntCast(align_bytes, T_i32())
        } else { cx.build.IntCast(C_int(0), T_i32()) };
2970
    auto volatile = C_bool(false);
2971 2972 2973
    ret res(cx,
            cx.build.Call(memset,
                          [dst_ptr, C_u8(0u), size, align, volatile]));
2974 2975
}

2976 2977
fn memmove_ty(&@block_ctxt cx, ValueRef dst, ValueRef src, &ty::t t) ->
   result {
2978
    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
2979 2980
        auto llsz = size_of(cx, t);
        auto llalign = align_of(llsz.bcx, t);
2981
        ret call_memmove(llalign.bcx, dst, src, llsz.val, llalign.val);
2982
    } else { ret res(cx, cx.build.Store(cx.build.Load(src), dst)); }
2983 2984
}

2985
tag copy_action { INIT; DROP_EXISTING; }
2986

2987 2988
fn copy_val(&@block_ctxt cx, copy_action action, ValueRef dst, ValueRef src,
            &ty::t t) -> result {
2989 2990
    if (ty::type_is_scalar(cx.fcx.lcx.ccx.tcx, t) ||
            ty::type_is_native(cx.fcx.lcx.ccx.tcx, t)) {
2991
        ret res(cx, cx.build.Store(src, dst));
2992
    } else if (ty::type_is_nil(cx.fcx.lcx.ccx.tcx, t) ||
2993
                   ty::type_is_bot(cx.fcx.lcx.ccx.tcx, t)) {
2994
        ret res(cx, C_nil());
2995
    } else if (ty::type_is_boxed(cx.fcx.lcx.ccx.tcx, t)) {
2996
        auto r = take_ty(cx, src, t);
2997
        if (action == DROP_EXISTING) {
2998
            r = drop_ty(r.bcx, r.bcx.build.Load(dst), t);
2999 3000
        }
        ret res(r.bcx, r.bcx.build.Store(src, dst));
3001
    } else if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, t) ||
3002
                   ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
3003
        auto r = take_ty(cx, src, t);
3004
        if (action == DROP_EXISTING) { r = drop_ty(r.bcx, dst, t); }
3005
        ret memmove_ty(r.bcx, dst, src, t);
3006
    }
3007
    cx.fcx.lcx.ccx.sess.bug("unexpected type in trans::copy_val: " +
3008
                                ty_to_str(cx.fcx.lcx.ccx.tcx, t));
3009 3010
}

3011

M
Michael Sullivan 已提交
3012 3013 3014 3015 3016
// This works like copy_val, except that it deinitializes the source.
// Since it needs to zero out the source, src also needs to be an lval.
// FIXME: We always zero out the source. Ideally we would detect the
// case where a variable is always deinitialized by block exit and thus
// doesn't need to be dropped.
3017
fn move_val(@block_ctxt cx, copy_action action, ValueRef dst, ValueRef src,
3018
            &ty::t t) -> result {
M
Michael Sullivan 已提交
3019 3020 3021 3022
    if (ty::type_is_scalar(cx.fcx.lcx.ccx.tcx, t) ||
            ty::type_is_native(cx.fcx.lcx.ccx.tcx, t)) {
        ret res(cx, cx.build.Store(src, dst));
    } else if (ty::type_is_nil(cx.fcx.lcx.ccx.tcx, t) ||
3023
                   ty::type_is_bot(cx.fcx.lcx.ccx.tcx, t)) {
M
Michael Sullivan 已提交
3024 3025 3026 3027 3028 3029 3030 3031
        ret res(cx, C_nil());
    } else if (ty::type_is_boxed(cx.fcx.lcx.ccx.tcx, t)) {
        if (action == DROP_EXISTING) {
            cx = drop_ty(cx, cx.build.Load(dst), t).bcx;
        }
        auto r = res(cx, cx.build.Store(cx.build.Load(src), dst));
        ret zero_alloca(r.bcx, src, t);
    } else if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, t) ||
3032 3033
                   ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
        if (action == DROP_EXISTING) { cx = drop_ty(cx, dst, t).bcx; }
M
Michael Sullivan 已提交
3034 3035 3036 3037
        auto r = memmove_ty(cx, dst, cx.build.Load(src), t);
        ret zero_alloca(r.bcx, src, t);
    }
    cx.fcx.lcx.ccx.sess.bug("unexpected type in trans::move_val: " +
3038
                                ty_to_str(cx.fcx.lcx.ccx.tcx, t));
M
Michael Sullivan 已提交
3039 3040
}

3041
fn trans_lit(&@crate_ctxt cx, &ast::lit lit, &ast::ann ann) -> ValueRef {
3042
    alt (lit.node) {
3043 3044
        case (ast::lit_int(?i)) { ret C_int(i); }
        case (ast::lit_uint(?u)) { ret C_int(u as int); }
3045
        case (ast::lit_mach_int(?tm, ?i)) {
3046 3047 3048
            // 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.
3049

3050
            auto t = T_int();
3051
            auto s = True;
3052
            alt (tm) {
3053 3054 3055 3056 3057 3058 3059 3060
                case (common::ty_u8) { t = T_i8(); s = False; }
                case (common::ty_u16) { t = T_i16(); s = False; }
                case (common::ty_u32) { t = T_i32(); s = False; }
                case (common::ty_u64) { t = T_i64(); s = False; }
                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(); }
3061
            }
3062
            ret C_integral(t, i as uint, s);
3063
        }
3064 3065
        case (ast::lit_float(?fs)) { ret C_float(fs); }
        case (ast::lit_mach_float(?tm, ?s)) {
3066
            auto t = T_float();
3067 3068 3069
            alt (tm) {
                case (common::ty_f32) { t = T_f32(); }
                case (common::ty_f64) { t = T_f64(); }
3070 3071 3072
            }
            ret C_floating(s, t);
        }
3073
        case (ast::lit_char(?c)) {
3074
            ret C_integral(T_char(), c as uint, False);
3075
        }
3076 3077 3078
        case (ast::lit_bool(?b)) { ret C_bool(b); }
        case (ast::lit_nil) { ret C_nil(); }
        case (ast::lit_str(?s, _)) { ret C_str(cx, s); }
3079 3080 3081
    }
}

3082

3083
// Converts an annotation to a type
3084
fn node_ann_type(&@crate_ctxt cx, &ast::ann a) -> ty::t {
3085
    ret ty::ann_to_monotype(cx.tcx, a);
3086 3087
}

3088
fn node_type(&@crate_ctxt cx, &span sp, &ast::ann a) -> TypeRef {
3089
    ret type_of(cx, sp, node_ann_type(cx, a));
3090 3091
}

3092 3093
fn trans_unary(&@block_ctxt cx, ast::unop op, &@ast::expr e, &ast::ann a) ->
   result {
3094
    auto sub = trans_expr(cx, e);
3095
    auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
3096
    alt (op) {
3097
        case (ast::not) {
3098 3099 3100
            sub =
                autoderef(sub.bcx, sub.val,
                          ty::expr_ty(cx.fcx.lcx.ccx.tcx, e));
3101
            ret res(sub.bcx, sub.bcx.build.Not(sub.val));
3102
        }
3103
        case (ast::neg) {
3104 3105 3106 3107
            sub =
                autoderef(sub.bcx, sub.val,
                          ty::expr_ty(cx.fcx.lcx.ccx.tcx, e));
            if (ty::struct(cx.fcx.lcx.ccx.tcx, e_ty) == ty::ty_float) {
3108
                ret res(sub.bcx, sub.bcx.build.FNeg(sub.val));
3109
            } else { ret res(sub.bcx, sub.bcx.build.Neg(sub.val)); }
3110
        }
3111
        case (ast::box(_)) {
3112
            auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
3113
            auto e_val = sub.val;
3114
            auto box_ty = node_ann_type(sub.bcx.fcx.lcx.ccx, a);
3115 3116
            sub = trans_malloc_boxed(sub.bcx, e_ty);
            find_scope_cx(cx).cleanups +=
3117
                [clean(bind drop_ty(_, sub.val, box_ty))];
3118
            auto box = sub.val;
3119 3120 3121 3122 3123 3124 3125
            auto rc =
                sub.bcx.build.GEP(box,
                                  [C_int(0),
                                   C_int(abi::box_rc_field_refcnt)]);
            auto body =
                sub.bcx.build.GEP(box,
                                  [C_int(0), C_int(abi::box_rc_field_body)]);
3126
            sub.bcx.build.Store(C_int(1), rc);
3127 3128 3129
            // Cast the body type to the type of the value. This is needed to
            // make tags work, since tags have a different LLVM type depending
            // on whether they're boxed or not.
3130

3131
            if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, e_ty)) {
3132 3133
                auto llety =
                    T_ptr(type_of(sub.bcx.fcx.lcx.ccx, e.span, e_ty));
3134 3135
                body = sub.bcx.build.PointerCast(body, llety);
            }
3136
            sub = copy_val(sub.bcx, INIT, body, e_val, e_ty);
3137
            ret res(sub.bcx, box);
3138
        }
3139
        case (ast::deref) {
3140 3141 3142
            cx.fcx.lcx.ccx.sess.bug("deref expressions should have been " +
                                        "translated using trans_lval(), not "
                                        + "trans_unary()");
3143
        }
3144 3145 3146
    }
}

3147 3148
fn trans_compare(&@block_ctxt cx0, ast::binop op, &ty::t t0, ValueRef lhs0,
                 ValueRef rhs0) -> result {
3149
    // Autoderef both sides.
3150

3151
    auto cx = cx0;
3152 3153 3154 3155 3156 3157
    auto lhs_r = autoderef(cx, lhs0, t0);
    auto lhs = lhs_r.val;
    cx = lhs_r.bcx;
    auto rhs_r = autoderef(cx, rhs0, t0);
    auto rhs = rhs_r.val;
    cx = rhs_r.bcx;
3158
    auto t = autoderefed_ty(cx.fcx.lcx.ccx, t0);
3159 3160
    // Determine the operation we need.
    // FIXME: Use or-patterns when we have them.
3161

3162
    auto llop;
3163
    alt (op) {
3164 3165 3166 3167 3168 3169
        case (ast::eq) { llop = C_u8(abi::cmp_glue_op_eq); }
        case (ast::lt) { llop = C_u8(abi::cmp_glue_op_lt); }
        case (ast::le) { llop = C_u8(abi::cmp_glue_op_le); }
        case (ast::ne) { llop = C_u8(abi::cmp_glue_op_eq); }
        case (ast::ge) { llop = C_u8(abi::cmp_glue_op_lt); }
        case (ast::gt) { llop = C_u8(abi::cmp_glue_op_le); }
3170
    }
3171
    auto rslt = call_cmp_glue(cx, lhs, rhs, t, llop);
3172

3173 3174
    // Invert the result if necessary.
    // FIXME: Use or-patterns when we have them.
3175
    alt (op) {
3176 3177 3178
        case (ast::eq) { ret res(rslt.bcx, rslt.val); }
        case (ast::lt) { ret res(rslt.bcx, rslt.val); }
        case (ast::le) { ret res(rslt.bcx, rslt.val); }
3179 3180 3181
        case (ast::ne) { ret res(rslt.bcx, rslt.bcx.build.Not(rslt.val)); }
        case (ast::ge) { ret res(rslt.bcx, rslt.bcx.build.Not(rslt.val)); }
        case (ast::gt) { ret res(rslt.bcx, rslt.bcx.build.Not(rslt.val)); }
3182 3183 3184
    }
}

3185 3186
fn trans_vec_append(&@block_ctxt cx, &ty::t t, ValueRef lhs, ValueRef rhs) ->
   result {
3187
    auto elt_ty = ty::sequence_element_type(cx.fcx.lcx.ccx.tcx, t);
3188
    auto skip_null = C_bool(false);
3189 3190
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
        case (ty::ty_str) { skip_null = C_bool(true); }
3191 3192 3193
        case (_) { }
    }
    auto bcx = cx;
3194 3195
    auto ti = none[@tydesc_info];
    auto llvec_tydesc = get_tydesc(bcx, t, false, ti);
3196
    bcx = llvec_tydesc.bcx;
3197 3198 3199 3200
    ti = none[@tydesc_info];
    auto llelt_tydesc = get_tydesc(bcx, elt_ty, false, ti);
    lazily_emit_tydesc_glue(cx, abi::tydesc_field_take_glue, ti);
    lazily_emit_tydesc_glue(cx, abi::tydesc_field_drop_glue, ti);
3201
    lazily_emit_tydesc_glue(cx, abi::tydesc_field_free_glue, ti);
3202
    bcx = llelt_tydesc.bcx;
3203 3204
    auto dst = bcx.build.PointerCast(lhs, T_ptr(T_opaque_vec_ptr()));
    auto src = bcx.build.PointerCast(rhs, T_opaque_vec_ptr());
3205 3206 3207 3208
    ret res(bcx,
            bcx.build.Call(cx.fcx.lcx.ccx.upcalls.vec_append,
                           [cx.fcx.lltaskptr, llvec_tydesc.val,
                            llelt_tydesc.val, dst, src, skip_null]));
3209 3210
}

3211

3212 3213
// Returns a tuple consisting of a pointer to the newly-reserved space and a
// block context. Updates the length appropriately.
3214
fn reserve_ivec_space(&@block_ctxt cx, TypeRef llunitty, ValueRef v,
3215 3216 3217
                      ValueRef len_needed) -> result {
    auto stack_len_ptr =
        cx.build.InBoundsGEP(v, [C_int(0), C_uint(abi::ivec_elt_len)]);
3218
    auto stack_len = cx.build.Load(stack_len_ptr);
3219 3220 3221 3222
    auto alen =
        cx.build.Load(cx.build.InBoundsGEP(v,
                                           [C_int(0),
                                            C_uint(abi::ivec_elt_alen)]));
3223 3224 3225 3226 3227 3228
    // There are four cases we have to consider:
    // (1) On heap, no resize necessary.
    // (2) On heap, need to resize.
    // (3) On stack, no resize necessary.
    // (4) On stack, need to spill to heap.

3229 3230
    auto maybe_on_heap =
        cx.build.ICmp(lib::llvm::LLVMIntEQ, stack_len, C_int(0));
3231 3232 3233 3234 3235
    auto maybe_on_heap_cx = new_sub_block_ctxt(cx, "maybe_on_heap");
    auto on_stack_cx = new_sub_block_ctxt(cx, "on_stack");
    cx.build.CondBr(maybe_on_heap, maybe_on_heap_cx.llbb, on_stack_cx.llbb);
    auto next_cx = new_sub_block_ctxt(cx, "next");
    // We're possibly on the heap, unless the vector is zero-length.
3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248

    auto stub_p = [C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)];

    auto stub_ptr =
        maybe_on_heap_cx.build.PointerCast(v, T_ptr(T_ivec_heap(llunitty)));
    auto heap_ptr =
        {
            auto m = maybe_on_heap_cx.build.InBoundsGEP(stub_ptr, stub_p);
            maybe_on_heap_cx.build.Load(m)
        };
    auto on_heap =
        maybe_on_heap_cx.build.ICmp(lib::llvm::LLVMIntNE, heap_ptr,
                                    C_null(val_ty(heap_ptr)));
3249 3250 3251
    auto on_heap_cx = new_sub_block_ctxt(cx, "on_heap");
    maybe_on_heap_cx.build.CondBr(on_heap, on_heap_cx.llbb, on_stack_cx.llbb);
    // We're definitely on the heap. Check whether we need to resize.
3252 3253 3254 3255 3256

    auto heap_len_ptr =
        on_heap_cx.build.InBoundsGEP(heap_ptr,
                                     [C_int(0),
                                      C_uint(abi::ivec_heap_elt_len)]);
3257 3258
    auto heap_len = on_heap_cx.build.Load(heap_len_ptr);
    auto new_heap_len = on_heap_cx.build.Add(heap_len, len_needed);
3259 3260 3261 3262
    auto heap_len_unscaled =
        on_heap_cx.build.UDiv(heap_len, llsize_of(llunitty));
    auto heap_no_resize_needed =
        on_heap_cx.build.ICmp(lib::llvm::LLVMIntULE, new_heap_len, alen);
3263 3264 3265 3266 3267
    auto heap_no_resize_cx = new_sub_block_ctxt(cx, "heap_no_resize");
    auto heap_resize_cx = new_sub_block_ctxt(cx, "heap_resize");
    on_heap_cx.build.CondBr(heap_no_resize_needed, heap_no_resize_cx.llbb,
                            heap_resize_cx.llbb);
    // Case (1): We're on the heap and don't need to resize.
3268 3269 3270 3271 3272 3273

    auto heap_data_no_resize =
        heap_no_resize_cx.build.InBoundsGEP(heap_ptr,
                                            [C_int(0),
                                             C_uint(abi::ivec_heap_elt_elems),
                                             heap_len_unscaled]);
3274
    heap_no_resize_cx.build.Store(new_heap_len, heap_len_ptr);
3275 3276 3277 3278
    heap_no_resize_cx.build.Br(next_cx.llbb);
    // Case (2): We're on the heap and need to resize. This path is rare, so
    // we delegate to cold glue.

3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295
    {
        auto p = heap_resize_cx.build.PointerCast(v, T_ptr(T_opaque_ivec()));
        heap_resize_cx.build.Call(cx.fcx.lcx.ccx.upcalls.ivec_resize,
                                  [cx.fcx.lltaskptr, p, new_heap_len]);
    }

    auto heap_ptr_resize =
        {
            auto m = heap_resize_cx.build.InBoundsGEP(stub_ptr, stub_p);
            heap_resize_cx.build.Load(m)
        };
    auto heap_data_resize =
        heap_resize_cx.build.InBoundsGEP(heap_ptr_resize,
                                         [C_int(0),
                                          C_uint(abi::ivec_heap_elt_elems),
                                          heap_len_unscaled]);
    heap_resize_cx.build.Br(next_cx.llbb);
3296
    // We're on the stack. Check whether we need to spill to the heap.
3297

3298
    auto new_stack_len = on_stack_cx.build.Add(stack_len, len_needed);
3299 3300 3301 3302
    auto stack_no_spill_needed =
        on_stack_cx.build.ICmp(lib::llvm::LLVMIntULE, new_stack_len, alen);
    auto stack_len_unscaled =
        on_stack_cx.build.UDiv(stack_len, llsize_of(llunitty));
3303 3304 3305 3306 3307
    auto stack_no_spill_cx = new_sub_block_ctxt(cx, "stack_no_spill");
    auto stack_spill_cx = new_sub_block_ctxt(cx, "stack_spill");
    on_stack_cx.build.CondBr(stack_no_spill_needed, stack_no_spill_cx.llbb,
                             stack_spill_cx.llbb);
    // Case (3): We're on the stack and don't need to spill.
3308 3309 3310 3311 3312 3313

    auto stack_data_no_spill =
        stack_no_spill_cx.build.InBoundsGEP(v,
                                            [C_int(0),
                                             C_uint(abi::ivec_elt_elems),
                                             stack_len_unscaled]);
3314
    stack_no_spill_cx.build.Store(new_stack_len, stack_len_ptr);
3315 3316 3317 3318
    stack_no_spill_cx.build.Br(next_cx.llbb);
    // Case (4): We're on the stack and need to spill. Like case (2), this
    // path is rare, so we delegate to cold glue.

3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337
    {
        auto p = stack_spill_cx.build.PointerCast(v, T_ptr(T_opaque_ivec()));
        stack_spill_cx.build.Call(cx.fcx.lcx.ccx.upcalls.ivec_spill,
                                  [cx.fcx.lltaskptr, p, new_stack_len]);
    }
    auto spill_stub =
        stack_spill_cx.build.PointerCast(v, T_ptr(T_ivec_heap(llunitty)));
    auto heap_ptr_spill =
        stack_spill_cx.build.Load(stack_spill_cx.build.InBoundsGEP(spill_stub,
                                                                   stub_p));
    auto heap_len_ptr_spill =
        stack_spill_cx.build.InBoundsGEP(heap_ptr_spill,
                                         [C_int(0),
                                          C_uint(abi::ivec_heap_elt_len)]);
    auto heap_data_spill =
        stack_spill_cx.build.InBoundsGEP(heap_ptr_spill,
                                         [C_int(0),
                                          C_uint(abi::ivec_heap_elt_elems),
                                          stack_len_unscaled]);
3338 3339
    stack_spill_cx.build.Br(next_cx.llbb);
    // Phi together the different data pointers to get the result.
3340 3341 3342 3343 3344 3345 3346

    auto data_ptr =
        next_cx.build.Phi(T_ptr(llunitty),
                          [heap_data_no_resize, heap_data_resize,
                           stack_data_no_spill, heap_data_spill],
                          [heap_no_resize_cx.llbb, heap_resize_cx.llbb,
                           stack_no_spill_cx.llbb, stack_spill_cx.llbb]);
3347
    ret res(next_cx, data_ptr);
3348 3349
}

3350 3351
fn trans_ivec_append(&@block_ctxt cx, &ty::t t, ValueRef lhs, ValueRef rhs) ->
   result {
3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362
    auto unit_ty = ty::sequence_element_type(cx.fcx.lcx.ccx.tcx, t);
    auto llunitty = type_of_or_i8(cx, unit_ty);
    auto skip_null;
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
        case (ty::ty_istr) { skip_null = true; }
        case (ty::ty_ivec(_)) { skip_null = false; }
        case (_) {
            cx.fcx.lcx.ccx.tcx.sess.bug("non-istr/ivec in trans_ivec_append");
        }
    }
    // Gather the various type descriptors we'll need.
3363

3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376
    auto rslt = get_tydesc(cx, t, false, none);
    auto vec_tydesc = rslt.val;
    auto bcx = rslt.bcx;
    rslt = get_tydesc(bcx, unit_ty, false, none);
    auto unit_tydesc = rslt.val;
    bcx = rslt.bcx;
    lazily_emit_tydesc_glue(bcx, abi::tydesc_field_take_glue, none);
    lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, none);
    lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, none);
    auto rhs_len_and_data = get_ivec_len_and_data(bcx, rhs, unit_ty);
    auto rhs_len = rhs_len_and_data._0;
    auto rhs_data = rhs_len_and_data._1;
    bcx = rhs_len_and_data._2;
3377 3378 3379
    rslt = reserve_ivec_space(bcx, llunitty, lhs, rhs_len);
    auto lhs_data = rslt.val;
    bcx = rslt.bcx;
3380
    // Work out the end pointer.
3381

3382 3383 3384
    auto lhs_unscaled_idx = bcx.build.UDiv(rhs_len, llsize_of(llunitty));
    auto lhs_end = bcx.build.InBoundsGEP(lhs_data, [lhs_unscaled_idx]);
    // Now emit the copy loop.
3385

3386 3387 3388 3389 3390 3391 3392
    auto dest_ptr = alloca(bcx, T_ptr(llunitty));
    bcx.build.Store(lhs_data, dest_ptr);
    auto src_ptr = alloca(bcx, T_ptr(llunitty));
    bcx.build.Store(rhs_data, src_ptr);
    auto copy_loop_header_cx = new_sub_block_ctxt(bcx, "copy_loop_header");
    bcx.build.Br(copy_loop_header_cx.llbb);
    auto copy_dest_ptr = copy_loop_header_cx.build.Load(dest_ptr);
3393 3394 3395
    auto not_yet_at_end =
        copy_loop_header_cx.build.ICmp(lib::llvm::LLVMIntNE, copy_dest_ptr,
                                       lhs_end);
3396 3397 3398 3399 3400 3401 3402 3403
    auto copy_loop_body_cx = new_sub_block_ctxt(bcx, "copy_loop_body");
    auto next_cx = new_sub_block_ctxt(bcx, "next");
    copy_loop_header_cx.build.CondBr(not_yet_at_end, copy_loop_body_cx.llbb,
                                     next_cx.llbb);
    auto copy_src_ptr = copy_loop_body_cx.build.Load(src_ptr);
    rslt = copy_val(copy_loop_body_cx, INIT, copy_dest_ptr, copy_src_ptr, t);
    auto post_copy_cx = rslt.bcx;
    // Increment both pointers.
3404

3405
    post_copy_cx.build.Store(post_copy_cx.build.InBoundsGEP(copy_dest_ptr,
3406 3407
                                                            [C_int(1)]),
                             dest_ptr);
3408
    post_copy_cx.build.Store(post_copy_cx.build.InBoundsGEP(copy_src_ptr,
3409 3410
                                                            [C_int(1)]),
                             src_ptr);
3411 3412 3413 3414
    post_copy_cx.build.Br(copy_loop_header_cx.llbb);
    ret res(next_cx, C_nil());
}

3415 3416
fn trans_vec_add(&@block_ctxt cx, &ty::t t, ValueRef lhs, ValueRef rhs) ->
   result {
3417
    auto r = alloc_ty(cx, t);
3418
    auto tmp = r.val;
3419
    r = copy_val(r.bcx, INIT, tmp, lhs, t);
3420
    auto bcx = trans_vec_append(r.bcx, t, tmp, rhs).bcx;
3421
    tmp = load_if_immediate(bcx, tmp, t);
3422
    find_scope_cx(cx).cleanups += [clean(bind drop_ty(_, tmp, t))];
3423
    ret res(bcx, tmp);
3424 3425
}

3426
fn trans_eager_binop(&@block_ctxt cx, ast::binop op, &ty::t intype,
3427
                     ValueRef lhs, ValueRef rhs) -> result {
3428
    auto is_float = false;
3429
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, intype)) {
3430 3431
        case (ty::ty_float) { is_float = true; }
        case (_) { is_float = false; }
3432
    }
3433
    alt (op) {
3434 3435
        case (ast::add) {
            if (ty::type_is_sequence(cx.fcx.lcx.ccx.tcx, intype)) {
3436
                ret trans_vec_add(cx, intype, lhs, rhs);
3437
            }
3438 3439
            if (is_float) {
                ret res(cx, cx.build.FAdd(lhs, rhs));
3440
            } else { ret res(cx, cx.build.Add(lhs, rhs)); }
3441
        }
3442
        case (ast::sub) {
3443 3444
            if (is_float) {
                ret res(cx, cx.build.FSub(lhs, rhs));
3445
            } else { ret res(cx, cx.build.Sub(lhs, rhs)); }
3446
        }
3447
        case (ast::mul) {
3448 3449
            if (is_float) {
                ret res(cx, cx.build.FMul(lhs, rhs));
3450
            } else { ret res(cx, cx.build.Mul(lhs, rhs)); }
3451
        }
3452
        case (ast::div) {
3453
            if (is_float) { ret res(cx, cx.build.FDiv(lhs, rhs)); }
3454
            if (ty::type_is_signed(cx.fcx.lcx.ccx.tcx, intype)) {
3455
                ret res(cx, cx.build.SDiv(lhs, rhs));
3456
            } else { ret res(cx, cx.build.UDiv(lhs, rhs)); }
3457
        }
3458
        case (ast::rem) {
3459
            if (is_float) { ret res(cx, cx.build.FRem(lhs, rhs)); }
3460
            if (ty::type_is_signed(cx.fcx.lcx.ccx.tcx, intype)) {
3461
                ret res(cx, cx.build.SRem(lhs, rhs));
3462
            } else { ret res(cx, cx.build.URem(lhs, rhs)); }
3463
        }
3464 3465 3466 3467 3468 3469
        case (ast::bitor) { ret res(cx, cx.build.Or(lhs, rhs)); }
        case (ast::bitand) { ret res(cx, cx.build.And(lhs, rhs)); }
        case (ast::bitxor) { ret res(cx, cx.build.Xor(lhs, rhs)); }
        case (ast::lsl) { ret res(cx, cx.build.Shl(lhs, rhs)); }
        case (ast::lsr) { ret res(cx, cx.build.LShr(lhs, rhs)); }
        case (ast::asr) { ret res(cx, cx.build.AShr(lhs, rhs)); }
3470
        case (_) { ret trans_compare(cx, op, intype, lhs, rhs); }
3471 3472 3473
    }
}

3474
fn autoderef(&@block_ctxt cx, ValueRef v, &ty::t t) -> result {
3475
    let ValueRef v1 = v;
3476
    let ty::t t1 = t;
3477
    while (true) {
3478 3479
        alt (ty::struct(cx.fcx.lcx.ccx.tcx, t1)) {
            case (ty::ty_box(?mt)) {
3480 3481 3482
                auto body =
                    cx.build.GEP(v1,
                                 [C_int(0), C_int(abi::box_rc_field_body)]);
3483
                t1 = mt.ty;
3484 3485 3486 3487
                // Since we're changing levels of box indirection, we may have
                // to cast this pointer, since statically-sized tag types have
                // different types depending on whether they're behind a box
                // or not.
3488

3489
                if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, mt.ty)) {
3490
                    auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, mt.ty);
3491
                    v1 = cx.build.PointerCast(body, T_ptr(llty));
3492
                } else { v1 = body; }
3493
                v1 = load_if_immediate(cx, v1, t1);
3494
            }
3495
            case (_) { break; }
3496 3497
        }
    }
3498
    ret res(cx, v1);
3499 3500
}

3501 3502
fn autoderefed_ty(&@crate_ctxt ccx, &ty::t t) -> ty::t {
    let ty::t t1 = t;
3503
    while (true) {
3504
        alt (ty::struct(ccx.tcx, t1)) {
3505
            case (ty::ty_box(?mt)) { t1 = mt.ty; }
3506
            case (_) { break; }
3507 3508
        }
    }
3509
    ret t1;
3510 3511
}

3512 3513
fn trans_binary(&@block_ctxt cx, ast::binop op, &@ast::expr a, &@ast::expr b)
   -> result {
3514

3515 3516
    // First couple cases are lazy:
    alt (op) {
3517
        case (ast::and) {
3518 3519
            // Lazy-eval and

3520 3521 3522 3523
            auto lhs_res = trans_expr(cx, a);
            lhs_res =
                autoderef(lhs_res.bcx, lhs_res.val,
                          ty::expr_ty(cx.fcx.lcx.ccx.tcx, a));
3524
            auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
3525
            auto rhs_res = trans_expr(rhs_cx, b);
3526 3527 3528
            rhs_res =
                autoderef(rhs_res.bcx, rhs_res.val,
                          ty::expr_ty(cx.fcx.lcx.ccx.tcx, b));
3529
            auto lhs_false_cx = new_scope_block_ctxt(cx, "lhs false");
3530
            auto lhs_false_res = res(lhs_false_cx, C_bool(false));
3531
            // The following line ensures that any cleanups for rhs
3532
            // are done within the block for rhs. This is necessary
3533 3534 3535
            // because and/or are lazy. So the rhs may never execute,
            // and the cleanups can't be pushed into later code.

3536 3537
            auto rhs_bcx = trans_block_cleanups(rhs_res.bcx, rhs_cx);
            lhs_res.bcx.build.CondBr(lhs_res.val, rhs_cx.llbb,
3538 3539
                                     lhs_false_cx.llbb);
            ret join_results(cx, T_bool(),
3540
                             [lhs_false_res, rec(bcx=rhs_bcx with rhs_res)]);
3541
        }
3542
        case (ast::or) {
3543 3544
            // Lazy-eval or

3545 3546 3547 3548
            auto lhs_res = trans_expr(cx, a);
            lhs_res =
                autoderef(lhs_res.bcx, lhs_res.val,
                          ty::expr_ty(cx.fcx.lcx.ccx.tcx, a));
3549
            auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
3550
            auto rhs_res = trans_expr(rhs_cx, b);
3551 3552 3553
            rhs_res =
                autoderef(rhs_res.bcx, rhs_res.val,
                          ty::expr_ty(cx.fcx.lcx.ccx.tcx, b));
3554
            auto lhs_true_cx = new_scope_block_ctxt(cx, "lhs true");
3555
            auto lhs_true_res = res(lhs_true_cx, C_bool(true));
3556 3557
            // see the and case for an explanation

3558 3559
            auto rhs_bcx = trans_block_cleanups(rhs_res.bcx, rhs_cx);
            lhs_res.bcx.build.CondBr(lhs_res.val, lhs_true_cx.llbb,
3560
                                     rhs_cx.llbb);
3561
            ret join_results(cx, T_bool(),
3562
                             [lhs_true_res, rec(bcx=rhs_bcx with rhs_res)]);
3563
        }
3564
        case (_) {
3565
            // Remaining cases are eager:
3566

3567
            auto lhs = trans_expr(cx, a);
3568
            auto lhty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, a);
3569
            lhs = autoderef(lhs.bcx, lhs.val, lhty);
3570
            auto rhs = trans_expr(lhs.bcx, b);
3571
            auto rhty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, b);
3572
            rhs = autoderef(rhs.bcx, rhs.val, rhty);
3573
            ret trans_eager_binop(rhs.bcx, op,
3574 3575
                                  autoderefed_ty(cx.fcx.lcx.ccx, lhty),
                                  lhs.val, rhs.val);
3576
        }
3577 3578 3579
    }
}

3580 3581
fn join_results(&@block_ctxt parent_cx, TypeRef t, &vec[result] ins) ->
   result {
3582 3583 3584
    let vec[result] live = [];
    let vec[ValueRef] vals = [];
    let vec[BasicBlockRef] bbs = [];
3585
    for (result r in ins) {
3586
        if (!is_terminated(r.bcx)) {
3587 3588 3589
            live += [r];
            vals += [r.val];
            bbs += [r.bcx.llbb];
3590 3591
        }
    }
3592
    alt (vec::len[result](live)) {
3593 3594 3595 3596
        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.
3597

3598
            assert (vec::len[result](ins) >= 1u);
3599 3600
            ret ins.(0);
        }
3601
        case (_) {/* fall through */ }
3602 3603
    }
    // We have >1 incoming edges. Make a join block and br+phi them into it.
3604

3605
    auto join_cx = new_sub_block_ctxt(parent_cx, "join");
3606
    for (result r in live) { r.bcx.build.Br(join_cx.llbb); }
3607 3608 3609 3610
    auto phi = join_cx.build.Phi(t, vals, bbs);
    ret res(join_cx, phi);
}

3611 3612 3613
fn join_branches(&@block_ctxt parent_cx, &vec[result] ins) -> @block_ctxt {
    auto out = new_sub_block_ctxt(parent_cx, "join");
    for (result r in ins) {
3614
        if (!is_terminated(r.bcx)) { r.bcx.build.Br(out.llbb); }
3615 3616 3617 3618
    }
    ret out;
}

3619
tag out_method { return; save_in(ValueRef); }
3620

3621 3622 3623
fn trans_if(&@block_ctxt cx, &@ast::expr cond, &ast::block thn,
            &option::t[@ast::expr] els, &ast::ann ann, &out_method output) ->
   result {
3624
    auto cond_res = trans_expr(cx, cond);
3625
    auto then_cx = new_scope_block_ctxt(cx, "then");
3626
    auto then_res = trans_block(then_cx, thn, output);
3627
    auto else_cx = new_scope_block_ctxt(cx, "else");
3628 3629
    auto else_res;
    auto expr_llty;
3630
    alt (els) {
3631
        case (some(?elexpr)) {
3632
            alt (elexpr.node) {
3633 3634 3635 3636 3637
                case (ast::expr_if(_, _, _, ?ann)) {
                    // Synthesize a block here to act as the else block
                    // containing an if expression. Needed in order for the
                    // else scope to behave like a normal block scope. A tad
                    // ugly.
3638 3639 3640 3641

                    let ast::block_ elseif_blk_ =
                        rec(stmts=[], expr=some[@ast::expr](elexpr), a=ann);
                    auto elseif_blk = rec(node=elseif_blk_, span=elexpr.span);
3642
                    else_res = trans_block(else_cx, elseif_blk, output);
3643
                }
3644
                case (ast::expr_block(?blk, _)) {
3645 3646 3647 3648
                    // Calling trans_block directly instead of trans_expr
                    // because trans_expr will create another scope block
                    // context for the block, but we've already got the
                    // 'else' context
3649

3650
                    else_res = trans_block(else_cx, blk, output);
3651 3652
                }
            }
3653
            // FIXME: This isn't quite right, particularly re: dynamic types
3654 3655

            auto expr_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann);
3656
            if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, expr_ty)) {
3657
                expr_llty = T_typaram_ptr(cx.fcx.lcx.ccx.tn);
3658
            } else {
3659
                expr_llty = type_of(cx.fcx.lcx.ccx, elexpr.span, expr_ty);
3660
                if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, expr_ty)) {
3661 3662
                    expr_llty = T_ptr(expr_llty);
                }
3663
            }
3664
        }
3665
        case (_) { else_res = res(else_cx, C_nil()); expr_llty = T_nil(); }
3666
    }
3667
    cond_res.bcx.build.CondBr(cond_res.val, then_cx.llbb, else_cx.llbb);
3668
    ret res(join_branches(cx, [then_res, else_res]), C_nil());
3669 3670
}

3671
fn trans_for(&@block_ctxt cx, &@ast::local local, &@ast::expr seq,
3672
             &ast::block body) -> result {
3673 3674
    fn inner(&@block_ctxt cx, @ast::local_ local, ValueRef curr, ty::t t,
             ast::block body, @block_ctxt outer_next_cx) -> result {
G
Graydon Hoare 已提交
3675
        auto next_cx = new_sub_block_ctxt(cx, "next");
3676
        auto scope_cx =
3677
            new_loop_scope_block_ctxt(cx, option::some[@block_ctxt](next_cx),
3678
                                      outer_next_cx, "for loop scope");
G
Graydon Hoare 已提交
3679 3680
        cx.build.Br(scope_cx.llbb);
        auto local_res = alloc_local(scope_cx, local);
3681
        auto bcx = copy_val(local_res.bcx, INIT, local_res.val, curr, t).bcx;
3682
        scope_cx.cleanups += [clean(bind drop_slot(_, local_res.val, t))];
3683
        bcx = trans_block(bcx, body, return).bcx;
G
Graydon Hoare 已提交
3684 3685 3686
        bcx.build.Br(next_cx.llbb);
        ret res(next_cx, C_nil());
    }
3687
    auto next_cx = new_sub_block_ctxt(cx, "next");
3688
    auto seq_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, seq);
G
Graydon Hoare 已提交
3689
    auto seq_res = trans_expr(cx, seq);
3690 3691 3692
    auto it =
        iter_sequence(seq_res.bcx, seq_res.val, seq_ty,
                      bind inner(_, local.node, _, _, body, next_cx));
3693 3694
    it.bcx.build.Br(next_cx.llbb);
    ret res(next_cx, it.val);
G
Graydon Hoare 已提交
3695 3696
}

3697 3698 3699 3700 3701

// Iterator translation

// Searches through a block for all references to locals or upvars in this
// frame and returns the list of definition IDs thus found.
3702 3703
fn collect_upvars(&@block_ctxt cx, &ast::block bloc,
                  &ast::def_id initial_decl) -> vec[ast::def_id] {
3704 3705 3706 3707
    type env =
        @rec(mutable vec[ast::def_id] refs,
             hashmap[ast::def_id, ()] decls,
             resolve::def_map def_map);
3708

3709
    fn walk_expr(env e, &@ast::expr expr) {
M
Marijn Haverbeke 已提交
3710
        alt (expr.node) {
3711
            case (ast::expr_path(?path, ?ann)) {
P
Patrick Walton 已提交
3712
                alt (e.def_map.get(ann.id)) {
3713
                    case (ast::def_arg(?did)) {
3714
                        vec::push[ast::def_id](e.refs, did);
M
Marijn Haverbeke 已提交
3715
                    }
3716
                    case (ast::def_local(?did)) {
3717
                        vec::push[ast::def_id](e.refs, did);
M
Marijn Haverbeke 已提交
3718
                    }
3719
                    case (_) { }
M
Marijn Haverbeke 已提交
3720 3721
                }
            }
3722
            case (_) { }
3723 3724
        }
    }
3725 3726
    fn walk_local(env e, &@ast::local local) {
        e.decls.insert(local.node.id, ());
3727
    }
3728
    let vec[ast::def_id] refs = [];
3729
    let hashmap[ast::def_id, ()] decls = new_def_hash[()]();
3730
    decls.insert(initial_decl, ());
3731 3732 3733 3734 3735 3736 3737 3738
    let env e =
        @rec(mutable refs=refs,
             decls=decls,
             def_map=cx.fcx.lcx.ccx.tcx.def_map);
    auto visitor =
        @rec(visit_local_pre=bind walk_local(e, _),
             visit_expr_pre=bind walk_expr(e, _)
             with walk::default_visitor());
3739
    walk::walk_block(*visitor, bloc);
3740
    // Calculate (refs - decls). This is the set of captured upvars.
3741

3742
    let vec[ast::def_id] result = [];
3743 3744
    for (ast::def_id ref_id_ in e.refs) {
        auto ref_id = ref_id_;
3745
        if (!decls.contains_key(ref_id)) { result += [ref_id]; }
3746 3747 3748 3749
    }
    ret result;
}

3750
fn trans_for_each(&@block_ctxt cx, &@ast::local local, &@ast::expr seq,
3751
                  &ast::block body) -> result {
3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777
    /*
     * The translation is a little .. complex here. Code like:
     *
     *    let ty1 p = ...;
     *
     *    let ty1 q = ...;
     *
     *    foreach (ty v in foo(a,b)) { body(p,q,v) }
     *
     *
     * Turns into a something like so (C/Rust mishmash):
     *
     *    type env = { *ty1 p, *ty2 q, ... };
     *
     *    let env e = { &p, &q, ... };
     *
     *    fn foreach123_body(env* e, ty v) { body(*(e->p),*(e->q),v) }
     *
     *    foo([foreach123_body, env*], a, b);
     *
     */

    // Step 1: walk body and figure out which references it makes
    // escape. This could be determined upstream, and probably ought
    // to be so, eventualy. For first cut, skip this. Null env.

3778
    auto lcx = cx.fcx.lcx;
3779
    // FIXME: possibly support alias-mode here?
3780

3781 3782
    auto decl_ty = node_ann_type(lcx.ccx, local.node.ann);
    auto decl_id = local.node.id;
3783
    auto upvars = collect_upvars(cx, body, decl_id);
3784
    auto upvar_count = vec::len[ast::def_id](upvars);
3785 3786 3787
    auto llbindingsptr;
    if (upvar_count > 0u) {
        // Gather up the upvars.
3788

3789 3790
        let vec[ValueRef] llbindings = [];
        let vec[TypeRef] llbindingtys = [];
3791
        for (ast::def_id did in upvars) {
3792 3793
            auto llbinding;
            alt (cx.fcx.lllocals.find(did)) {
3794
                case (none) {
3795 3796 3797 3798 3799 3800
                    alt (cx.fcx.llupvars.find(did)) {
                        case (none[ValueRef]) {
                            llbinding = cx.fcx.llargs.get(did);
                        }
                        case (some[ValueRef](?llval)) { llbinding = llval; }
                    }
3801
                }
3802
                case (some(?llval)) { llbinding = llval; }
3803
            }
3804 3805
            llbindings += [llbinding];
            llbindingtys += [val_ty(llbinding)];
3806 3807
        }
        // Create an array of bindings and copy in aliases to the upvars.
3808

3809
        llbindingsptr = alloca(cx, T_struct(llbindingtys));
3810 3811
        auto i = 0u;
        while (i < upvar_count) {
3812 3813
            auto llbindingptr =
                cx.build.GEP(llbindingsptr, [C_int(0), C_int(i as int)]);
3814 3815 3816 3817 3818
            cx.build.Store(llbindings.(i), llbindingptr);
            i += 1u;
        }
    } else {
        // Null bindings.
3819

3820
        llbindingsptr = C_null(T_ptr(T_i8()));
3821
    }
3822
    // Create an environment and populate it with the bindings.
3823

3824
    auto tydesc_count = vec::len[ValueRef](cx.fcx.lltydescs);
3825 3826 3827
    auto llenvptrty =
        T_closure_ptr(lcx.ccx.tn, T_ptr(T_nil()), val_ty(llbindingsptr),
                      tydesc_count);
3828
    auto llenvptr = alloca(cx, llvm::LLVMGetElementType(llenvptrty));
3829 3830 3831
    auto llbindingsptrptr =
        cx.build.GEP(llenvptr,
                     [C_int(0), C_int(abi::box_rc_field_body), C_int(2)]);
3832
    cx.build.Store(llbindingsptr, llbindingsptrptr);
3833 3834
    // Copy in our type descriptors, in case the iterator body needs to refer
    // to them.
3835 3836 3837 3838 3839

    auto lltydescsptr =
        cx.build.GEP(llenvptr,
                     [C_int(0), C_int(abi::box_rc_field_body),
                      C_int(abi::closure_elt_ty_params)]);
3840 3841
    auto i = 0u;
    while (i < tydesc_count) {
3842 3843
        auto lltydescptr =
            cx.build.GEP(lltydescsptr, [C_int(0), C_int(i as int)]);
3844 3845 3846
        cx.build.Store(cx.fcx.lltydescs.(i), lltydescptr);
        i += 1u;
    }
3847 3848
    // Step 2: Declare foreach body function.

3849 3850
    let str s =
        mangle_internal_name_by_path_and_seq(lcx.ccx, lcx.path, "foreach");
3851 3852 3853 3854 3855 3856
    // The 'env' arg entering the body function is a fake env member (as in
    // the env-part of the normal rust calling convention) that actually
    // points to a stack allocated env in this frame. We bundle that env
    // pointer along with the foreach-body-fn pointer into a 'normal' fn pair
    // and pass it in as a first class fn-arg to the iterator.

3857
    auto iter_body_llty =
3858
        type_of_fn_full(lcx.ccx, cx.sp, ast::proto_fn, none[TypeRef],
3859
                        [rec(mode=ty::mo_alias(false), ty=decl_ty)],
3860
                        ty::mk_nil(lcx.ccx.tcx), 0u);
3861 3862
    let ValueRef lliterbody =
        decl_internal_fastcall_fn(lcx.ccx.llmod, s, iter_body_llty);
3863
    auto fcx = new_fn_ctxt(lcx, cx.sp, lliterbody);
3864
    auto copy_args_bcx = new_raw_block_ctxt(fcx, fcx.llcopyargs);
3865
    // Populate the upvars from the environment.
3866 3867 3868

    auto llremoteenvptr =
        copy_args_bcx.build.PointerCast(fcx.llenv, llenvptrty);
3869
    auto llremotebindingsptrptr =
3870
        copy_args_bcx.build.GEP(llremoteenvptr,
3871 3872
                                [C_int(0), C_int(abi::box_rc_field_body),
                                 C_int(abi::closure_elt_bindings)]);
3873 3874
    auto llremotebindingsptr =
        copy_args_bcx.build.Load(llremotebindingsptrptr);
3875
    i = 0u;
3876 3877
    while (i < upvar_count) {
        auto upvar_id = upvars.(i);
3878 3879
        auto llupvarptrptr =
            copy_args_bcx.build.GEP(llremotebindingsptr,
3880
                                    [C_int(0), C_int(i as int)]);
3881
        auto llupvarptr = copy_args_bcx.build.Load(llupvarptrptr);
3882 3883 3884
        fcx.llupvars.insert(upvar_id, llupvarptr);
        i += 1u;
    }
3885
    // Populate the type parameters from the environment.
3886

3887
    auto llremotetydescsptr =
3888
        copy_args_bcx.build.GEP(llremoteenvptr,
3889 3890
                                [C_int(0), C_int(abi::box_rc_field_body),
                                 C_int(abi::closure_elt_ty_params)]);
3891 3892
    i = 0u;
    while (i < tydesc_count) {
3893
        auto llremotetydescptr =
3894 3895
            copy_args_bcx.build.GEP(llremotetydescsptr,
                                    [C_int(0), C_int(i as int)]);
3896
        auto llremotetydesc = copy_args_bcx.build.Load(llremotetydescptr);
3897
        fcx.lltydescs += [llremotetydesc];
3898 3899
        i += 1u;
    }
3900
    // Add an upvar for the loop variable alias.
3901

3902
    fcx.llupvars.insert(decl_id, llvm::LLVMGetParam(fcx.llfn, 3u));
3903 3904
    auto bcx = new_top_block_ctxt(fcx);
    auto lltop = bcx.llbb;
3905
    auto r = trans_block(bcx, body, return);
3906
    finish_fn(fcx, lltop);
3907
    r.bcx.build.RetVoid();
3908

3909
    // Step 3: Call iter passing [lliterbody, llenv], plus other args.
3910
    alt (seq.node) {
3911
        case (ast::expr_call(?f, ?args, ?ann)) {
3912 3913 3914
            auto pair = alloca(cx, T_fn_pair(lcx.ccx.tn, iter_body_llty));
            auto code_cell =
                cx.build.GEP(pair, [C_int(0), C_int(abi::fn_field_code)]);
3915
            cx.build.Store(lliterbody, code_cell);
3916 3917 3918 3919 3920
            auto env_cell =
                cx.build.GEP(pair, [C_int(0), C_int(abi::fn_field_box)]);
            auto llenvblobptr =
                cx.build.PointerCast(llenvptr,
                                     T_opaque_closure_ptr(lcx.ccx.tn));
3921
            cx.build.Store(llenvblobptr, env_cell);
3922
            // log "lliterbody: " + val_str(lcx.ccx.tn, lliterbody);
3923 3924 3925

            r =
                trans_call(cx, f, some[ValueRef](cx.build.Load(pair)), args,
3926
                           ann);
3927
            ret res(r.bcx, C_nil());
3928 3929
        }
    }
3930 3931
}

3932 3933
fn trans_while(&@block_ctxt cx, &@ast::expr cond, &ast::block body) ->
   result {
3934
    auto cond_cx = new_scope_block_ctxt(cx, "while cond");
3935
    auto next_cx = new_sub_block_ctxt(cx, "next");
3936 3937 3938
    auto body_cx =
        new_loop_scope_block_ctxt(cx, option::none[@block_ctxt], next_cx,
                                  "while loop body");
3939
    auto body_res = trans_block(body_cx, body, return);
3940 3941
    auto cond_res = trans_expr(cond_cx, cond);
    body_res.bcx.build.Br(cond_cx.llbb);
3942 3943
    auto cond_bcx = trans_block_cleanups(cond_res.bcx, cond_cx);
    cond_bcx.build.CondBr(cond_res.val, body_cx.llbb, next_cx.llbb);
3944
    cx.build.Br(cond_cx.llbb);
3945 3946 3947
    ret res(next_cx, C_nil());
}

3948 3949
fn trans_do_while(&@block_ctxt cx, &ast::block body, &@ast::expr cond) ->
   result {
3950
    auto next_cx = new_sub_block_ctxt(cx, "next");
3951 3952 3953
    auto body_cx =
        new_loop_scope_block_ctxt(cx, option::none[@block_ctxt], next_cx,
                                  "do-while loop body");
3954
    auto body_res = trans_block(body_cx, body, return);
3955
    auto cond_res = trans_expr(body_res.bcx, cond);
3956
    cond_res.bcx.build.CondBr(cond_res.val, body_cx.llbb, next_cx.llbb);
3957
    cx.build.Br(body_cx.llbb);
3958 3959 3960
    ret res(next_cx, body_res.val);
}

P
Patrick Walton 已提交
3961

3962
// Pattern matching translation
3963
fn trans_pat_match(&@block_ctxt cx, &@ast::pat pat, ValueRef llval,
G
Graydon Hoare 已提交
3964
                   &@block_ctxt next_cx) -> result {
P
Patrick Walton 已提交
3965
    alt (pat.node) {
3966 3967 3968
        case (ast::pat_wild(_)) { ret res(cx, llval); }
        case (ast::pat_bind(_, _, _)) { ret res(cx, llval); }
        case (ast::pat_lit(?lt, ?ann)) {
3969
            auto lllit = trans_lit(cx.fcx.lcx.ccx, *lt, ann);
3970
            auto lltype = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann);
3971
            auto lleq = trans_compare(cx, ast::eq, lltype, llval, lllit);
3972 3973
            auto matched_cx = new_sub_block_ctxt(lleq.bcx, "matched_cx");
            lleq.bcx.build.CondBr(lleq.val, matched_cx.llbb, next_cx.llbb);
3974 3975
            ret res(matched_cx, llval);
        }
3976
        case (ast::pat_tag(?id, ?subpats, ?ann)) {
3977 3978 3979 3980
            auto lltagptr =
                cx.build.PointerCast(llval,
                                     T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn));
            auto lldiscrimptr = cx.build.GEP(lltagptr, [C_int(0), C_int(0)]);
3981
            auto lldiscrim = cx.build.Load(lldiscrimptr);
3982 3983
            auto vdef =
                ast::variant_def_ids(cx.fcx.lcx.ccx.tcx.def_map.get(ann.id));
P
Patrick Walton 已提交
3984
            auto variant_tag = 0;
3985
            auto variants = ty::tag_variants(cx.fcx.lcx.ccx.tcx, vdef._0);
P
Patrick Walton 已提交
3986
            auto i = 0;
3987
            for (ty::variant_info v in variants) {
3988
                auto this_variant_id = v.id;
3989
                if (vdef._1._0 == this_variant_id._0 &&
3990
                        vdef._1._1 == this_variant_id._1) {
P
Patrick Walton 已提交
3991 3992 3993 3994 3995
                    variant_tag = i;
                }
                i += 1;
            }
            auto matched_cx = new_sub_block_ctxt(cx, "matched_cx");
3996 3997 3998
            auto lleq =
                cx.build.ICmp(lib::llvm::LLVMIntEQ, lldiscrim,
                              C_int(variant_tag));
P
Patrick Walton 已提交
3999
            cx.build.CondBr(lleq, matched_cx.llbb, next_cx.llbb);
4000
            auto ty_params = ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx, ann);
4001
            if (vec::len[@ast::pat](subpats) > 0u) {
4002 4003
                auto llblobptr =
                    matched_cx.build.GEP(lltagptr, [C_int(0), C_int(1)]);
P
Patrick Walton 已提交
4004
                auto i = 0;
4005
                for (@ast::pat subpat in subpats) {
4006 4007 4008
                    auto rslt =
                        GEP_tag(matched_cx, llblobptr, vdef._0, vdef._1,
                                ty_params, i);
4009 4010
                    auto llsubvalptr = rslt.val;
                    matched_cx = rslt.bcx;
4011 4012 4013 4014 4015 4016
                    auto llsubval =
                        load_if_immediate(matched_cx, llsubvalptr,
                                          pat_ty(cx.fcx.lcx.ccx.tcx, subpat));
                    auto subpat_res =
                        trans_pat_match(matched_cx, subpat, llsubval,
                                        next_cx);
P
Patrick Walton 已提交
4017
                    matched_cx = subpat_res.bcx;
4018
                    i += 1;
P
Patrick Walton 已提交
4019 4020 4021 4022 4023 4024 4025
                }
            }
            ret res(matched_cx, llval);
        }
    }
}

4026 4027
fn trans_pat_binding(&@block_ctxt cx, &@ast::pat pat, ValueRef llval,
                     bool bind_alias) -> result {
P
Patrick Walton 已提交
4028
    alt (pat.node) {
4029 4030 4031
        case (ast::pat_wild(_)) { ret res(cx, llval); }
        case (ast::pat_lit(_, _)) { ret res(cx, llval); }
        case (ast::pat_bind(?id, ?def_id, ?ann)) {
4032 4033 4034 4035 4036 4037 4038 4039
            if (bind_alias) {
                cx.fcx.lllocals.insert(def_id, llval);
                ret res(cx, llval);
            } else {
                auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
                auto rslt = alloc_ty(cx, t);
                auto dst = rslt.val;
                auto bcx = rslt.bcx;
4040
                maybe_name_value(cx.fcx.lcx.ccx, dst, id);
4041
                bcx.fcx.lllocals.insert(def_id, dst);
4042
                bcx.cleanups += [clean(bind drop_slot(_, dst, t))];
4043
                ret copy_val(bcx, INIT, dst, llval, t);
4044
            }
P
Patrick Walton 已提交
4045
        }
4046
        case (ast::pat_tag(_, ?subpats, ?ann)) {
4047
            if (vec::len[@ast::pat](subpats) == 0u) { ret res(cx, llval); }
4048 4049
            // Get the appropriate variant for this tag.

4050 4051 4052 4053 4054
            auto vdef =
                ast::variant_def_ids(cx.fcx.lcx.ccx.tcx.def_map.get(ann.id));
            auto lltagptr =
                cx.build.PointerCast(llval,
                                     T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn));
4055
            auto llblobptr = cx.build.GEP(lltagptr, [C_int(0), C_int(1)]);
4056
            auto ty_param_substs =
4057
                ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx, ann);
P
Patrick Walton 已提交
4058 4059
            auto this_cx = cx;
            auto i = 0;
4060
            for (@ast::pat subpat in subpats) {
4061 4062 4063
                auto rslt =
                    GEP_tag(this_cx, llblobptr, vdef._0, vdef._1,
                            ty_param_substs, i);
4064
                this_cx = rslt.bcx;
4065 4066
                auto subpat_res =
                    trans_pat_binding(this_cx, subpat, rslt.val, true);
P
Patrick Walton 已提交
4067
                this_cx = subpat_res.bcx;
4068
                i += 1;
P
Patrick Walton 已提交
4069 4070 4071 4072 4073 4074
            }
            ret res(this_cx, llval);
        }
    }
}

4075 4076
fn trans_alt(&@block_ctxt cx, &@ast::expr expr, &vec[ast::arm] arms,
             &ast::ann ann, &out_method output) -> result {
P
Patrick Walton 已提交
4077 4078
    auto expr_res = trans_expr(cx, expr);
    auto this_cx = expr_res.bcx;
4079
    let vec[result] arm_results = [];
4080
    for (ast::arm arm in arms) {
P
Patrick Walton 已提交
4081
        auto next_cx = new_sub_block_ctxt(expr_res.bcx, "next");
4082 4083
        auto match_res =
            trans_pat_match(this_cx, arm.pat, expr_res.val, next_cx);
P
Patrick Walton 已提交
4084 4085
        auto binding_cx = new_scope_block_ctxt(match_res.bcx, "binding");
        match_res.bcx.build.Br(binding_cx.llbb);
4086 4087
        auto binding_res =
            trans_pat_binding(binding_cx, arm.pat, expr_res.val, false);
4088
        auto block_res = trans_block(binding_res.bcx, arm.block, output);
4089
        arm_results += [block_res];
P
Patrick Walton 已提交
4090 4091
        this_cx = next_cx;
    }
4092
    auto default_cx = this_cx;
4093 4094 4095
    auto default_res =
        trans_fail(default_cx, some[common::span](expr.span),
                   "non-exhaustive match failure");
4096
    // FIXME: This isn't quite right, particularly re: dynamic types
4097

4098
    auto expr_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann);
4099
    auto expr_llty;
4100
    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, expr_ty)) {
4101
        expr_llty = T_typaram_ptr(cx.fcx.lcx.ccx.tn);
4102
    } else {
4103
        expr_llty = type_of(cx.fcx.lcx.ccx, expr.span, expr_ty);
4104
        if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, expr_ty)) {
4105 4106 4107
            expr_llty = T_ptr(expr_llty);
        }
    }
4108
    ret res(join_branches(cx, arm_results), C_nil());
P
Patrick Walton 已提交
4109 4110
}

4111 4112 4113 4114
type generic_info =
    rec(ty::t item_type,
        vec[option::t[@tydesc_info]] static_tis,
        vec[ValueRef] tydescs);
4115

4116 4117 4118 4119 4120 4121
type lval_result =
    rec(result res,
        bool is_mem,
        option::t[generic_info] generic,
        option::t[ValueRef] llobj,
        option::t[ty::t] method_ty);
4122

G
Graydon Hoare 已提交
4123
fn lval_mem(&@block_ctxt cx, ValueRef val) -> lval_result {
4124 4125
    ret rec(res=res(cx, val),
            is_mem=true,
4126
            generic=none[generic_info],
4127
            llobj=none[ValueRef],
4128
            method_ty=none[ty::t]);
4129 4130
}

G
Graydon Hoare 已提交
4131
fn lval_val(&@block_ctxt cx, ValueRef val) -> lval_result {
4132 4133
    ret rec(res=res(cx, val),
            is_mem=false,
4134
            generic=none[generic_info],
4135
            llobj=none[ValueRef],
4136
            method_ty=none[ty::t]);
4137
}
4138

4139 4140
fn trans_external_path(&@block_ctxt cx, &ast::def_id did,
                       &ty::ty_param_count_and_ty tpt) -> lval_result {
4141
    auto lcx = cx.fcx.lcx;
4142
    auto name = creader::get_symbol(lcx.ccx.sess, did);
4143 4144 4145
    auto v =
        get_extern_const(lcx.ccx.externs, lcx.ccx.llmod, name,
                         type_of_ty_param_count_and_ty(lcx, cx.sp, tpt));
4146 4147 4148
    ret lval_val(cx, v);
}

4149 4150
fn lval_generic_fn(&@block_ctxt cx, &ty::ty_param_count_and_ty tpt,
                   &ast::def_id fn_id, &ast::ann ann) -> lval_result {
4151
    auto lv;
4152
    if (cx.fcx.lcx.ccx.sess.get_targ_crate_num() == fn_id._0) {
4153
        // Internal reference.
4154

4155
        assert (cx.fcx.lcx.ccx.fn_pairs.contains_key(fn_id));
4156
        lv = lval_val(cx, cx.fcx.lcx.ccx.fn_pairs.get(fn_id));
4157 4158
    } else {
        // External reference.
4159

4160
        lv = trans_external_path(cx, fn_id, tpt);
4161
    }
4162 4163
    auto tys = ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx, ann);
    auto monoty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann);
4164
    if (vec::len[ty::t](tys) != 0u) {
4165
        auto bcx = lv.res.bcx;
4166 4167
        let vec[ValueRef] tydescs = [];
        let vec[option::t[@tydesc_info]] tis = [];
4168
        for (ty::t t in tys) {
4169
            // TODO: Doesn't always escape.
4170

4171 4172
            auto ti = none[@tydesc_info];
            auto td = get_tydesc(bcx, t, true, ti);
4173
            tis += [ti];
4174
            bcx = td.bcx;
4175
            vec::push[ValueRef](tydescs, td.val);
4176
        }
4177 4178 4179 4180
        auto gen = rec(item_type=tpt._1, static_tis=tis, tydescs=tydescs);
        lv =
            rec(res=res(bcx, lv.res.val), generic=some[generic_info](gen)
                with lv);
4181 4182 4183 4184
    }
    ret lv;
}

4185
fn lookup_discriminant(&@local_ctxt lcx, &ast::def_id tid, &ast::def_id vid)
4186
   -> ValueRef {
4187
    alt (lcx.ccx.discrims.find(vid)) {
4188
        case (none) {
4189
            // It's an external discriminant that we haven't seen yet.
4190

4191
            assert (lcx.ccx.sess.get_targ_crate_num() != vid._0);
4192
            auto sym = creader::get_symbol(lcx.ccx.sess, vid);
4193 4194 4195 4196 4197
            auto gvar =
                llvm::LLVMAddGlobal(lcx.ccx.llmod, T_int(), str::buf(sym));
            llvm::LLVMSetLinkage(gvar,
                                 lib::llvm::LLVMExternalLinkage as
                                     llvm::Linkage);
4198
            llvm::LLVMSetGlobalConstant(gvar, True);
4199
            lcx.ccx.discrims.insert(vid, gvar);
4200 4201
            ret gvar;
        }
4202
        case (some(?llval)) { ret llval; }
4203 4204 4205
    }
}

4206
fn trans_path(&@block_ctxt cx, &ast::path p, &ast::ann ann) -> lval_result {
P
Patrick Walton 已提交
4207
    alt (cx.fcx.lcx.ccx.tcx.def_map.get(ann.id)) {
4208
        case (ast::def_arg(?did)) {
4209
            alt (cx.fcx.llargs.find(did)) {
4210
                case (none) {
4211 4212
                    assert (cx.fcx.llupvars.contains_key(did));
                    ret lval_mem(cx, cx.fcx.llupvars.get(did));
G
Graydon Hoare 已提交
4213
                }
4214
                case (some(?llval)) { ret lval_mem(cx, llval); }
4215 4216
            }
        }
4217
        case (ast::def_local(?did)) {
4218
            alt (cx.fcx.lllocals.find(did)) {
4219
                case (none) {
4220 4221
                    assert (cx.fcx.llupvars.contains_key(did));
                    ret lval_mem(cx, cx.fcx.llupvars.get(did));
4222
                }
4223
                case (some(?llval)) { ret lval_mem(cx, llval); }
4224 4225
            }
        }
4226
        case (ast::def_binding(?did)) {
4227 4228 4229
            assert (cx.fcx.lllocals.contains_key(did));
            ret lval_mem(cx, cx.fcx.lllocals.get(did));
        }
4230
        case (ast::def_obj_field(?did)) {
4231 4232 4233
            assert (cx.fcx.llobjfields.contains_key(did));
            ret lval_mem(cx, cx.fcx.llobjfields.get(did));
        }
4234
        case (ast::def_fn(?did)) {
4235
            auto tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, did);
4236 4237
            ret lval_generic_fn(cx, tyt, did, ann);
        }
4238
        case (ast::def_obj(?did)) {
4239
            auto tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, did);
4240 4241
            ret lval_generic_fn(cx, tyt, did, ann);
        }
4242
        case (ast::def_variant(?tid, ?vid)) {
4243
            auto v_tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, vid);
4244
            alt (ty::struct(cx.fcx.lcx.ccx.tcx, v_tyt._1)) {
4245
                case (ty::ty_fn(_, _, _, _, _)) {
4246
                    // N-ary variant.
4247

4248
                    ret lval_generic_fn(cx, v_tyt, vid, ann);
4249
                }
4250 4251
                case (_) {
                    // Nullary variant.
4252

4253 4254 4255 4256 4257 4258 4259
                    auto tag_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
                    auto lldiscrim_gv =
                        lookup_discriminant(cx.fcx.lcx, tid, vid);
                    auto lldiscrim = cx.build.Load(lldiscrim_gv);
                    auto alloc_result = alloc_ty(cx, tag_ty);
                    auto lltagblob = alloc_result.val;
                    auto lltagty;
4260 4261
                    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, tag_ty))
                       {
4262 4263
                        lltagty = T_opaque_tag(cx.fcx.lcx.ccx.tn);
                    } else {
4264
                        lltagty = type_of(cx.fcx.lcx.ccx, p.span, tag_ty);
4265
                    }
4266 4267 4268 4269 4270 4271 4272
                    auto lltagptr =
                        alloc_result.bcx.build.PointerCast(lltagblob,
                                                           T_ptr(lltagty));
                    auto lldiscrimptr =
                        alloc_result.bcx.build.GEP(lltagptr,
                                                   [C_int(0), C_int(0)]);
                    alloc_result.bcx.build.Store(lldiscrim, lldiscrimptr);
4273
                    ret lval_val(alloc_result.bcx, lltagptr);
G
Graydon Hoare 已提交
4274 4275 4276
                }
            }
        }
4277
        case (ast::def_const(?did)) {
4278
            // TODO: externals
4279

4280 4281 4282
            assert (cx.fcx.lcx.ccx.consts.contains_key(did));
            ret lval_mem(cx, cx.fcx.lcx.ccx.consts.get(did));
        }
4283
        case (ast::def_native_fn(?did)) {
4284
            auto tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, did);
4285 4286 4287
            ret lval_generic_fn(cx, tyt, did, ann);
        }
        case (_) {
4288
            cx.fcx.lcx.ccx.sess.span_unimpl(cx.sp, "def variant in trans");
4289 4290 4291 4292
        }
    }
}

4293
fn trans_field(&@block_ctxt cx, &span sp, ValueRef v, &ty::t t0,
4294
               &ast::ident field, &ast::ann ann) -> lval_result {
4295
    auto r = autoderef(cx, v, t0);
4296
    auto t = autoderefed_ty(cx.fcx.lcx.ccx, t0);
4297 4298 4299
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
        case (ty::ty_tup(_)) {
            let uint ix = ty::field_num(cx.fcx.lcx.ccx.sess, sp, field);
4300
            auto v = GEP_tup_like(r.bcx, t, r.val, [0, ix as int]);
4301
            ret lval_mem(v.bcx, v.val);
4302
        }
4303
        case (ty::ty_rec(?fields)) {
4304 4305
            let uint ix =
                ty::field_idx(cx.fcx.lcx.ccx.sess, sp, field, fields);
4306
            auto v = GEP_tup_like(r.bcx, t, r.val, [0, ix as int]);
4307
            ret lval_mem(v.bcx, v.val);
4308
        }
4309
        case (ty::ty_obj(?methods)) {
4310 4311 4312 4313 4314
            let uint ix =
                ty::method_idx(cx.fcx.lcx.ccx.sess, sp, field, methods);
            auto vtbl =
                r.bcx.build.GEP(r.val,
                                [C_int(0), C_int(abi::obj_field_vtbl)]);
4315
            vtbl = r.bcx.build.Load(vtbl);
4316
            // +1 because slot #0 contains the destructor
4317

4318
            auto v = r.bcx.build.GEP(vtbl, [C_int(0), C_int(ix + 1u as int)]);
4319
            auto lvo = lval_mem(r.bcx, v);
4320 4321 4322
            let ty::t fn_ty =
                ty::method_ty_to_fn_ty(cx.fcx.lcx.ccx.tcx, methods.(ix));
            ret rec(llobj=some[ValueRef](r.val), method_ty=some[ty::t](fn_ty)
4323
                    with lvo);
4324
        }
4325 4326 4327
        case (_) {
            cx.fcx.lcx.ccx.sess.unimpl("field variant in trans_field");
        }
4328 4329 4330
    }
}

4331 4332
fn trans_index(&@block_ctxt cx, &span sp, &@ast::expr base, &@ast::expr idx,
               &ast::ann ann) -> lval_result {
4333
    // Is this an interior vector?
4334

4335 4336
    auto base_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, base);
    auto base_ty_no_boxes = ty::strip_boxes(cx.fcx.lcx.ccx.tcx, base_ty);
4337 4338
    auto is_interior =
        ty::sequence_is_interior(cx.fcx.lcx.ccx.tcx, base_ty_no_boxes);
G
Graydon Hoare 已提交
4339
    auto lv = trans_expr(cx, base);
4340
    lv = autoderef(lv.bcx, lv.val, base_ty);
G
Graydon Hoare 已提交
4341 4342
    auto ix = trans_expr(lv.bcx, idx);
    auto v = lv.val;
4343
    auto bcx = ix.bcx;
4344
    // Cast to an LLVM integer. Rust is less strict than LLVM in this regard.
4345

4346
    auto ix_val;
4347 4348
    auto ix_size = llsize_of_real(cx.fcx.lcx.ccx, val_ty(ix.val));
    auto int_size = llsize_of_real(cx.fcx.lcx.ccx, T_int());
4349 4350 4351 4352
    if (ix_size < int_size) {
        ix_val = bcx.build.ZExt(ix.val, T_int());
    } else if (ix_size > int_size) {
        ix_val = bcx.build.Trunc(ix.val, T_int());
4353
    } else { ix_val = ix.val; }
4354
    auto unit_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
4355
    auto unit_sz = size_of(bcx, unit_ty);
4356
    bcx = unit_sz.bcx;
4357
    maybe_name_value(cx.fcx.lcx.ccx, unit_sz.val, "unit_sz");
4358
    auto scaled_ix = bcx.build.Mul(ix_val, unit_sz.val);
4359
    maybe_name_value(cx.fcx.lcx.ccx, scaled_ix, "scaled_ix");
4360 4361 4362 4363 4364
    auto interior_len_and_data;
    if (is_interior) {
        auto rslt = get_ivec_len_and_data(bcx, v, unit_ty);
        interior_len_and_data = some(tup(rslt._0, rslt._1));
        bcx = rslt._2;
4365
    } else { interior_len_and_data = none; }
4366 4367 4368 4369 4370 4371 4372 4373
    auto lim;
    alt (interior_len_and_data) {
        case (some(?lad)) { lim = lad._0; }
        case (none) {
            lim = bcx.build.GEP(v, [C_int(0), C_int(abi::vec_elt_fill)]);
            lim = bcx.build.Load(lim);
        }
    }
4374
    auto bounds_check = bcx.build.ICmp(lib::llvm::LLVMIntULT, scaled_ix, lim);
4375 4376 4377
    auto fail_cx = new_sub_block_ctxt(bcx, "fail");
    auto next_cx = new_sub_block_ctxt(bcx, "next");
    bcx.build.CondBr(bounds_check, next_cx.llbb, fail_cx.llbb);
4378 4379
    // fail: bad bounds check.

4380 4381
    auto fail_res =
        trans_fail(fail_cx, some[common::span](sp), "bounds check");
4382 4383 4384 4385
    auto body;
    alt (interior_len_and_data) {
        case (some(?lad)) { body = lad._1; }
        case (none) {
4386 4387 4388 4389
            body =
                next_cx.build.GEP(v,
                                  [C_int(0), C_int(abi::vec_elt_data),
                                   C_int(0)]);
4390 4391
        }
    }
4392
    auto elt;
4393
    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, unit_ty)) {
4394 4395
        body = next_cx.build.PointerCast(body, T_ptr(T_i8()));
        elt = next_cx.build.GEP(body, [scaled_ix]);
4396
    } else {
4397
        elt = next_cx.build.GEP(body, [ix_val]);
4398
        // We're crossing a box boundary here, so we may need to pointer cast.
4399

4400
        auto llunitty = type_of(next_cx.fcx.lcx.ccx, sp, unit_ty);
4401
        elt = next_cx.build.PointerCast(elt, T_ptr(llunitty));
4402
    }
4403
    ret lval_mem(next_cx, elt);
4404 4405
}

4406

4407 4408 4409
// 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).
4410
fn trans_lval(&@block_ctxt cx, &@ast::expr e) -> lval_result {
4411
    alt (e.node) {
4412
        case (ast::expr_path(?p, ?ann)) { ret trans_path(cx, p, ann); }
4413
        case (ast::expr_field(?base, ?ident, ?ann)) {
4414
            auto r = trans_expr(cx, base);
4415
            auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, base);
4416
            ret trans_field(r.bcx, e.span, r.val, t, ident, ann);
4417
        }
4418
        case (ast::expr_index(?base, ?idx, ?ann)) {
4419 4420
            ret trans_index(cx, e.span, base, idx, ann);
        }
4421 4422
        case (ast::expr_unary(?unop, ?base, ?ann)) {
            assert (unop == ast::deref);
4423
            auto sub = trans_expr(cx, base);
4424 4425 4426
            auto val =
                sub.bcx.build.GEP(sub.val,
                                  [C_int(0), C_int(abi::box_rc_field_body)]);
4427 4428
            ret lval_mem(sub.bcx, val);
        }
4429
        case (ast::expr_self_method(?ident, ?ann)) {
4430
            alt ({ cx.fcx.llself }) {
L
Lindsey Kuper 已提交
4431
                case (some(?pair)) {
4432 4433
                    auto r = pair.v;
                    auto t = pair.t;
4434 4435 4436 4437 4438
                    ret trans_field(cx, e.span, r, t, ident, ann);
                }
                case (_) {
                    // Shouldn't happen.

4439 4440 4441 4442
                    cx.fcx.lcx.ccx.sess.bug("trans_lval called on "
                                            + "expr_self_method in a context"
                                            + "without llself");
                }
4443 4444
            }
        }
4445
        case (_) {
4446 4447 4448 4449 4450
            ret rec(res=trans_expr(cx, e),
                    is_mem=false,
                    generic=none,
                    llobj=none,
                    method_ty=none);
4451
        }
G
Graydon Hoare 已提交
4452 4453 4454
    }
}

G
Graydon Hoare 已提交
4455
fn int_cast(&@block_ctxt bcx, TypeRef lldsttype, TypeRef llsrctype,
4456
            ValueRef llsrc, bool signed) -> ValueRef {
4457 4458
    if (llvm::LLVMGetIntTypeWidth(lldsttype) >
            llvm::LLVMGetIntTypeWidth(llsrctype)) {
4459 4460
        if (signed) {
            // Widening signed cast.
4461

4462 4463 4464
            ret bcx.build.SExtOrBitCast(llsrc, lldsttype);
        }
        // Widening unsigned cast.
4465

4466 4467 4468 4469 4470
        ret bcx.build.ZExtOrBitCast(llsrc, lldsttype);
    }
    ret bcx.build.TruncOrBitCast(llsrc, lldsttype);
}

4471
fn trans_cast(&@block_ctxt cx, &@ast::expr e, &ast::ann ann) -> result {
4472 4473
    auto e_res = trans_expr(cx, e);
    auto llsrctype = val_ty(e_res.val);
4474
    auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
4475
    auto lldsttype = type_of(cx.fcx.lcx.ccx, e.span, t);
4476
    if (!ty::type_is_fp(cx.fcx.lcx.ccx.tcx, t)) {
4477

4478
        // TODO: native-to-native casts
4479
        if (ty::type_is_native(cx.fcx.lcx.ccx.tcx,
4480 4481 4482 4483
                               ty::expr_ty(cx.fcx.lcx.ccx.tcx, e))) {
            e_res =
                res(e_res.bcx,
                    e_res.bcx.build.PtrToInt(e_res.val, lldsttype));
4484
        } else if (ty::type_is_native(cx.fcx.lcx.ccx.tcx, t)) {
4485 4486 4487
            e_res =
                res(e_res.bcx,
                    e_res.bcx.build.IntToPtr(e_res.val, lldsttype));
4488
        } else {
4489 4490 4491 4492
            e_res =
                res(e_res.bcx,
                    int_cast(e_res.bcx, lldsttype, llsrctype, e_res.val,
                             ty::type_is_signed(cx.fcx.lcx.ccx.tcx, t)));
4493
        }
4494
    } else { cx.fcx.lcx.ccx.sess.unimpl("fp cast"); }
4495 4496 4497
    ret e_res;
}

4498 4499 4500
fn trans_bind_thunk(&@local_ctxt cx, &span sp, &ty::t incoming_fty,
                    &ty::t outgoing_fty, &vec[option::t[@ast::expr]] args,
                    &ty::t closure_ty, &vec[ty::t] bound_tys,
4501
                    uint ty_param_count) -> ValueRef {
4502
    // Construct a thunk-call with signature incoming_fty, and that copies
4503
    // args forward into a call to outgoing_fty:
4504

4505 4506 4507 4508 4509 4510
    let str s =
        mangle_internal_name_by_path_and_seq(cx.ccx, cx.path, "thunk");
    let TypeRef llthunk_ty =
        get_pair_fn_ty(type_of(cx.ccx, sp, incoming_fty));
    let ValueRef llthunk =
        decl_internal_fastcall_fn(cx.ccx.llmod, s, llthunk_ty);
4511
    auto fcx = new_fn_ctxt(cx, sp, llthunk);
4512
    auto bcx = new_top_block_ctxt(fcx);
4513
    auto lltop = bcx.llbb;
4514
    auto llclosure_ptr_ty =
4515
        type_of(cx.ccx, sp, ty::mk_imm_box(cx.ccx.tcx, closure_ty));
4516
    auto llclosure = bcx.build.PointerCast(fcx.llenv, llclosure_ptr_ty);
4517 4518 4519
    auto lltarget =
        GEP_tup_like(bcx, closure_ty, llclosure,
                     [0, abi::box_rc_field_body, abi::closure_elt_target]);
4520
    bcx = lltarget.bcx;
4521 4522
    auto lltargetclosure =
        bcx.build.GEP(lltarget.val, [C_int(0), C_int(abi::fn_field_box)]);
4523
    lltargetclosure = bcx.build.Load(lltargetclosure);
4524 4525
    auto outgoing_ret_ty = ty::ty_fn_ret(cx.ccx.tcx, outgoing_fty);
    auto outgoing_args = ty::ty_fn_args(cx.ccx.tcx, outgoing_fty);
4526
    auto llretptr = fcx.llretptr;
4527
    if (ty::type_has_dynamic_size(cx.ccx.tcx, outgoing_ret_ty)) {
4528
        llretptr = bcx.build.PointerCast(llretptr, T_typaram_ptr(cx.ccx.tn));
4529
    }
4530
    let vec[ValueRef] llargs = [llretptr, fcx.lltaskptr, lltargetclosure];
4531
    // Copy in the type parameters.
4532

4533 4534 4535
    let uint i = 0u;
    while (i < ty_param_count) {
        auto lltyparam_ptr =
4536
            GEP_tup_like(bcx, closure_ty, llclosure,
4537 4538
                         [0, abi::box_rc_field_body,
                          abi::closure_elt_ty_params, i as int]);
4539
        bcx = lltyparam_ptr.bcx;
4540
        auto td = bcx.build.Load(lltyparam_ptr.val);
4541 4542
        llargs += [td];
        fcx.lltydescs += [td];
4543 4544
        i += 1u;
    }
4545
    let uint a = 3u; // retptr, task ptr, env come first
4546

4547
    let int b = 0;
4548
    let uint outgoing_arg_index = 0u;
4549
    let vec[TypeRef] llout_arg_tys =
4550
        type_of_explicit_args(cx.ccx, sp, outgoing_args);
4551
    for (option::t[@ast::expr] arg in args) {
4552 4553
        auto out_arg = outgoing_args.(outgoing_arg_index);
        auto llout_arg_ty = llout_arg_tys.(outgoing_arg_index);
4554
        alt (arg) {
4555 4556 4557 4558
            case (
                 // Arg provided at binding time; thunk copies it from
                 // closure.
                 some(?e)) {
4559
                auto e_ty = ty::expr_ty(cx.ccx.tcx, e);
4560 4561
                auto bound_arg =
                    GEP_tup_like(bcx, closure_ty, llclosure,
4562 4563
                                 [0, abi::box_rc_field_body,
                                  abi::closure_elt_bindings, b]);
4564
                bcx = bound_arg.bcx;
4565
                auto val = bound_arg.val;
4566
                if (out_arg.mode == ty::mo_val) {
4567 4568 4569 4570 4571 4572 4573
                    if (type_is_immediate(cx.ccx, e_ty)) {
                        val = bcx.build.Load(val);
                        bcx = take_ty(bcx, val, e_ty).bcx;
                    } else {
                        bcx = take_ty(bcx, val, e_ty).bcx;
                        val = bcx.build.Load(val);
                    }
4574
                } else if (ty::type_contains_params(cx.ccx.tcx, out_arg.ty)) {
4575
                    assert (out_arg.mode != ty::mo_val);
4576 4577
                    val = bcx.build.PointerCast(val, llout_arg_ty);
                }
4578
                llargs += [val];
4579 4580
                b += 1;
            }
4581 4582 4583
            case (
                 // Arg will be provided when the thunk is invoked.
                 none) {
4584 4585
                let ValueRef passed_arg = llvm::LLVMGetParam(llthunk, a);
                if (ty::type_contains_params(cx.ccx.tcx, out_arg.ty)) {
4586
                    assert (out_arg.mode != ty::mo_val);
4587 4588
                    passed_arg =
                        bcx.build.PointerCast(passed_arg, llout_arg_ty);
4589
                }
4590
                llargs += [passed_arg];
4591 4592 4593
                a += 1u;
            }
        }
4594
        outgoing_arg_index += 1u;
4595 4596
    }
    // FIXME: turn this call + ret into a tail call.
4597

4598 4599
    auto lltargetfn =
        bcx.build.GEP(lltarget.val, [C_int(0), C_int(abi::fn_field_code)]);
4600 4601 4602
    // Cast the outgoing function to the appropriate type (see the comments in
    // trans_bind below for why this is necessary).

4603 4604 4605 4606 4607
    auto lltargetty =
        type_of_fn(bcx.fcx.lcx.ccx, sp,
                   ty::ty_fn_proto(bcx.fcx.lcx.ccx.tcx, outgoing_fty),
                   outgoing_args, outgoing_ret_ty, ty_param_count);
    lltargetfn = bcx.build.PointerCast(lltargetfn, T_ptr(T_ptr(lltargetty)));
4608 4609
    lltargetfn = bcx.build.Load(lltargetfn);
    auto r = bcx.build.FastCall(lltargetfn, llargs);
4610
    bcx.build.RetVoid();
4611
    finish_fn(fcx, lltop);
4612 4613 4614
    ret llthunk;
}

4615
fn trans_bind(&@block_ctxt cx, &@ast::expr f,
4616
              &vec[option::t[@ast::expr]] args, &ast::ann ann) -> result {
4617 4618
    auto f_res = trans_lval(cx, f);
    if (f_res.is_mem) {
4619
        cx.fcx.lcx.ccx.sess.unimpl("re-binding existing function");
4620
    } else {
4621
        let vec[@ast::expr] bound = [];
4622
        for (option::t[@ast::expr] argopt in args) {
4623
            alt (argopt) {
4624 4625
                case (none) { }
                case (some(?e)) { vec::push[@ast::expr](bound, e); }
4626 4627
            }
        }
4628
        // Figure out which tydescs we need to pass, if any.
4629

4630
        let ty::t outgoing_fty;
B
Brian Anderson 已提交
4631
        let vec[ValueRef] lltydescs;
4632
        alt (f_res.generic) {
4633
            case (none) {
4634
                outgoing_fty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, f);
4635
                lltydescs = [];
4636
            }
4637
            case (some(?ginfo)) {
4638
                lazily_emit_all_generic_info_tydesc_glues(cx, ginfo);
4639 4640 4641 4642
                outgoing_fty = ginfo.item_type;
                lltydescs = ginfo.tydescs;
            }
        }
4643 4644
        auto ty_param_count = vec::len[ValueRef](lltydescs);
        if (vec::len[@ast::expr](bound) == 0u && ty_param_count == 0u) {
4645
            // Trivial 'binding': just return the static pair-ptr.
4646

4647 4648 4649
            ret f_res.res;
        } else {
            auto bcx = f_res.res.bcx;
4650
            auto pair_t = node_type(cx.fcx.lcx.ccx, cx.sp, ann);
4651
            auto pair_v = alloca(bcx, pair_t);
4652
            // Translate the bound expressions.
4653

4654 4655
            let vec[ty::t] bound_tys = [];
            let vec[ValueRef] bound_vals = [];
4656
            auto i = 0u;
4657
            for (@ast::expr e in bound) {
4658 4659
                auto arg = trans_expr(bcx, e);
                bcx = arg.bcx;
4660 4661
                vec::push[ValueRef](bound_vals, arg.val);
                vec::push[ty::t](bound_tys,
4662
                                 ty::expr_ty(cx.fcx.lcx.ccx.tcx, e));
4663
                i += 1u;
4664 4665
            }
            // Synthesize a closure type.
4666

4667 4668
            let ty::t bindings_ty =
                ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, bound_tys);
4669
            // NB: keep this in sync with T_closure_ptr; we're making
4670
            // a ty::t structure that has the same "shape" as the LLVM type
4671 4672
            // it constructs.

4673
            let ty::t tydesc_ty = ty::mk_type(cx.fcx.lcx.ccx.tcx);
4674
            let vec[ty::t] captured_tys =
4675
                vec::init_elt[ty::t](tydesc_ty, ty_param_count);
4676
            let vec[ty::t] closure_tys =
4677 4678 4679 4680
                [tydesc_ty, outgoing_fty, bindings_ty,
                 ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, captured_tys)];
            let ty::t closure_ty =
                ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, closure_tys);
4681
            auto r = trans_malloc_boxed(bcx, closure_ty);
4682 4683
            auto box = r.val;
            bcx = r.bcx;
4684
            auto rc =
4685
                bcx.build.GEP(box,
4686 4687 4688
                              [C_int(0), C_int(abi::box_rc_field_refcnt)]);
            auto closure =
                bcx.build.GEP(box, [C_int(0), C_int(abi::box_rc_field_body)]);
4689 4690
            bcx.build.Store(C_int(1), rc);
            // Store bindings tydesc.
4691

4692 4693
            auto bound_tydesc =
                bcx.build.GEP(closure,
4694
                              [C_int(0), C_int(abi::closure_elt_tydesc)]);
4695 4696 4697
            auto ti = none[@tydesc_info];
            auto bindings_tydesc = get_tydesc(bcx, bindings_ty, true, ti);
            lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
4698
            lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
4699 4700
            bcx = bindings_tydesc.bcx;
            bcx.build.Store(bindings_tydesc.val, bound_tydesc);
4701 4702 4703 4704 4705 4706 4707
            // Determine the LLVM type for the outgoing function type. This
            // may be different from the type returned by trans_malloc_boxed()
            // since we have more information than that function does;
            // specifically, we know how many type descriptors the outgoing
            // function has, which type_of() doesn't, as only we know which
            // item the function refers to.

4708 4709 4710 4711 4712 4713 4714
            auto llfnty =
                type_of_fn(bcx.fcx.lcx.ccx, cx.sp,
                           ty::ty_fn_proto(bcx.fcx.lcx.ccx.tcx, outgoing_fty),
                           ty::ty_fn_args(bcx.fcx.lcx.ccx.tcx, outgoing_fty),
                           ty::ty_fn_ret(bcx.fcx.lcx.ccx.tcx, outgoing_fty),
                           ty_param_count);
            auto llclosurety = T_ptr(T_fn_pair(bcx.fcx.lcx.ccx.tn, llfnty));
4715
            // Store thunk-target.
4716

4717
            auto bound_target =
4718
                bcx.build.GEP(closure,
4719
                              [C_int(0), C_int(abi::closure_elt_target)]);
4720
            auto src = bcx.build.Load(f_res.res.val);
4721
            bound_target = bcx.build.PointerCast(bound_target, llclosurety);
4722
            bcx.build.Store(src, bound_target);
4723
            // Copy expr values into boxed bindings.
4724

4725
            i = 0u;
4726 4727
            auto bindings =
                bcx.build.GEP(closure,
4728
                              [C_int(0), C_int(abi::closure_elt_bindings)]);
4729
            for (ValueRef v in bound_vals) {
4730 4731
                auto bound =
                    bcx.build.GEP(bindings, [C_int(0), C_int(i as int)]);
4732
                bcx = copy_val(bcx, INIT, bound, v, bound_tys.(i)).bcx;
4733 4734 4735 4736
                i += 1u;
            }
            // If necessary, copy tydescs describing type parameters into the
            // appropriate slot in the closure.
4737

4738
            alt (f_res.generic) {
4739
                case (none) {/* nothing to do */ }
4740
                case (some(?ginfo)) {
4741
                    lazily_emit_all_generic_info_tydesc_glues(cx, ginfo);
4742 4743
                    auto ty_params_slot =
                        bcx.build.GEP(closure,
4744
                                      [C_int(0),
4745
                                       C_int(abi::closure_elt_ty_params)]);
4746 4747
                    auto i = 0;
                    for (ValueRef td in ginfo.tydescs) {
4748 4749 4750
                        auto ty_param_slot =
                            bcx.build.GEP(ty_params_slot,
                                          [C_int(0), C_int(i)]);
4751 4752 4753
                        bcx.build.Store(td, ty_param_slot);
                        i += 1;
                    }
4754
                    outgoing_fty = ginfo.item_type;
4755
                }
4756
            }
4757
            // Make thunk and store thunk-ptr in outer pair's code slot.
4758

4759 4760
            auto pair_code =
                bcx.build.GEP(pair_v, [C_int(0), C_int(abi::fn_field_code)]);
4761
            let ty::t pair_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
4762
            let ValueRef llthunk =
4763
                trans_bind_thunk(cx.fcx.lcx, cx.sp, pair_ty, outgoing_fty,
4764
                                 args, closure_ty, bound_tys, ty_param_count);
4765 4766
            bcx.build.Store(llthunk, pair_code);
            // Store box ptr in outer pair's box slot.
4767

4768 4769 4770 4771 4772 4773
            auto tn = bcx.fcx.lcx.ccx.tn;
            auto pair_box =
                bcx.build.GEP(pair_v, [C_int(0), C_int(abi::fn_field_box)]);
            bcx.build.Store(bcx.build.PointerCast(box,
                                                  T_opaque_closure_ptr(tn)),
                            pair_box);
4774
            find_scope_cx(cx).cleanups +=
4775
                [clean(bind drop_slot(_, pair_v, pair_ty))];
4776 4777
            ret res(bcx, pair_v);
        }
4778 4779 4780
    }
}

4781
fn trans_arg_expr(&@block_ctxt cx, &ty::arg arg, TypeRef lldestty0,
4782
                  &@ast::expr e) -> result {
4783 4784
    auto val;
    auto bcx = cx;
4785
    auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
4786
    if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, e_ty)) {
4787 4788 4789
        auto re = trans_expr(bcx, e);
        val = re.val;
        bcx = re.bcx;
4790
    } else if (arg.mode != ty::mo_val) {
4791
        let lval_result lv;
4792
        if (ty::is_lval(e)) {
4793 4794 4795 4796 4797
            lv = trans_lval(bcx, e);
        } else {
            auto r = trans_expr(bcx, e);
            if (type_is_immediate(cx.fcx.lcx.ccx, e_ty)) {
                lv = lval_val(r.bcx, r.val);
4798
            } else { lv = lval_mem(r.bcx, r.val); }
4799 4800 4801 4802 4803 4804 4805
        }
        bcx = lv.res.bcx;
        if (lv.is_mem) {
            val = lv.res.val;
        } else {
            // Non-mem but we're trying to alias; synthesize an
            // alloca, spill to it and pass its address.
4806

4807 4808
            val = do_spill(lv.res.bcx, lv.res.val);
        }
4809 4810
    } else { auto re = trans_expr(bcx, e); val = re.val; bcx = re.bcx; }
    if (arg.mode == ty::mo_val) { bcx = take_ty(bcx, val, e_ty).bcx; }
4811 4812 4813 4814 4815
    if (ty::type_is_bot(cx.fcx.lcx.ccx.tcx, e_ty)) {
        // For values of type _|_, we generate an
        // "undef" value, as such a value should never
        // be inspected. It's important for the value
        // to have type lldestty0 (the callee's expected type).
4816

4817
        val = llvm::LLVMGetUndef(lldestty0);
4818
    } else if (ty::type_contains_params(cx.fcx.lcx.ccx.tcx, arg.ty)) {
4819
        auto lldestty = lldestty0;
4820
        if (arg.mode == ty::mo_val) {
4821

4822
            // FIXME: we'd prefer to use &&, but rustboot doesn't like it
4823
            if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, e_ty)) {
4824 4825 4826 4827 4828
                lldestty = T_ptr(lldestty);
            }
        }
        val = bcx.build.PointerCast(val, lldestty);
    }
4829
    if (arg.mode == ty::mo_val) {
4830

4831
        // FIXME: we'd prefer to use &&, but rustboot doesn't like it
4832
        if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, e_ty)) {
4833 4834
            // Until here we've been treating structures by pointer;
            // we are now passing it as an arg, so need to load it.
4835

4836 4837 4838 4839 4840 4841
            val = bcx.build.Load(val);
        }
    }
    ret res(bcx, val);
}

4842

4843 4844 4845 4846 4847 4848
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args
4849 4850 4851 4852
fn trans_args(&@block_ctxt cx, ValueRef llenv, &option::t[ValueRef] llobj,
              &option::t[generic_info] gen, &option::t[ValueRef] lliterbody,
              &vec[@ast::expr] es, &ty::t fn_ty) ->
   tup(@block_ctxt, vec[ValueRef], ValueRef) {
4853
    let vec[ty::arg] args = ty::ty_fn_args(cx.fcx.lcx.ccx.tcx, fn_ty);
4854 4855
    let vec[ValueRef] llargs = [];
    let vec[ValueRef] lltydescs = [];
4856 4857
    let @block_ctxt bcx = cx;
    // Arg 0: Output pointer.
4858

4859
    auto retty = ty::ty_fn_ret(cx.fcx.lcx.ccx.tcx, fn_ty);
4860 4861 4862
    auto llretslot_res = alloc_ty(bcx, retty);
    bcx = llretslot_res.bcx;
    auto llretslot = llretslot_res.val;
4863
    alt (gen) {
4864
        case (some(?g)) {
4865
            lazily_emit_all_generic_info_tydesc_glues(cx, g);
4866
            lltydescs = g.tydescs;
4867 4868
            args = ty::ty_fn_args(cx.fcx.lcx.ccx.tcx, g.item_type);
            retty = ty::ty_fn_ret(cx.fcx.lcx.ccx.tcx, g.item_type);
4869
        }
4870
        case (_) { }
4871
    }
4872
    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, retty)) {
4873 4874 4875
        llargs +=
            [bcx.build.PointerCast(llretslot,
                                   T_typaram_ptr(cx.fcx.lcx.ccx.tn))];
4876
    } else if (ty::type_contains_params(cx.fcx.lcx.ccx.tcx, retty)) {
4877 4878 4879 4880 4881
        // It's possible that the callee has some generic-ness somewhere in
        // its return value -- say a method signature within an obj or a fn
        // type deep in a structure -- which the caller has a concrete view
        // of. If so, cast the caller's view of the restlot to the callee's
        // view, for the sake of making a type-compatible call.
4882

4883
        llargs +=
4884
            [cx.build.PointerCast(llretslot,
4885 4886 4887
                                  T_ptr(type_of(bcx.fcx.lcx.ccx, bcx.sp,
                                                retty)))];
    } else { llargs += [llretslot]; }
4888
    // Arg 1: task pointer.
4889

4890
    llargs += [bcx.fcx.lltaskptr];
4891
    // Arg 2: Env (closure-bindings / self-obj)
4892

4893
    alt (llobj) {
4894
        case (some(?ob)) {
4895 4896 4897
            // Every object is always found in memory,
            // and not-yet-loaded (as part of an lval x.y
            // doted method-call).
4898

4899
            llargs += [bcx.build.Load(ob)];
4900
        }
4901
        case (_) { llargs += [llenv]; }
4902 4903 4904
    }
    // Args >3: ty_params ...

4905
    llargs += lltydescs;
4906
    // ... then possibly an lliterbody argument.
4907

4908
    alt (lliterbody) {
4909 4910
        case (none) { }
        case (some(?lli)) { llargs += [lli]; }
4911
    }
4912
    // ... then explicit args.
4913 4914 4915 4916 4917

    // First we figure out the caller's view of the types of the arguments.
    // This will be needed if this is a generic call, because the callee has
    // to cast her view of the arguments to the caller's view.

4918
    auto arg_tys = type_of_explicit_args(cx.fcx.lcx.ccx, cx.sp, args);
4919
    auto i = 0u;
4920
    for (@ast::expr e in es) {
4921 4922
        auto r = trans_arg_expr(bcx, args.(i), arg_tys.(i), e);
        bcx = r.bcx;
4923
        llargs += [r.val];
4924 4925 4926 4927 4928
        i += 1u;
    }
    ret tup(bcx, llargs, llretslot);
}

4929 4930
fn trans_call(&@block_ctxt cx, &@ast::expr f, &option::t[ValueRef] lliterbody,
              &vec[@ast::expr] args, &ast::ann ann) -> result {
4931 4932 4933 4934
    // NB: 'f' isn't necessarily a function; it might be an entire self-call
    // expression because of the hack that allows us to process self-calls
    // with trans_call.

4935
    auto f_res = trans_lval(cx, f);
4936
    auto faddr = f_res.res.val;
4937
    auto llenv = C_null(T_opaque_closure_ptr(cx.fcx.lcx.ccx.tn));
4938
    alt (f_res.llobj) {
4939
        case (some(_)) {
4940
            // It's a vtbl entry.
4941

4942 4943
            faddr = f_res.res.bcx.build.Load(faddr);
        }
4944
        case (none) {
4945
            // It's a closure.
4946

4947
            auto bcx = f_res.res.bcx;
4948
            auto pair = faddr;
4949 4950
            faddr =
                bcx.build.GEP(pair, [C_int(0), C_int(abi::fn_field_code)]);
4951
            faddr = bcx.build.Load(faddr);
4952 4953
            auto llclosure =
                bcx.build.GEP(pair, [C_int(0), C_int(abi::fn_field_box)]);
4954
            llenv = bcx.build.Load(llclosure);
4955
        }
4956
    }
4957
    let ty::t fn_ty;
4958
    alt (f_res.method_ty) {
4959
        case (some(?meth)) {
4960
            // self-call
4961

4962
            fn_ty = meth;
4963
        }
4964
        case (_) { fn_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, f); }
4965
    }
4966
    auto ret_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann);
4967 4968 4969
    auto args_res =
        trans_args(f_res.res.bcx, llenv, f_res.llobj, f_res.generic,
                   lliterbody, args, fn_ty);
4970 4971 4972 4973
    auto bcx = args_res._0;
    auto llargs = args_res._1;
    auto llretslot = args_res._2;
    /*
4974
    log "calling: " + val_str(cx.fcx.lcx.ccx.tn, faddr);
4975
    
4976
    for (ValueRef arg in llargs) {
4977
        log "arg: " + val_str(cx.fcx.lcx.ccx.tn, arg);
4978
    }
4979 4980 4981 4982
    */

    bcx.build.FastCall(faddr, llargs);
    auto retval = C_nil();
4983
    alt (lliterbody) {
4984
        case (none) {
4985
            if (!ty::type_is_nil(cx.fcx.lcx.ccx.tcx, ret_ty)) {
4986 4987 4988 4989
                retval = load_if_immediate(bcx, llretslot, ret_ty);
                // Retval doesn't correspond to anything really tangible in
                // the frame, but it's a ref all the same, so we put a note
                // here to drop it when we're done in this scope.
4990

4991
                find_scope_cx(cx).cleanups +=
4992
                    [clean(bind drop_ty(_, retval, ret_ty))];
4993 4994
            }
        }
4995
        case (some(_)) {
4996 4997 4998
            // If there was an lliterbody, it means we were calling an
            // iter, and we are *not* the party using its 'output' value,
            // we should ignore llretslot.
4999

5000
        }
5001 5002 5003 5004
    }
    ret res(bcx, retval);
}

5005
fn trans_tup(&@block_ctxt cx, &vec[ast::elt] elts, &ast::ann ann) -> result {
5006
    auto bcx = cx;
5007
    auto t = node_ann_type(bcx.fcx.lcx.ccx, ann);
5008 5009 5010
    auto tup_res = alloc_ty(bcx, t);
    auto tup_val = tup_res.val;
    bcx = tup_res.bcx;
5011
    find_scope_cx(cx).cleanups += [clean(bind drop_ty(_, tup_val, t))];
G
Graydon Hoare 已提交
5012
    let int i = 0;
5013
    for (ast::elt e in elts) {
5014
        auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e.expr);
5015 5016
        auto src_res = trans_expr(bcx, e.expr);
        bcx = src_res.bcx;
5017
        auto dst_res = GEP_tup_like(bcx, t, tup_val, [0, i]);
5018
        bcx = dst_res.bcx;
5019
        bcx = copy_val(src_res.bcx, INIT, dst_res.val, src_res.val, e_ty).bcx;
G
Graydon Hoare 已提交
5020 5021
        i += 1;
    }
5022
    ret res(bcx, tup_val);
G
Graydon Hoare 已提交
5023 5024
}

5025 5026
fn trans_vec(&@block_ctxt cx, &vec[@ast::expr] args, &ast::ann ann) ->
   result {
5027
    auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
5028
    auto unit_ty = t;
5029
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
5030 5031
        case (ty::ty_vec(?mt)) { unit_ty = mt.ty; }
        case (_) { cx.fcx.lcx.ccx.sess.bug("non-vec type in trans_vec"); }
G
Graydon Hoare 已提交
5032
    }
5033 5034 5035
    auto bcx = cx;
    auto unit_sz = size_of(bcx, unit_ty);
    bcx = unit_sz.bcx;
5036 5037
    auto data_sz =
        bcx.build.Mul(C_int(vec::len[@ast::expr](args) as int), unit_sz.val);
G
Graydon Hoare 已提交
5038
    // FIXME: pass tydesc properly.
5039 5040 5041 5042 5043

    auto vec_val =
        bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.new_vec,
                       [bcx.fcx.lltaskptr, data_sz,
                        C_null(T_ptr(T_tydesc(bcx.fcx.lcx.ccx.tn)))]);
5044
    auto llty = type_of(bcx.fcx.lcx.ccx, bcx.sp, t);
5045
    vec_val = bcx.build.PointerCast(vec_val, llty);
5046 5047
    find_scope_cx(bcx).cleanups += [clean(bind drop_ty(_, vec_val, t))];
    auto body = bcx.build.GEP(vec_val, [C_int(0), C_int(abi::vec_elt_data)]);
5048
    auto pseudo_tup_ty =
5049
        ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx,
5050 5051
                       vec::init_elt[ty::t](unit_ty,
                                            vec::len[@ast::expr](args)));
G
Graydon Hoare 已提交
5052
    let int i = 0;
5053
    for (@ast::expr e in args) {
5054 5055
        auto src_res = trans_expr(bcx, e);
        bcx = src_res.bcx;
5056
        auto dst_res = GEP_tup_like(bcx, pseudo_tup_ty, body, [0, i]);
5057
        bcx = dst_res.bcx;
5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070
        // Cast the destination type to the source type. This is needed to
        // make tags work, for a subtle combination of reasons:
        //
        // (1) "dst_res" above is derived from "body", which is in turn
        //     derived from "vec_val".
        // (2) "vec_val" has the LLVM type "llty".
        // (3) "llty" is the result of calling type_of() on a vector type.
        // (4) For tags, type_of() returns a different type depending on
        //     on whether the tag is behind a box or not. Vector types are
        //     considered boxes.
        // (5) "src_res" is derived from "unit_ty", which is not behind a box.

        auto dst_val;
5071
        if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, unit_ty)) {
5072
            auto llunit_ty = type_of(cx.fcx.lcx.ccx, bcx.sp, unit_ty);
5073
            dst_val = bcx.build.PointerCast(dst_res.val, T_ptr(llunit_ty));
5074
        } else { dst_val = dst_res.val; }
5075
        bcx = copy_val(bcx, INIT, dst_val, src_res.val, unit_ty).bcx;
G
Graydon Hoare 已提交
5076 5077
        i += 1;
    }
5078
    auto fill = bcx.build.GEP(vec_val, [C_int(0), C_int(abi::vec_elt_fill)]);
5079 5080
    bcx.build.Store(data_sz, fill);
    ret res(bcx, vec_val);
G
Graydon Hoare 已提交
5081 5082
}

5083 5084
fn trans_ivec(@block_ctxt bcx, &vec[@ast::expr] args, &ast::ann ann) ->
   result {
5085 5086 5087 5088 5089 5090 5091 5092 5093
    auto typ = node_ann_type(bcx.fcx.lcx.ccx, ann);
    auto unit_ty;
    alt (ty::struct(bcx.fcx.lcx.ccx.tcx, typ)) {
        case (ty::ty_ivec(?mt)) { unit_ty = mt.ty; }
        case (_) { bcx.fcx.lcx.ccx.sess.bug("non-ivec type in trans_ivec"); }
    }
    auto rslt = size_of(bcx, unit_ty);
    auto unit_sz = rslt.val;
    bcx = rslt.bcx;
5094
    auto llalen = bcx.build.Mul(unit_sz, C_uint(abi::ivec_default_length));
5095
    auto llunitty = type_of_or_i8(bcx, unit_ty);
5096 5097
    auto llvecptr;
    if (ty::type_has_dynamic_size(bcx.fcx.lcx.ccx.tcx, unit_ty)) {
5098 5099 5100
        auto array_size = bcx.build.Add(llsize_of(T_opaque_ivec()), llalen);
        llvecptr = array_alloca(bcx, T_i8(), array_size);
        llvecptr = bcx.build.PointerCast(llvecptr, T_ptr(T_opaque_ivec()));
5101
    } else { llvecptr = alloca(bcx, T_ivec(llunitty)); }
5102 5103
    auto lllen = bcx.build.Mul(C_uint(vec::len(args)), unit_sz);
    // Allocate the vector pieces and store length and allocated length.
5104

5105
    auto llfirsteltptr;
5106
    if (vec::len(args) > 0u && vec::len(args) < abi::ivec_default_length) {
5107
        // Interior case.
5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120

        bcx.build.Store(lllen,
                        bcx.build.InBoundsGEP(llvecptr,
                                              [C_int(0),
                                               C_uint(abi::ivec_elt_len)]));
        bcx.build.Store(llalen,
                        bcx.build.InBoundsGEP(llvecptr,
                                              [C_int(0),
                                               C_uint(abi::ivec_elt_alen)]));
        llfirsteltptr =
            bcx.build.InBoundsGEP(llvecptr,
                                  [C_int(0), C_uint(abi::ivec_elt_elems),
                                   C_int(0)]);
5121 5122
    } else {
        // Heap case.
5123 5124 5125 5126 5127 5128


        auto stub_z = [C_int(0), C_uint(abi::ivec_heap_stub_elt_zero)];
        auto stub_a = [C_int(0), C_uint(abi::ivec_heap_stub_elt_alen)];
        auto stub_p = [C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)];

5129 5130
        auto llstubty = T_ivec_heap(llunitty);
        auto llstubptr = bcx.build.PointerCast(llvecptr, T_ptr(llstubty));
5131 5132
        bcx.build.Store(C_int(0),
                        bcx.build.InBoundsGEP(llstubptr, stub_z));
5133
        bcx.build.Store(lllen,
5134
                        bcx.build.InBoundsGEP(llstubptr, stub_a));
5135 5136 5137
        auto llheapty = struct_elt(llstubty, abi::ivec_heap_stub_elt_ptr);
        if (vec::len(args) == 0u) {
            // Null heap pointer indicates a zero-length vector.
5138

5139
            bcx.build.Store(C_null(T_ptr(llheapty)),
5140
                            bcx.build.InBoundsGEP(llstubptr, stub_p));
5141 5142 5143
            llfirsteltptr = C_null(T_ptr(llunitty));
        } else {
            auto llheapsz = bcx.build.Add(llsize_of(llheapty), lllen);
5144
            rslt = trans_raw_malloc(bcx, T_ptr(llheapty), llheapsz);
5145 5146
            bcx = rslt.bcx;
            auto llheapptr = rslt.val;
5147 5148 5149 5150 5151 5152 5153 5154 5155 5156
            bcx.build.Store(llheapptr,
                            bcx.build.InBoundsGEP(llstubptr, stub_p));
            auto heap_l = [C_uint(abi::ivec_heap_elt_len)];
            bcx.build.Store(lllen,
                            bcx.build.InBoundsGEP(llheapptr, heap_l));
            llfirsteltptr =
                bcx.build.InBoundsGEP(llheapptr,
                                      [C_int(0),
                                       C_uint(abi::ivec_heap_elt_elems),
                                       C_int(0)]);
5157 5158 5159
        }
    }
    // Store the individual elements.
5160

5161 5162 5163 5164 5165 5166 5167
    auto i = 0u;
    for (@ast::expr e in args) {
        rslt = trans_expr(bcx, e);
        bcx = rslt.bcx;
        auto llsrc = rslt.val;
        auto lleltptr;
        if (ty::type_has_dynamic_size(bcx.fcx.lcx.ccx.tcx, unit_ty)) {
5168 5169 5170
            lleltptr =
                bcx.build.InBoundsGEP(llfirsteltptr,
                                      [bcx.build.Mul(C_uint(i), unit_sz)]);
5171
        } else {
5172
            lleltptr = bcx.build.InBoundsGEP(llfirsteltptr, [C_uint(i)]);
5173 5174 5175 5176 5177 5178 5179
        }
        bcx = copy_val(bcx, INIT, lleltptr, llsrc, unit_ty).bcx;
        i += 1u;
    }
    ret res(bcx, llvecptr);
}

5180 5181
fn trans_rec(&@block_ctxt cx, &vec[ast::field] fields,
             &option::t[@ast::expr] base, &ast::ann ann) -> result {
5182
    auto bcx = cx;
5183
    auto t = node_ann_type(bcx.fcx.lcx.ccx, ann);
5184 5185 5186
    auto rec_res = alloc_ty(bcx, t);
    auto rec_val = rec_res.val;
    bcx = rec_res.bcx;
5187
    find_scope_cx(cx).cleanups += [clean(bind drop_ty(_, rec_val, t))];
5188
    let int i = 0;
G
Graydon Hoare 已提交
5189 5190
    auto base_val = C_nil();
    alt (base) {
5191 5192
        case (none) { }
        case (some(?bexp)) {
G
Graydon Hoare 已提交
5193 5194 5195 5196 5197
            auto base_res = trans_expr(bcx, bexp);
            bcx = base_res.bcx;
            base_val = base_res.val;
        }
    }
5198
    let vec[ty::field] ty_fields = [];
5199 5200
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
        case (ty::ty_rec(?flds)) { ty_fields = flds; }
G
Graydon Hoare 已提交
5201
    }
5202
    for (ty::field tf in ty_fields) {
5203
        auto e_ty = tf.mt.ty;
5204
        auto dst_res = GEP_tup_like(bcx, t, rec_val, [0, i]);
5205
        bcx = dst_res.bcx;
G
Graydon Hoare 已提交
5206 5207
        auto expr_provided = false;
        auto src_res = res(bcx, C_nil());
5208
        for (ast::field f in fields) {
5209
            if (str::eq(f.node.ident, tf.ident)) {
G
Graydon Hoare 已提交
5210
                expr_provided = true;
5211
                src_res = trans_expr(bcx, f.node.expr);
G
Graydon Hoare 已提交
5212 5213 5214
            }
        }
        if (!expr_provided) {
5215
            src_res = GEP_tup_like(bcx, t, base_val, [0, i]);
5216 5217
            src_res =
                res(src_res.bcx, load_if_immediate(bcx, src_res.val, e_ty));
G
Graydon Hoare 已提交
5218 5219
        }
        bcx = src_res.bcx;
5220
        bcx = copy_val(bcx, INIT, dst_res.val, src_res.val, e_ty).bcx;
5221 5222
        i += 1;
    }
5223
    ret res(bcx, rec_val);
5224 5225
}

5226
fn trans_expr(&@block_ctxt cx, &@ast::expr e) -> result {
5227
    ret trans_expr_out(cx, e, return);
5228 5229
}

5230 5231
fn trans_expr_out(&@block_ctxt cx, &@ast::expr e, out_method output) ->
   result {
5232
    // FIXME Fill in cx.sp
5233

5234
    alt (e.node) {
5235
        case (ast::expr_lit(?lit, ?ann)) {
5236
            ret res(cx, trans_lit(cx.fcx.lcx.ccx, *lit, ann));
5237
        }
5238
        case (ast::expr_unary(?op, ?x, ?ann)) {
5239
            if (op != ast::deref) { ret trans_unary(cx, op, x, ann); }
5240
        }
5241
        case (ast::expr_binary(?op, ?x, ?y, _)) {
5242
            ret trans_binary(cx, op, x, y);
5243
        }
5244
        case (ast::expr_if(?cond, ?thn, ?els, ?ann)) {
5245 5246
            ret with_out_method(bind trans_if(cx, cond, thn, els, ann, _), cx,
                                ann, output);
5247
        }
5248
        case (ast::expr_for(?decl, ?seq, ?body, _)) {
G
Graydon Hoare 已提交
5249 5250
            ret trans_for(cx, decl, seq, body);
        }
5251
        case (ast::expr_for_each(?decl, ?seq, ?body, _)) {
5252 5253
            ret trans_for_each(cx, decl, seq, body);
        }
5254
        case (ast::expr_while(?cond, ?body, _)) {
5255
            ret trans_while(cx, cond, body);
5256
        }
5257
        case (ast::expr_do_while(?body, ?cond, _)) {
5258
            ret trans_do_while(cx, body, cond);
5259
        }
5260
        case (ast::expr_alt(?expr, ?arms, ?ann)) {
5261 5262
            ret with_out_method(bind trans_alt(cx, expr, arms, ann, _), cx,
                                ann, output);
P
Patrick Walton 已提交
5263
        }
5264 5265
        case (ast::expr_fn(?f, ?ann)) {
            auto ccx = cx.fcx.lcx.ccx;
5266 5267 5268 5269 5270 5271 5272
            let TypeRef llfnty =
                alt (ty::struct(ccx.tcx, node_ann_type(ccx, ann))) {
                    case (ty::ty_fn(?proto, ?inputs, ?output, _, _)) {
                        type_of_fn_full(ccx, e.span, proto, none, inputs,
                                        output, 0u)
                    }
                };
5273 5274 5275 5276 5277 5278
            auto sub_cx = extend_path(cx.fcx.lcx, ccx.names.next("anon"));
            auto s = mangle_internal_name_by_path(ccx, sub_cx.path);
            auto llfn = decl_internal_fastcall_fn(ccx.llmod, s, llfnty);
            trans_fn(sub_cx, e.span, f, llfn, none, [], ann);
            ret res(cx, create_fn_pair(ccx, s, llfnty, llfn, false));
        }
5279
        case (ast::expr_block(?blk, ?ann)) {
5280 5281
            auto sub_cx = new_scope_block_ctxt(cx, "block-expr body");
            auto next_cx = new_sub_block_ctxt(cx, "next");
5282 5283 5284
            auto sub =
                with_out_method(bind trans_block(sub_cx, blk, _), cx, ann,
                                output);
5285 5286 5287
            cx.build.Br(sub_cx.llbb);
            sub.bcx.build.Br(next_cx.llbb);
            ret res(next_cx, sub.val);
5288
        }
5289
        case (ast::expr_move(?dst, ?src, _)) {
5290 5291
            auto lhs_res = trans_lval(cx, dst);
            assert (lhs_res.is_mem);
5292
            // FIXME Fill in lhs_res.res.bcx.sp
5293

M
Michael Sullivan 已提交
5294
            auto rhs_res = trans_lval(lhs_res.res.bcx, src);
5295
            auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, src);
5296
            // FIXME: calculate copy init-ness in typestate.
5297 5298 5299 5300

            auto move_res =
                move_val(rhs_res.res.bcx, DROP_EXISTING, lhs_res.res.val,
                         rhs_res.res.val, t);
5301
            ret res(move_res.bcx, C_nil());
5302
        }
5303
        case (ast::expr_assign(?dst, ?src, _)) {
5304
            auto lhs_res = trans_lval(cx, dst);
5305
            assert (lhs_res.is_mem);
5306
            // FIXME Fill in lhs_res.res.bcx.sp
5307

5308
            auto rhs_res = trans_expr(lhs_res.res.bcx, src);
5309
            auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, src);
G
Graydon Hoare 已提交
5310
            // FIXME: calculate copy init-ness in typestate.
5311 5312 5313 5314

            auto copy_res =
                copy_val(rhs_res.bcx, DROP_EXISTING, lhs_res.res.val,
                         rhs_res.val, t);
5315
            ret res(copy_res.bcx, C_nil());
5316
        }
5317 5318
        case (ast::expr_assign_op(?op, ?dst, ?src, _)) {
            auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, src);
5319
            auto lhs_res = trans_lval(cx, dst);
5320
            assert (lhs_res.is_mem);
5321
            // FIXME Fill in lhs_res.res.bcx.sp
5322

5323
            auto rhs_res = trans_expr(lhs_res.res.bcx, src);
5324
            if (ty::type_is_sequence(cx.fcx.lcx.ccx.tcx, t)) {
5325
                alt (op) {
5326
                    case (ast::add) {
5327 5328 5329 5330 5331
                        if (ty::sequence_is_interior(cx.fcx.lcx.ccx.tcx, t)) {
                            ret trans_ivec_append(rhs_res.bcx, t,
                                                  lhs_res.res.val,
                                                  rhs_res.val);
                        }
5332
                        ret trans_vec_append(rhs_res.bcx, t, lhs_res.res.val,
5333 5334 5335 5336 5337
                                             rhs_res.val);
                    }
                    case (_) { }
                }
            }
5338 5339 5340
            auto lhs_val = load_if_immediate(rhs_res.bcx, lhs_res.res.val, t);
            auto v =
                trans_eager_binop(rhs_res.bcx, op, t, lhs_val, rhs_res.val);
5341
            // FIXME: calculate copy init-ness in typestate.
5342 5343 5344

            auto copy_res =
                copy_val(v.bcx, DROP_EXISTING, lhs_res.res.val, v.val, t);
5345
            ret res(copy_res.bcx, C_nil());
5346
        }
5347
        case (ast::expr_bind(?f, ?args, ?ann)) {
5348 5349
            ret trans_bind(cx, f, args, ann);
        }
5350
        case (ast::expr_call(?f, ?args, ?ann)) {
5351
            ret trans_call(cx, f, none[ValueRef], args, ann);
5352
        }
5353
        case (ast::expr_cast(?e, _, ?ann)) { ret trans_cast(cx, e, ann); }
5354
        case (ast::expr_vec(?args, _, ast::sk_rc, ?ann)) {
G
Graydon Hoare 已提交
5355 5356
            ret trans_vec(cx, args, ann);
        }
5357 5358 5359
        case (ast::expr_vec(?args, _, ast::sk_unique, ?ann)) {
            ret trans_ivec(cx, args, ann);
        }
5360
        case (ast::expr_tup(?args, ?ann)) { ret trans_tup(cx, args, ann); }
5361
        case (ast::expr_rec(?args, ?base, ?ann)) {
5362
            ret trans_rec(cx, args, base, ann);
5363
        }
5364
        case (ast::expr_ext(_, _, _, ?expanded, _)) {
5365
            ret trans_expr(cx, expanded);
5366
        }
J
Josh Matthews 已提交
5367 5368 5369
        case (ast::expr_fail(_, ?str)) {
            auto failmsg;
            alt (str) {
5370 5371
                case (some(?msg)) { failmsg = msg; }
                case (_) { failmsg = "explicit failure"; }
J
Josh Matthews 已提交
5372 5373
            }
            ret trans_fail(cx, some(e.span), failmsg);
5374
        }
5375
        case (ast::expr_log(?lvl, ?a, _)) { ret trans_log(lvl, cx, a); }
5376
        case (ast::expr_assert(?a, _)) {
5377
            ret trans_check_expr(cx, a, "Assertion");
5378
        }
5379
        case (ast::expr_check(?a, _)) {
5380
            ret trans_check_expr(cx, a, "Predicate");
5381
        }
5382 5383 5384 5385 5386 5387 5388
        case (ast::expr_break(?a)) { ret trans_break(e.span, cx); }
        case (ast::expr_cont(?a)) { ret trans_cont(e.span, cx); }
        case (ast::expr_ret(?e, _)) { ret trans_ret(cx, e); }
        case (ast::expr_put(?e, _)) { ret trans_put(cx, e); }
        case (ast::expr_be(?e, _)) { ret trans_be(cx, e); }
        case (ast::expr_port(?ann)) { ret trans_port(cx, ann); }
        case (ast::expr_chan(?e, ?ann)) { ret trans_chan(cx, e, ann); }
5389
        case (ast::expr_send(?lhs, ?rhs, ?ann)) {
B
Brian Anderson 已提交
5390 5391
            ret trans_send(cx, lhs, rhs, ann);
        }
5392
        case (ast::expr_recv(?lhs, ?rhs, ?ann)) {
B
Brian Anderson 已提交
5393 5394
            ret trans_recv(cx, lhs, rhs, ann);
        }
5395
        case (ast::expr_spawn(?dom, ?name, ?func, ?args, ?ann)) {
5396
            ret trans_spawn(cx, dom, name, func, args, ann);
5397
        }
L
Lindsey Kuper 已提交
5398
        case (ast::expr_anon_obj(?anon_obj, ?tps, ?odid, ?ann)) {
L
Lindsey Kuper 已提交
5399
            ret trans_anon_obj(cx, e.span, anon_obj, tps, odid.ctor, ann);
L
Lindsey Kuper 已提交
5400
        }
5401
        case (_) {
5402
            // The expression is an lvalue. Fall through.
5403

5404
        }
5405
    }
5406 5407 5408
    // lval cases fall through to trans_lval and then
    // possibly load the result (if it's non-structural).

5409
    auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
5410
    auto sub = trans_lval(cx, e);
5411
    ret res(sub.res.bcx, load_if_immediate(sub.res.bcx, sub.res.val, t));
5412 5413
}

5414
fn with_out_method(fn(&out_method) -> result  work, @block_ctxt cx,
5415 5416 5417 5418 5419 5420
                   &ast::ann ann, &out_method outer_output) -> result {
    auto ccx = cx.fcx.lcx.ccx;
    if (outer_output != return) {
        ret work(outer_output);
    } else {
        auto tp = node_ann_type(ccx, ann);
5421
        if (ty::type_is_nil(ccx.tcx, tp)) { ret work(return); }
5422 5423
        auto res_alloca = alloc_ty(cx, tp);
        cx = zero_alloca(res_alloca.bcx, res_alloca.val, tp).bcx;
5424 5425
        fn drop_hoisted_ty(&@block_ctxt cx, ValueRef target, ty::t t) ->
           result {
5426 5427 5428 5429 5430 5431
            auto reg_val = load_if_immediate(cx, target, t);
            ret drop_ty(cx, reg_val, t);
        }
        auto cleanup = bind drop_hoisted_ty(_, res_alloca.val, tp);
        find_scope_cx(cx).cleanups += [clean(cleanup)];
        auto done = work(save_in(res_alloca.val));
M
Marijn Haverbeke 已提交
5432
        done = res(done.bcx, load_if_immediate(done.bcx, res_alloca.val, tp));
5433 5434 5435 5436
        ret done;
    }
}

5437

5438
// We pass structural values around the compiler "by pointer" and
5439 5440 5441 5442
// non-structural values (scalars, boxes, pointers) "by value". We call the
// latter group "immediates" and, in some circumstances when we know we have a
// pointer (or need one), perform load/store operations based on the
// immediate-ness of the type.
5443
fn type_is_immediate(&@crate_ctxt ccx, &ty::t t) -> bool {
5444 5445
    ret ty::type_is_scalar(ccx.tcx, t) || ty::type_is_boxed(ccx.tcx, t) ||
            ty::type_is_native(ccx.tcx, t);
5446 5447
}

G
Graydon Hoare 已提交
5448
fn do_spill(&@block_ctxt cx, ValueRef v) -> ValueRef {
5449
    // We have a value but we have to spill it to pass by alias.
5450

5451 5452 5453 5454
    auto llptr = alloca(cx, val_ty(v));
    cx.build.Store(v, llptr);
    ret llptr;
}
5455

5456
fn spill_if_immediate(&@block_ctxt cx, ValueRef v, &ty::t t) -> ValueRef {
5457
    if (type_is_immediate(cx.fcx.lcx.ccx, t)) { ret do_spill(cx, v); }
5458 5459 5460
    ret v;
}

5461
fn load_if_immediate(&@block_ctxt cx, ValueRef v, &ty::t t) -> ValueRef {
5462
    if (type_is_immediate(cx.fcx.lcx.ccx, t)) { ret cx.build.Load(v); }
5463
    ret v;
5464 5465
}

5466
fn trans_log(int lvl, &@block_ctxt cx, &@ast::expr e) -> result {
5467
    auto lcx = cx.fcx.lcx;
5468
    auto modname = str::connect(lcx.module_path, "::");
5469 5470 5471 5472
    auto global;
    if (lcx.ccx.module_data.contains_key(modname)) {
        global = lcx.ccx.module_data.get(modname);
    } else {
5473 5474 5475 5476 5477
        auto s =
            link::mangle_internal_name_by_path_and_seq(lcx.ccx,
                                                       lcx.module_path,
                                                       "loglevel");
        global = llvm::LLVMAddGlobal(lcx.ccx.llmod, T_int(), str::buf(s));
5478 5479
        llvm::LLVMSetGlobalConstant(global, False);
        llvm::LLVMSetInitializer(global, C_null(T_int()));
5480 5481
        llvm::LLVMSetLinkage(global,
                             lib::llvm::LLVMInternalLinkage as llvm::Linkage);
5482 5483
        lcx.ccx.module_data.insert(modname, global);
    }
5484
    auto log_cx = new_scope_block_ctxt(cx, "log");
5485 5486
    auto after_cx = new_sub_block_ctxt(cx, "after");
    auto load = cx.build.Load(global);
5487
    auto test = cx.build.ICmp(lib::llvm::LLVMIntSGE, load, C_int(lvl));
5488 5489
    cx.build.CondBr(test, log_cx.llbb, after_cx.llbb);
    auto sub = trans_expr(log_cx, e);
5490
    auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
5491
    auto log_bcx = sub.bcx;
5492
    if (ty::type_is_fp(cx.fcx.lcx.ccx.tcx, e_ty)) {
5493 5494
        let TypeRef tr;
        let bool is32bit = false;
5495 5496
        alt (ty::struct(cx.fcx.lcx.ccx.tcx, e_ty)) {
            case (ty::ty_machine(util::common::ty_f32)) {
5497 5498 5499
                tr = T_f32();
                is32bit = true;
            }
5500 5501
            case (ty::ty_machine(util::common::ty_f64)) { tr = T_f64(); }
            case (_) { tr = T_float(); }
5502 5503
        }
        if (is32bit) {
5504
            log_bcx.build.Call(log_bcx.fcx.lcx.ccx.upcalls.log_float,
5505
                               [log_bcx.fcx.lltaskptr, C_int(lvl), sub.val]);
5506
        } else {
5507
            // FIXME: Eliminate this level of indirection.
5508

5509
            auto tmp = alloca(log_bcx, tr);
5510
            sub.bcx.build.Store(sub.val, tmp);
5511
            log_bcx.build.Call(log_bcx.fcx.lcx.ccx.upcalls.log_double,
5512
                               [log_bcx.fcx.lltaskptr, C_int(lvl), tmp]);
5513
        }
5514
    } else if (ty::type_is_integral(cx.fcx.lcx.ccx.tcx, e_ty) ||
5515
                   ty::type_is_bool(cx.fcx.lcx.ccx.tcx, e_ty)) {
5516
        // FIXME: Handle signedness properly.
5517 5518 5519

        auto llintval =
            int_cast(log_bcx, T_int(), val_ty(sub.val), sub.val, false);
5520
        log_bcx.build.Call(log_bcx.fcx.lcx.ccx.upcalls.log_int,
5521
                           [log_bcx.fcx.lltaskptr, C_int(lvl), llintval]);
5522
    } else {
5523 5524
        alt (ty::struct(cx.fcx.lcx.ccx.tcx, e_ty)) {
            case (ty::ty_str) {
5525
                log_bcx.build.Call(log_bcx.fcx.lcx.ccx.upcalls.log_str,
5526
                                   [log_bcx.fcx.lltaskptr, C_int(lvl),
5527
                                    sub.val]);
5528 5529
            }
            case (_) {
5530
                // FIXME: Support these types.
5531

5532
                cx.fcx.lcx.ccx.sess.span_err(e.span,
5533 5534 5535 5536
                                             "log called on unsupported type "
                                                 +
                                                 ty_to_str(cx.fcx.lcx.ccx.tcx,
                                                           e_ty));
5537
            }
5538 5539
        }
    }
5540 5541
    log_bcx = trans_block_cleanups(log_bcx, log_cx);
    log_bcx.build.Br(after_cx.llbb);
5542
    ret res(after_cx, C_nil());
5543 5544
}

5545
fn trans_check_expr(&@block_ctxt cx, &@ast::expr e, &str s) -> result {
5546
    auto cond_res = trans_expr(cx, e);
5547
    auto expr_str = s + " " + expr_to_str(e) + " failed";
5548
    auto fail_cx = new_sub_block_ctxt(cx, "fail");
5549
    auto fail_res = trans_fail(fail_cx, some[common::span](e.span), expr_str);
5550
    auto next_cx = new_sub_block_ctxt(cx, "next");
5551
    cond_res.bcx.build.CondBr(cond_res.val, next_cx.llbb, fail_cx.llbb);
5552 5553 5554
    ret res(next_cx, C_nil());
}

5555
fn trans_fail(&@block_ctxt cx, &option::t[common::span] sp_opt, &str fail_str)
5556
   -> result {
5557
    auto V_fail_str = C_cstr(cx.fcx.lcx.ccx, fail_str);
5558 5559
    auto V_filename;
    auto V_line;
5560
    alt (sp_opt) {
5561
        case (some(?sp)) {
5562
            auto loc = cx.fcx.lcx.ccx.sess.lookup_pos(sp.lo);
5563
            V_filename = C_cstr(cx.fcx.lcx.ccx, loc.filename);
5564 5565
            V_line = loc.line as int;
        }
5566
        case (none) {
5567
            V_filename = C_cstr(cx.fcx.lcx.ccx, "<runtime>");
5568 5569 5570
            V_line = 0;
        }
    }
5571 5572
    V_fail_str = cx.build.PointerCast(V_fail_str, T_ptr(T_i8()));
    V_filename = cx.build.PointerCast(V_filename, T_ptr(T_i8()));
5573
    auto args = [cx.fcx.lltaskptr, V_fail_str, V_filename, C_int(V_line)];
5574 5575 5576
    cx.build.Call(cx.fcx.lcx.ccx.upcalls._fail, args);
    cx.build.Unreachable();
    ret res(cx, C_nil());
B
Brian Anderson 已提交
5577 5578
}

5579
fn trans_put(&@block_ctxt cx, &option::t[@ast::expr] e) -> result {
5580 5581
    auto llcallee = C_nil();
    auto llenv = C_nil();
5582
    alt ({ cx.fcx.lliterbody }) {
5583
        case (some(?lli)) {
5584
            auto slot = alloca(cx, val_ty(lli));
5585
            cx.build.Store(lli, slot);
5586 5587
            llcallee =
                cx.build.GEP(slot, [C_int(0), C_int(abi::fn_field_code)]);
5588
            llcallee = cx.build.Load(llcallee);
5589
            llenv = cx.build.GEP(slot, [C_int(0), C_int(abi::fn_field_box)]);
5590 5591 5592 5593
            llenv = cx.build.Load(llenv);
        }
    }
    auto bcx = cx;
5594
    auto dummy_retslot = alloca(bcx, T_nil());
5595
    let vec[ValueRef] llargs = [dummy_retslot, cx.fcx.lltaskptr, llenv];
5596
    alt (e) {
5597 5598
        case (none) { }
        case (some(?x)) {
5599
            auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, x);
5600
            auto arg = rec(mode=ty::mo_alias(false), ty=e_ty);
5601 5602
            auto arg_tys =
                type_of_explicit_args(cx.fcx.lcx.ccx, x.span, [arg]);
5603
            auto r = trans_arg_expr(bcx, arg, arg_tys.(0), x);
5604
            bcx = r.bcx;
5605
            llargs += [r.val];
5606 5607 5608
        }
    }
    ret res(bcx, bcx.build.FastCall(llcallee, llargs));
5609 5610
}

5611
fn trans_break_cont(&span sp, &@block_ctxt cx, bool to_end) -> result {
5612 5613
    auto bcx = cx;
    // Locate closest loop block, outputting cleanup as we go.
5614

5615 5616 5617
    auto cleanup_cx = cx;
    while (true) {
        bcx = trans_block_cleanups(bcx, cleanup_cx);
5618
        alt ({ cleanup_cx.kind }) {
5619 5620 5621 5622 5623
            case (LOOP_SCOPE_BLOCK(?_cont, ?_break)) {
                if (to_end) {
                    bcx.build.Br(_break.llbb);
                } else {
                    alt (_cont) {
5624
                        case (option::some(?_cont)) {
5625 5626
                            bcx.build.Br(_cont.llbb);
                        }
5627
                        case (_) { bcx.build.Br(cleanup_cx.llbb); }
5628 5629
                    }
                }
5630 5631
                ret res(new_sub_block_ctxt(bcx, "break_cont.unreachable"),
                        C_nil());
5632 5633
            }
            case (_) {
5634
                alt ({ cleanup_cx.parent }) {
5635
                    case (parent_some(?cx)) { cleanup_cx = cx; }
5636 5637
                    case (parent_none) {
                        cx.fcx.lcx.ccx.sess.span_err(sp,
5638 5639 5640 5641
                                                     if (to_end) {
                                                         "Break"
                                                     } else { "Cont" } +
                                                         " outside a loop");
5642
                    }
5643 5644 5645 5646
                }
            }
        }
    }
5647
    // If we get here without returning, it's a bug
5648

5649
    cx.fcx.lcx.ccx.sess.bug("in trans::trans_break_cont()");
5650 5651
}

5652 5653
fn trans_break(&span sp, &@block_ctxt cx) -> result {
    ret trans_break_cont(sp, cx, true);
5654 5655
}

5656 5657
fn trans_cont(&span sp, &@block_ctxt cx) -> result {
    ret trans_break_cont(sp, cx, false);
5658 5659
}

5660
fn trans_ret(&@block_ctxt cx, &option::t[@ast::expr] e) -> result {
5661 5662
    auto bcx = cx;
    auto val = C_nil();
5663
    alt (e) {
5664
        case (some(?x)) {
5665
            auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, x);
5666 5667 5668
            auto r = trans_expr(cx, x);
            bcx = r.bcx;
            val = r.val;
5669
            bcx = copy_val(bcx, INIT, cx.fcx.llretptr, val, t).bcx;
5670
        }
5671
        case (_) {
5672 5673
            auto t = llvm::LLVMGetElementType(val_ty(cx.fcx.llretptr));
            auto null = lib::llvm::llvm::LLVMConstNull(t);
5674 5675
            bcx.build.Store(null, cx.fcx.llretptr);
        }
5676
    }
5677
    // run all cleanups and back out.
5678

5679
    let bool more_cleanups = true;
5680
    auto cleanup_cx = cx;
5681
    while (more_cleanups) {
5682
        bcx = trans_block_cleanups(bcx, cleanup_cx);
5683 5684 5685
        alt ({ cleanup_cx.parent }) {
            case (parent_some(?b)) { cleanup_cx = b; }
            case (parent_none) { more_cleanups = false; }
5686 5687
        }
    }
5688
    bcx.build.RetVoid();
5689
    ret res(new_sub_block_ctxt(bcx, "ret.unreachable"), C_nil());
5690 5691
}

5692
fn trans_be(&@block_ctxt cx, &@ast::expr e) -> result {
5693
    // FIXME: This should be a typestate precondition
5694

5695
    assert (ast::is_call_expr(e));
5696 5697
    // FIXME: Turn this into a real tail call once
    // calling convention issues are settled
5698

5699 5700 5701
    ret trans_ret(cx, some(e));
}

5702
fn trans_port(&@block_ctxt cx, &ast::ann ann) -> result {
5703
    auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
B
Brian Anderson 已提交
5704
    auto unit_ty;
5705
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
5706 5707
        case (ty::ty_port(?t)) { unit_ty = t; }
        case (_) { cx.fcx.lcx.ccx.sess.bug("non-port type in trans_port"); }
B
Brian Anderson 已提交
5708
    }
5709
    auto llunit_ty = type_of(cx.fcx.lcx.ccx, cx.sp, unit_ty);
B
Brian Anderson 已提交
5710 5711 5712
    auto bcx = cx;
    auto unit_sz = size_of(bcx, unit_ty);
    bcx = unit_sz.bcx;
5713 5714 5715
    auto port_raw_val =
        bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.new_port,
                       [bcx.fcx.lltaskptr, unit_sz.val]);
5716
    auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, t);
5717
    auto port_val = bcx.build.PointerCast(port_raw_val, llty);
B
Brian Anderson 已提交
5718
    auto dropref = clean(bind drop_ty(_, port_val, t));
5719
    find_scope_cx(bcx).cleanups += [dropref];
B
Brian Anderson 已提交
5720 5721 5722
    ret res(bcx, port_val);
}

5723
fn trans_chan(&@block_ctxt cx, &@ast::expr e, &ast::ann ann) -> result {
B
Brian Anderson 已提交
5724 5725 5726
    auto bcx = cx;
    auto prt = trans_expr(bcx, e);
    bcx = prt.bcx;
5727
    auto prt_val = bcx.build.PointerCast(prt.val, T_opaque_port_ptr());
5728 5729 5730
    auto chan_raw_val =
        bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.new_chan,
                       [bcx.fcx.lltaskptr, prt_val]);
5731
    auto chan_ty = node_ann_type(bcx.fcx.lcx.ccx, ann);
5732
    auto chan_llty = type_of(bcx.fcx.lcx.ccx, e.span, chan_ty);
5733
    auto chan_val = bcx.build.PointerCast(chan_raw_val, chan_llty);
B
Brian Anderson 已提交
5734
    auto dropref = clean(bind drop_ty(_, chan_val, chan_ty));
5735
    find_scope_cx(bcx).cleanups += [dropref];
B
Brian Anderson 已提交
5736 5737 5738
    ret res(bcx, chan_val);
}

5739 5740 5741
fn trans_spawn(&@block_ctxt cx, &ast::spawn_dom dom, &option::t[str] name,
               &@ast::expr func, &vec[@ast::expr] args, &ast::ann ann) ->
   result {
5742
    auto bcx = cx;
5743 5744
    // Make the task name

5745 5746 5747 5748 5749 5750 5751 5752
    auto tname =
        alt (name) {
            case (none) {
                auto argss = vec::map(expr_to_str, args);
                #fmt("%s(%s)", expr_to_str(func), str::connect(argss, ", "))
            }
            case (some(?n)) { n }
        };
5753
    // Generate code
5754 5755 5756 5757 5758 5759 5760 5761 5762
    //
    // This is a several step process. The following things need to happen
    // (not necessarily in order):
    //
    // 1. Evaluate all the arguments to the spawnee.
    //
    // 2. Alloca a tuple that holds these arguments (they must be in reverse
    // order, so that they match the expected stack layout for the spawnee)
    //
5763
    // 3. Fill the tuple with the arguments we evaluated.
5764
    // 
5765 5766 5767 5768 5769 5770
    // 3.5. Generate a wrapper function that takes the tuple and unpacks it to
    // call the real task.
    //
    // 4. Pass a pointer to the wrapper function and the argument tuple to
    // upcall_start_task. In order to do this, we need to allocate another
    // tuple that matches the arguments expected by rust_task::start.
5771 5772
    //
    // 5. Oh yeah, we have to create the task before we start it...
5773

5774 5775
    // Translate the arguments, remembering their types and where the values
    // ended up.
5776

5777
    let vec[ty::t] arg_tys = [];
5778
    let vec[ValueRef] arg_vals = [];
5779
    for (@ast::expr e in args) {
5780 5781 5782
        auto arg = trans_expr(bcx, e);
        bcx = arg.bcx;
        vec::push[ValueRef](arg_vals, arg.val);
5783
        vec::push[ty::t](arg_tys, ty::expr_ty(cx.fcx.lcx.ccx.tcx, e));
5784
    }
5785
    // Make the tuple.
5786

5787 5788 5789
    auto args_ty = ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, arg_tys);
    // Allocate and fill the tuple.

5790
    auto llargs = alloc_ty(bcx, args_ty);
5791
    auto i = 0u;
5792
    for (ValueRef v in arg_vals) {
5793 5794
        // log_err #fmt("ty(llargs) = %s", 
        //              val_str(bcx.fcx.lcx.ccx.tn, llargs.val));
5795

5796 5797 5798 5799 5800 5801
        auto target = bcx.build.GEP(llargs.val, [C_int(0), C_int(i as int)]);
        // log_err #fmt("ty(v) = %s", val_str(bcx.fcx.lcx.ccx.tn, v));
        // log_err #fmt("ty(target) = %s", 
        //              val_str(bcx.fcx.lcx.ccx.tn, target));

        bcx.build.Store(v, target);
5802
        i += 1u;
5803 5804 5805
    }
    // Now we're ready to do the upcall.

5806 5807
    // But first, we'll create a task.

5808 5809 5810 5811
    let ValueRef lltname = C_str(bcx.fcx.lcx.ccx, tname);
    auto new_task =
        bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.new_task,
                       [bcx.fcx.lltaskptr, lltname]);
5812
    // Okay, start the task.
5813

5814
    auto llargs_i = bcx.build.PointerCast(llargs.val, T_int());
5815
    // Generate the wrapper function
5816

5817
    auto wrapper = mk_spawn_wrapper(bcx, func, args_ty);
5818 5819 5820
    bcx = wrapper.bcx;
    auto llfnptr_i = bcx.build.PointerCast(wrapper.val, T_int());
    // And start the task
5821

5822
    auto args_size = size_of(bcx, args_ty).val;
5823
    bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.start_task,
5824 5825
                   [bcx.fcx.lltaskptr, new_task, llfnptr_i, llargs_i,
                    args_size]);
E
Eric Holk 已提交
5826 5827 5828
    auto task_ty = node_ann_type(bcx.fcx.lcx.ccx, ann);
    auto dropref = clean(bind drop_ty(_, new_task, task_ty));
    find_scope_cx(bcx).cleanups += [dropref];
5829
    ret res(bcx, new_task);
5830 5831
}

5832 5833
fn mk_spawn_wrapper(&@block_ctxt cx, &@ast::expr func, &ty::t args_ty) ->
   result {
5834 5835 5836 5837
    auto llmod = cx.fcx.lcx.ccx.llmod;
    let TypeRef args_ty_tref = type_of(cx.fcx.lcx.ccx, cx.sp, args_ty);
    let TypeRef wrapper_fn_type =
        type_of_fn(cx.fcx.lcx.ccx, cx.sp, ast::proto_fn,
5838
                   [rec(mode=ty::mo_alias(false), ty=args_ty)], ty::idx_nil,
5839 5840
                   0u);
    // TODO: construct a name based on tname
5841

5842
    let str wrap_name =
5843
        mangle_internal_name_by_path_and_seq(cx.fcx.lcx.ccx, cx.fcx.lcx.path,
5844
                                             "spawn_wrapper");
5845
    auto llfndecl = decl_fastcall_fn(llmod, wrap_name, wrapper_fn_type);
5846 5847 5848 5849
    auto fcx = new_fn_ctxt(cx.fcx.lcx, cx.sp, llfndecl);
    auto fbcx = new_top_block_ctxt(fcx);
    // 3u to skip the three implicit args

5850
    let ValueRef arg = llvm::LLVMGetParam(fcx.llfn, 3u);
5851
    let vec[ValueRef] child_args =
5852
        [llvm::LLVMGetParam(fcx.llfn, 0u), llvm::LLVMGetParam(fcx.llfn, 1u),
5853 5854
         llvm::LLVMGetParam(fcx.llfn, 2u)];
    // unpack the arguments
5855 5856 5857

    alt (ty::struct(fcx.lcx.ccx.tcx, args_ty)) {
        case (ty::ty_tup(?elements)) {
5858
            auto i = 0;
5859
            for (ty::mt m in elements) {
5860 5861 5862 5863 5864 5865 5866 5867
                auto src = fbcx.build.GEP(arg, [C_int(0), C_int(i)]);
                i += 1;
                auto child_arg = fbcx.build.Load(src);
                child_args += [child_arg];
            }
        }
    }
    // Find the function
5868

5869 5870
    auto fnptr = trans_lval(fbcx, func).res;
    fbcx = fnptr.bcx;
5871
    auto llfnptr = fbcx.build.GEP(fnptr.val, [C_int(0), C_int(0)]);
5872
    auto llfn = fbcx.build.Load(llfnptr);
5873
    fbcx.build.FastCall(llfn, child_args);
5874 5875 5876
    fbcx.build.RetVoid();
    finish_fn(fcx, fbcx.llbb);
    // TODO: make sure we clean up everything we need to.
5877

5878 5879 5880
    ret res(cx, llfndecl);
}

5881 5882
fn trans_send(&@block_ctxt cx, &@ast::expr lhs, &@ast::expr rhs,
              &ast::ann ann) -> result {
5883 5884 5885 5886 5887
    auto bcx = cx;
    auto chn = trans_expr(bcx, lhs);
    bcx = chn.bcx;
    auto data = trans_expr(bcx, rhs);
    bcx = data.bcx;
5888
    auto chan_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
5889
    auto unit_ty;
5890
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, chan_ty)) {
5891 5892
        case (ty::ty_chan(?t)) { unit_ty = t; }
        case (_) { bcx.fcx.lcx.ccx.sess.bug("non-chan type in trans_send"); }
5893
    }
5894 5895
    auto data_alloc = alloc_ty(bcx, unit_ty);
    bcx = data_alloc.bcx;
5896
    auto data_tmp = copy_val(bcx, INIT, data_alloc.val, data.val, unit_ty);
5897
    bcx = data_tmp.bcx;
5898
    find_scope_cx(bcx).cleanups +=
5899
        [clean(bind drop_ty(_, data_alloc.val, unit_ty))];
5900 5901 5902
    auto llchanval = bcx.build.PointerCast(chn.val, T_opaque_chan_ptr());
    auto lldataptr = bcx.build.PointerCast(data_alloc.val, T_ptr(T_i8()));
    bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.send,
5903
                   [bcx.fcx.lltaskptr, llchanval, lldataptr]);
5904
    ret res(bcx, chn.val);
B
Brian Anderson 已提交
5905 5906
}

5907 5908
fn trans_recv(&@block_ctxt cx, &@ast::expr lhs, &@ast::expr rhs,
              &ast::ann ann) -> result {
5909
    auto bcx = cx;
B
Brian Anderson 已提交
5910
    auto data = trans_lval(bcx, lhs);
5911
    assert (data.is_mem);
B
Brian Anderson 已提交
5912
    bcx = data.res.bcx;
5913
    auto unit_ty = node_ann_type(bcx.fcx.lcx.ccx, ann);
5914 5915
    // FIXME: calculate copy init-ness in typestate.

5916 5917
    ret recv_val(bcx, data.res.val, rhs, unit_ty, DROP_EXISTING);
}
5918

5919 5920
fn recv_val(&@block_ctxt cx, ValueRef lhs, &@ast::expr rhs, &ty::t unit_ty,
            copy_action action) -> result {
5921
    auto bcx = cx;
5922 5923
    auto prt = trans_expr(bcx, rhs);
    bcx = prt.bcx;
5924 5925 5926
    auto lldataptr = bcx.build.PointerCast(lhs, T_ptr(T_ptr(T_i8())));
    auto llportptr = bcx.build.PointerCast(prt.val, T_opaque_port_ptr());
    bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.recv,
5927
                   [bcx.fcx.lltaskptr, lldataptr, llportptr]);
5928
    auto data_load = load_if_immediate(bcx, lhs, unit_ty);
5929
    auto cp = copy_val(bcx, action, lhs, data_load, unit_ty);
5930
    bcx = cp.bcx;
5931
    // TODO: Any cleanup need to be done here?
5932

5933
    ret res(bcx, lhs);
B
Brian Anderson 已提交
5934 5935
}

L
Lindsey Kuper 已提交
5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967

/*

  Suppose we create an anonymous object my_b from a regular object a:

        obj a() {
            fn foo() -> int {
                ret 2;
            }
            fn bar() -> int {
                ret self.foo();
            }
        }

       auto my_a = a();
       auto my_b = obj { fn baz() -> int { ret self.foo() } with my_a };

  Here we're extending the my_a object with an additional method baz, creating
  an object my_b. Since it's an object, my_b is a pair of a vtable pointer and
  a body pointer:

  my_b: [vtbl* | body*]

  my_b's vtable has entries for foo, bar, and baz, whereas my_a's vtable has
  only foo and bar. my_b's 3-entry vtable consists of two forwarding functions
  and one real method.

  my_b's body just contains the pair a: [ a_vtable | a_body ], wrapped up with
  any additional fields that my_b added. None were added, so my_b is just the
  wrapped inner object.

*/
L
Lindsey Kuper 已提交
5968 5969 5970 5971 5972 5973 5974

// trans_anon_obj: create (and return!) an LLVM function that is the object
// constructor for the anonymous object being translated.  
//
// This code differs from trans_obj in that, rather than creating an object
// constructor function and putting it in the generated code as an object
// item, we are instead "inlining" the construction of the object.
5975 5976
fn trans_anon_obj(@block_ctxt cx, &span sp, &ast::anon_obj anon_obj,
                  &vec[ast::ty_param] ty_params, ast::def_id oid,
L
Lindsey Kuper 已提交
5977
                  &ast::ann ann) -> result {
L
Lindsey Kuper 已提交
5978 5979 5980 5981
    auto ccx = cx.fcx.lcx.ccx;
    // A crate_ctxt has an item_ids hashmap, which has all of the def_ids of
    // everything in the crate.  By looking up a def_id, you can get the
    // ValueRef of that item.
L
Lindsey Kuper 已提交
5982

5983
    auto llctor_decl = ccx.item_ids.get(oid);
L
Lindsey Kuper 已提交
5984 5985
    // If with_obj (the object being extended) exists, translate it, producing
    // a result.
5986

L
Lindsey Kuper 已提交
5987 5988
    let option::t[result] with_obj_val = none[result];
    alt (anon_obj.with_obj) {
5989 5990
        case (none) { }
        case (some(?e)) {
5991 5992 5993
            // Translating with_obj returns a ValueRef (pointer to a 2-word
            // value) wrapped in a result.  We want to allocate space for this
            // value in our outer object, then copy it into the outer object.
5994

L
Lindsey Kuper 已提交
5995 5996 5997
            with_obj_val = some[result](trans_expr(cx, e));
        }
    }
L
Lindsey Kuper 已提交
5998 5999 6000 6001 6002 6003 6004
    // If the anonymous object we're translating adds any additional fields,
    // they'll become the arguments to the function we're creating.

    // FIXME (part of issue #417): all of the following code is copypasta from
    // trans_obj for translating the anonymous wrapper object.  Eventually we
    // should abstract this code out of trans_anon_obj and trans_obj.

L
Lindsey Kuper 已提交
6005 6006
    // For the anon obj's additional fields, if any exist, translate object
    // constructor arguments to function arguments.
6007

L
Lindsey Kuper 已提交
6008
    let vec[ast::obj_field] addtl_fields = [];
L
Lindsey Kuper 已提交
6009 6010
    let vec[ast::arg] addtl_fn_args = [];
    alt (anon_obj.fields) {
6011 6012
        case (none) { }
        case (some(?fields)) {
L
Lindsey Kuper 已提交
6013
            addtl_fields = fields;
L
Lindsey Kuper 已提交
6014
            for (ast::obj_field f in fields) {
6015 6016 6017 6018 6019
                addtl_fn_args +=
                    [rec(mode=ast::alias(false),
                         ty=f.ty,
                         ident=f.ident,
                         id=f.id)];
L
Lindsey Kuper 已提交
6020 6021 6022
            }
        }
    }
L
Lindsey Kuper 已提交
6023 6024
    auto fcx = new_fn_ctxt(cx.fcx.lcx, sp, llctor_decl);
    // Both regular arguments and type parameters are handled here.
6025 6026 6027 6028

    create_llargs_for_fn_args(fcx, ast::proto_fn, none[ty_self_pair],
                              ret_ty_of_fn(ccx, ann), addtl_fn_args,
                              ty_params);
L
Lindsey Kuper 已提交
6029 6030 6031 6032
    let vec[ty::arg] arg_tys = arg_tys_of_fn(ccx, ann);
    copy_args_to_allocas(fcx, addtl_fn_args, arg_tys);
    //  Create the first block context in the function and keep a handle on it
    //  to pass to finish_fn later.
6033

L
Lindsey Kuper 已提交
6034 6035 6036 6037
    auto bcx = new_top_block_ctxt(fcx);
    auto lltop = bcx.llbb;
    // Pick up the type of this object by looking at our own output type, that
    // is, the output type of the object constructor we're building.
6038

L
Lindsey Kuper 已提交
6039 6040 6041 6042 6043 6044 6045 6046
    auto self_ty = ret_ty_of_fn(ccx, ann);
    auto llself_ty = type_of(ccx, sp, self_ty);
    // Set up the two-word pair that we're going to return from the object
    // constructor we're building.  The two elements of this pair will be a
    // vtable pointer and a body pointer.  (llretptr already points to the
    // place where this two-word pair should go; it was pre-allocated by the
    // caller of the function.)

6047
    auto pair = bcx.fcx.llretptr;
L
Lindsey Kuper 已提交
6048 6049 6050 6051
    // Grab onto the first and second elements of the pair.
    // abi::obj_field_vtbl and abi::obj_field_box simply specify words 0 and 1
    // of 'pair'.

6052 6053 6054 6055
    auto pair_vtbl =
        bcx.build.GEP(pair, [C_int(0), C_int(abi::obj_field_vtbl)]);
    auto pair_box =
        bcx.build.GEP(pair, [C_int(0), C_int(abi::obj_field_box)]);
L
Lindsey Kuper 已提交
6056 6057 6058 6059 6060 6061 6062 6063
    // Make a vtable for this object: a static array of pointers to functions.
    // It will be located in the read-only memory of the executable we're
    // creating and will contain ValueRefs for all of this object's methods.
    // create_vtbl returns a pointer to the vtable, which we store.

    // create_vtbl() wants an ast::_obj and all we have is an
    // ast::anon_obj, so we need to roll our own.

6064 6065 6066 6067 6068 6069
    let ast::_obj wrapper_obj =
        rec(fields=addtl_fields,
            methods=anon_obj.methods,
            dtor=none[@ast::method]);
    auto vtbl =
        create_vtbl(cx.fcx.lcx, llself_ty, self_ty, wrapper_obj, ty_params);
L
Lindsey Kuper 已提交
6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085
    bcx.build.Store(vtbl, pair_vtbl);
    // FIXME (part of issue #417): This vtable needs to contain "forwarding
    // slots" for the methods that exist in the with_obj, as well.  How do we
    // do that?

    // Next we have to take care of the other half of the pair we're
    // returning: a boxed (reference-counted) tuple containing a tydesc,
    // typarams, and fields.

    // FIXME (part of issue #417): Because this is an anonymous object, we
    // also have to fill in the with_obj field of this tuple.

    let TypeRef llbox_ty = T_opaque_obj_ptr(ccx.tn);
    // FIXME: we should probably also allocate a box for empty objs that have
    // a dtor, since otherwise they are never dropped, and the dtor never
    // runs.
6086

L
Lindsey Kuper 已提交
6087
    if (vec::len[ast::ty_param](ty_params) == 0u &&
6088
            vec::len[ty::arg](arg_tys) == 0u) {
L
Lindsey Kuper 已提交
6089 6090 6091 6092
        // If the object we're translating has no fields or type parameters,
        // there's not much to do.

        // Store null into pair, if no args or typarams.
6093

L
Lindsey Kuper 已提交
6094 6095 6096 6097 6098 6099
        bcx.build.Store(C_null(llbox_ty), pair_box);
    } else {
        // Otherwise, we have to synthesize a big structural type for the
        // object body.

        let vec[ty::t] obj_fields = [];
6100
        for (ty::arg a in arg_tys) { vec::push[ty::t](obj_fields, a.ty); }
L
Lindsey Kuper 已提交
6101 6102
        // Tuple type for fields: [field, ...]

6103
        let ty::t fields_ty = ty::mk_imm_tup(ccx.tcx, obj_fields);
L
Lindsey Kuper 已提交
6104
        // Tuple type for typarams: [typaram, ...]
6105

L
Lindsey Kuper 已提交
6106 6107 6108 6109 6110 6111 6112 6113
        auto tydesc_ty = ty::mk_type(ccx.tcx);
        let vec[ty::t] tps = [];
        for (ast::ty_param tp in ty_params) {
            vec::push[ty::t](tps, tydesc_ty);
        }
        let ty::t typarams_ty = ty::mk_imm_tup(ccx.tcx, tps);
        // Tuple type for body: [tydesc_ty, [typaram, ...], [field, ...]]

6114 6115
        let ty::t body_ty =
            ty::mk_imm_tup(ccx.tcx, [tydesc_ty, typarams_ty, fields_ty]);
L
Lindsey Kuper 已提交
6116 6117
        // Hand this type we've synthesized off to trans_malloc_boxed, which
        // allocates a box, including space for a refcount.
6118

L
Lindsey Kuper 已提交
6119 6120 6121 6122 6123
        auto box = trans_malloc_boxed(bcx, body_ty);
        bcx = box.bcx;
        // mk_imm_box throws a refcount into the type we're synthesizing, so
        // that it looks like: [rc, [tydesc_ty, [typaram, ...], [field, ...]]]

6124
        let ty::t boxed_body_ty = ty::mk_imm_box(ccx.tcx, body_ty);
L
Lindsey Kuper 已提交
6125 6126
        // Grab onto the refcount and body parts of the box we allocated.

6127 6128 6129 6130 6131 6132 6133
        auto rc =
            GEP_tup_like(bcx, boxed_body_ty, box.val,
                         [0, abi::box_rc_field_refcnt]);
        bcx = rc.bcx;
        auto body =
            GEP_tup_like(bcx, boxed_body_ty, box.val,
                         [0, abi::box_rc_field_body]);
L
Lindsey Kuper 已提交
6134 6135 6136 6137 6138 6139 6140 6141 6142 6143
        bcx = body.bcx;
        bcx.build.Store(C_int(1), rc.val);
        // Put together a tydesc for the body, so that the object can later be
        // freed by calling through its tydesc.

        // Every object (not just those with type parameters) needs to have a
        // tydesc to describe its body, since all objects have unknown type to
        // the user of the object.  So the tydesc is needed to keep track of
        // the types of the object's fields, so that the fields can be freed
        // later.
6144

L
Lindsey Kuper 已提交
6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162
        auto body_tydesc =
            GEP_tup_like(bcx, body_ty, body.val,
                         [0, abi::obj_body_elt_tydesc]);
        bcx = body_tydesc.bcx;
        auto ti = none[@tydesc_info];
        auto body_td = get_tydesc(bcx, body_ty, true, ti);
        lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
        lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
        bcx = body_td.bcx;
        bcx.build.Store(body_td.val, body_tydesc.val);
        // Copy the object's type parameters and fields into the space we
        // allocated for the object body.  (This is something like saving the
        // lexical environment of a function in its closure: the "captured
        // typarams" are any type parameters that are passed to the object
        // constructor and are then available to the object's methods.
        // Likewise for the object's fields.)

        // Copy typarams into captured typarams.
6163

L
Lindsey Kuper 已提交
6164 6165 6166 6167 6168 6169 6170
        auto body_typarams =
            GEP_tup_like(bcx, body_ty, body.val,
                         [0, abi::obj_body_elt_typarams]);
        bcx = body_typarams.bcx;
        let int i = 0;
        for (ast::ty_param tp in ty_params) {
            auto typaram = bcx.fcx.lltydescs.(i);
6171 6172
            auto capture =
                GEP_tup_like(bcx, typarams_ty, body_typarams.val, [0, i]);
L
Lindsey Kuper 已提交
6173 6174 6175 6176 6177
            bcx = capture.bcx;
            bcx = copy_val(bcx, INIT, capture.val, typaram, tydesc_ty).bcx;
            i += 1;
        }
        // Copy args into body fields.
6178

L
Lindsey Kuper 已提交
6179 6180 6181 6182 6183 6184 6185 6186
        auto body_fields =
            GEP_tup_like(bcx, body_ty, body.val,
                         [0, abi::obj_body_elt_fields]);
        bcx = body_fields.bcx;
        i = 0;
        for (ast::obj_field f in wrapper_obj.fields) {
            auto arg = bcx.fcx.llargs.get(f.id);
            arg = load_if_immediate(bcx, arg, arg_tys.(i).ty);
6187 6188
            auto field =
                GEP_tup_like(bcx, fields_ty, body_fields.val, [0, i]);
L
Lindsey Kuper 已提交
6189 6190 6191 6192 6193
            bcx = field.bcx;
            bcx = copy_val(bcx, INIT, field.val, arg, arg_tys.(i).ty).bcx;
            i += 1;
        }
        // Store box ptr in outer pair.
6194

L
Lindsey Kuper 已提交
6195 6196 6197 6198 6199
        auto p = bcx.build.PointerCast(box.val, llbox_ty);
        bcx.build.Store(p, pair_box);
    }
    bcx.build.RetVoid();
    // Insert the mandatory first few basic blocks before lltop.
L
Lindsey Kuper 已提交
6200

6201
    finish_fn(fcx, lltop);
L
Lindsey Kuper 已提交
6202
    // Return the object we built.
6203

L
Lindsey Kuper 已提交
6204
    ret res(bcx, pair);
L
Lindsey Kuper 已提交
6205 6206
}

6207
fn init_local(&@block_ctxt cx, &@ast::local_ local) -> result {
6208
    // Make a note to drop this slot on the way out.
6209

6210
    assert (cx.fcx.lllocals.contains_key(local.id));
6211
    auto llptr = cx.fcx.lllocals.get(local.id);
6212
    auto ty = node_ann_type(cx.fcx.lcx.ccx, local.ann);
6213
    auto bcx = cx;
6214
    find_scope_cx(cx).cleanups += [clean(bind drop_slot(_, llptr, ty))];
6215
    alt (local.init) {
6216
        case (some(?init)) {
6217
            alt (init.op) {
6218
                case (ast::init_assign) {
6219 6220 6221
                    // Use the type of the RHS because if it's _|_, the LHS
                    // type might be something else, but we don't want to copy
                    // the value.
6222 6223 6224 6225

                    ty =
                        node_ann_type(cx.fcx.lcx.ccx,
                                      ty::expr_ann(init.expr));
6226
                    auto sub = trans_expr(bcx, init.expr);
6227
                    bcx = copy_val(sub.bcx, INIT, llptr, sub.val, ty).bcx;
6228
                }
6229 6230
                case (ast::init_move) {
                    auto sub = trans_lval(bcx, init.expr);
6231 6232 6233
                    bcx =
                        move_val(sub.res.bcx, INIT, llptr, sub.res.val,
                                 ty).bcx;
6234
                }
6235
                case (ast::init_recv) {
6236 6237 6238
                    bcx = recv_val(bcx, llptr, init.expr, ty, INIT).bcx;
                }
            }
6239
        }
6240
        case (_) { bcx = zero_alloca(bcx, llptr, ty).bcx; }
6241 6242 6243 6244
    }
    ret res(bcx, llptr);
}

6245
fn zero_alloca(&@block_ctxt cx, ValueRef llptr, ty::t t) -> result {
6246
    auto bcx = cx;
6247
    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
6248
        auto llsz = size_of(bcx, t);
6249
        auto llalign = align_of(llsz.bcx, t);
6250
        bcx = call_bzero(llalign.bcx, llptr, llsz.val, llalign.val).bcx;
6251
    } else {
6252
        auto llty = type_of(bcx.fcx.lcx.ccx, cx.sp, t);
6253
        auto null = lib::llvm::llvm::LLVMConstNull(llty);
6254 6255 6256
        bcx.build.Store(null, llptr);
    }
    ret res(bcx, llptr);
6257
}
6258

6259
fn trans_stmt(&@block_ctxt cx, &ast::stmt s) -> result {
6260
    // FIXME Fill in cx.sp
6261

6262
    auto bcx = cx;
6263
    alt (s.node) {
6264 6265
        case (ast::stmt_expr(?e, _)) { bcx = trans_expr(cx, e).bcx; }
        case (ast::stmt_decl(?d, _)) {
6266
            alt (d.node) {
6267
                case (ast::decl_local(?local)) {
6268
                    bcx = init_local(bcx, local).bcx;
6269
                }
6270
                case (ast::decl_item(?i)) { trans_item(cx.fcx.lcx, *i); }
6271 6272
            }
        }
6273
        case (_) { cx.fcx.lcx.ccx.sess.unimpl("stmt variant"); }
6274
    }
6275
    ret res(bcx, C_nil());
6276 6277
}

6278
fn new_builder(BasicBlockRef llbb) -> builder {
6279 6280
    let BuilderRef llbuild = llvm::LLVMCreateBuilder();
    llvm::LLVMPositionBuilderAtEnd(llbuild, llbb);
6281
    ret builder(llbuild, @mutable false);
6282 6283
}

6284

6285 6286
// You probably don't want to use this one. See the
// next three functions instead.
6287
fn new_block_ctxt(&@fn_ctxt cx, &block_parent parent, block_kind kind,
G
Graydon Hoare 已提交
6288
                  &str name) -> @block_ctxt {
6289
    let vec[cleanup] cleanups = [];
6290
    auto s = str::buf("");
6291
    if (cx.lcx.ccx.sess.get_opts().save_temps) {
6292
        s = str::buf(cx.lcx.ccx.names.next(name));
6293
    }
6294
    let BasicBlockRef llbb = llvm::LLVMAppendBasicBlock(cx.llfn, s);
6295
    ret @rec(llbb=llbb,
6296
             build=new_builder(llbb),
6297
             parent=parent,
6298
             kind=kind,
6299
             mutable cleanups=cleanups,
6300
             sp=cx.sp,
6301 6302 6303
             fcx=cx);
}

6304

6305
// Use this when you're at the top block of a function or the like.
G
Graydon Hoare 已提交
6306
fn new_top_block_ctxt(&@fn_ctxt fcx) -> @block_ctxt {
6307
    ret new_block_ctxt(fcx, parent_none, SCOPE_BLOCK, "function top level");
6308
}
6309

6310

6311
// Use this when you're at a curly-brace or similar lexical scope.
G
Graydon Hoare 已提交
6312
fn new_scope_block_ctxt(&@block_ctxt bcx, &str n) -> @block_ctxt {
6313
    ret new_block_ctxt(bcx.fcx, parent_some(bcx), SCOPE_BLOCK, n);
6314 6315
}

6316
fn new_loop_scope_block_ctxt(&@block_ctxt bcx, &option::t[@block_ctxt] _cont,
G
Graydon Hoare 已提交
6317
                             &@block_ctxt _break, &str n) -> @block_ctxt {
6318 6319 6320 6321
    ret new_block_ctxt(bcx.fcx, parent_some(bcx),
                       LOOP_SCOPE_BLOCK(_cont, _break), n);
}

6322

6323
// Use this when you're making a general CFG BB within a scope.
G
Graydon Hoare 已提交
6324
fn new_sub_block_ctxt(&@block_ctxt bcx, &str n) -> @block_ctxt {
6325
    ret new_block_ctxt(bcx.fcx, parent_some(bcx), NON_SCOPE_BLOCK, n);
6326
}
6327

6328
fn new_raw_block_ctxt(&@fn_ctxt fcx, BasicBlockRef llbb) -> @block_ctxt {
6329
    let vec[cleanup] cleanups = [];
6330 6331 6332 6333 6334 6335
    ret @rec(llbb=llbb,
             build=new_builder(llbb),
             parent=parent_none,
             kind=NON_SCOPE_BLOCK,
             mutable cleanups=cleanups,
             sp=fcx.sp,
6336
             fcx=fcx);
6337 6338
}

6339

6340 6341 6342 6343 6344 6345 6346
// trans_block_cleanups: Go through all the cleanups attached to this
// block_ctxt and execute them.  
//
// When translating a block that introdces new variables during its scope, we
// need to make sure those variables go out of scope when the block ends.  We
// do that by running a 'cleanup' function for each variable.
// trans_block_cleanups runs all the cleanup functions for the block.
6347 6348
fn trans_block_cleanups(&@block_ctxt cx, &@block_ctxt cleanup_cx) ->
   @block_ctxt {
6349
    auto bcx = cx;
6350
    if (cleanup_cx.kind == NON_SCOPE_BLOCK) {
6351
        assert (vec::len[cleanup](cleanup_cx.cleanups) == 0u);
6352
    }
6353
    auto i = vec::len[cleanup](cleanup_cx.cleanups);
6354 6355 6356
    while (i > 0u) {
        i -= 1u;
        auto c = cleanup_cx.cleanups.(i);
6357
        alt (c) { case (clean(?cfn)) { bcx = cfn(bcx).bcx; } }
6358
    }
6359 6360 6361
    ret bcx;
}

6362
iter block_locals(&ast::block b) -> @ast::local_ {
6363

6364 6365
    // FIXME: putting from inside an iter block doesn't work, so we can't
    // use the index here.
6366
    for (@ast::stmt s in b.node.stmts) {
6367
        alt (s.node) {
6368
            case (ast::stmt_decl(?d, _)) {
6369
                alt (d.node) {
6370 6371
                    case (ast::decl_local(?local)) { put local; }
                    case (_) {/* fall through */ }
6372 6373
                }
            }
6374
            case (_) {/* fall through */ }
6375 6376 6377 6378
        }
    }
}

G
Graydon Hoare 已提交
6379
fn llallocas_block_ctxt(&@fn_ctxt fcx) -> @block_ctxt {
6380
    let vec[cleanup] cleanups = [];
6381 6382 6383 6384 6385
    ret @rec(llbb=fcx.llallocas,
             build=new_builder(fcx.llallocas),
             parent=parent_none,
             kind=SCOPE_BLOCK,
             mutable cleanups=cleanups,
6386
             sp=fcx.sp,
6387 6388 6389
             fcx=fcx);
}

6390
fn alloc_ty(&@block_ctxt cx, &ty::t t) -> result {
6391
    auto val = C_int(0);
6392
    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
6393 6394 6395 6396 6397 6398 6399 6400
        // NB: we have to run this particular 'size_of' in a
        // block_ctxt built on the llallocas block for the fn,
        // so that the size dominates the array_alloca that
        // comes next.

        auto n = size_of(llallocas_block_ctxt(cx.fcx), t);
        cx.fcx.llallocas = n.bcx.llbb;
        val = array_alloca(cx, T_i8(), n.val);
6401
    } else { val = alloca(cx, type_of(cx.fcx.lcx.ccx, cx.sp, t)); }
6402 6403 6404 6405 6406 6407
    // NB: since we've pushed all size calculations in this
    // function up to the alloca block, we actually return the
    // block passed into us unmodified; it doesn't really
    // have to be passed-and-returned here, but it fits
    // past caller conventions and may well make sense again,
    // so we leave it as-is.
6408

6409
    ret res(cx, val);
6410 6411
}

6412
fn alloc_local(&@block_ctxt cx, &@ast::local_ local) -> result {
6413
    auto t = node_ann_type(cx.fcx.lcx.ccx, local.ann);
6414 6415 6416 6417 6418
    auto r = alloc_ty(cx, t);
    r.bcx.fcx.lllocals.insert(local.id, r.val);
    ret r;
}

6419
fn trans_block(&@block_ctxt cx, &ast::block b, &out_method output) -> result {
6420
    auto bcx = cx;
6421
    for each (@ast::local_ local in block_locals(b)) {
6422
        // FIXME Update bcx.sp
6423

6424
        bcx = alloc_local(bcx, local).bcx;
6425
    }
6426
    auto r = res(bcx, C_nil());
6427
    for (@ast::stmt s in b.node.stmts) {
6428 6429
        r = trans_stmt(bcx, *s);
        bcx = r.bcx;
6430

6431 6432
        // If we hit a terminator, control won't go any further so
        // we're in dead-code land. Stop here.
6433
        if (is_terminated(bcx)) { ret r; }
6434
    }
6435 6436
    fn accept_out_method(&@ast::expr expr) -> bool {
        ret alt (expr.node) {
6437 6438 6439 6440 6441
                case (ast::expr_if(_, _, _, _)) { true }
                case (ast::expr_alt(_, _, _)) { true }
                case (ast::expr_block(_, _)) { true }
                case (_) { false }
            };
6442
    }
6443
    alt (b.node.expr) {
6444
        case (some(?e)) {
6445 6446 6447
            auto pass = output != return && accept_out_method(e);
            if (pass) {
                r = trans_expr_out(bcx, e, output);
6448
            } else { r = trans_expr(bcx, e); }
6449
            bcx = r.bcx;
6450 6451
            auto ccx = cx.fcx.lcx.ccx;
            auto r_ty = ty::expr_ty(ccx.tcx, e);
6452
            if (is_terminated(bcx) || ty::type_is_bot(ccx.tcx, r_ty)) {
6453
                ret r;
6454 6455 6456 6457 6458 6459 6460
            } else if (!pass) {
                alt (output) {
                    case (save_in(?target)) {
                        // The output method is to save the value at target,
                        // and we didn't pass it to the recursive trans_expr
                        // call.
                        // FIXME Use move semantics!
6461 6462 6463

                        auto res_copy =
                            copy_val(bcx, INIT, target, r.val, r_ty);
6464 6465
                        bcx = res_copy.bcx;
                        r = res(bcx, C_nil());
6466
                    }
6467
                    case (return) { }
6468
                }
6469 6470
            }
        }
6471
        case (none) { r = res(bcx, C_nil()); }
6472
    }
6473
    bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
6474
    ret res(bcx, r.val);
6475 6476
}

G
Graydon Hoare 已提交
6477
fn new_local_ctxt(&@crate_ctxt ccx) -> @local_ctxt {
6478 6479 6480
    let vec[str] pth = [];
    let vec[ast::ty_param] obj_typarams = [];
    let vec[ast::obj_field] obj_fields = [];
6481
    ret @rec(path=pth,
6482
             module_path=[ccx.crate_meta_name],
6483 6484 6485
             obj_typarams=obj_typarams,
             obj_fields=obj_fields,
             ccx=ccx);
6486 6487
}

6488

6489 6490 6491
// Creates the standard trio of basic blocks: allocas, copy-args, and derived
// tydescs.
fn mk_standard_basic_blocks(ValueRef llfn) ->
6492
   tup(BasicBlockRef, BasicBlockRef, BasicBlockRef) {
6493 6494 6495
    ret tup(llvm::LLVMAppendBasicBlock(llfn, str::buf("allocas")),
            llvm::LLVMAppendBasicBlock(llfn, str::buf("copy_args")),
            llvm::LLVMAppendBasicBlock(llfn, str::buf("derived_tydescs")));
6496 6497
}

6498

6499 6500 6501 6502 6503 6504
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args
6505
fn new_fn_ctxt(@local_ctxt cx, &span sp, ValueRef llfndecl) -> @fn_ctxt {
6506 6507 6508 6509 6510 6511 6512
    let ValueRef llretptr = llvm::LLVMGetParam(llfndecl, 0u);
    let ValueRef lltaskptr = llvm::LLVMGetParam(llfndecl, 1u);
    let ValueRef llenv = llvm::LLVMGetParam(llfndecl, 2u);
    let hashmap[ast::def_id, ValueRef] llargs = new_def_hash[ValueRef]();
    let hashmap[ast::def_id, ValueRef] llobjfields = new_def_hash[ValueRef]();
    let hashmap[ast::def_id, ValueRef] lllocals = new_def_hash[ValueRef]();
    let hashmap[ast::def_id, ValueRef] llupvars = new_def_hash[ValueRef]();
6513
    auto derived_tydescs =
6514
        map::mk_hashmap[ty::t, derived_tydesc_info](ty::hash_ty, ty::eq_ty);
6515
    auto llbbs = mk_standard_basic_blocks(llfndecl);
6516
    ret @rec(llfn=llfndecl,
6517
             lltaskptr=lltaskptr,
6518 6519
             llenv=llenv,
             llretptr=llretptr,
6520 6521 6522
             mutable llallocas=llbbs._0,
             mutable llcopyargs=llbbs._1,
             mutable llderivedtydescs=llbbs._2,
L
Lindsey Kuper 已提交
6523
             mutable llself=none[val_self_pair],
6524
             mutable lliterbody=none[ValueRef],
6525
             llargs=llargs,
6526
             llobjfields=llobjfields,
6527
             lllocals=lllocals,
6528
             llupvars=llupvars,
6529
             mutable lltydescs=vec::empty[ValueRef](),
6530
             derived_tydescs=derived_tydescs,
6531
             sp=sp,
6532
             lcx=cx);
6533 6534
}

6535

6536 6537 6538 6539 6540 6541 6542
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args

L
Lindsey Kuper 已提交
6543 6544 6545 6546 6547 6548 6549
// create_llargs_for_fn_args: Creates a mapping from incoming arguments to
// allocas created for them.
//
// When we translate a function, we need to map its incoming arguments to the
// spaces that have been created for them (by code in the llallocas field of
// the function's fn_ctxt).  create_llargs_for_fn_args populates the llargs
// field of the fn_ctxt with
6550 6551
fn create_llargs_for_fn_args(&@fn_ctxt cx, ast::proto proto,
                             option::t[ty_self_pair] ty_self, ty::t ret_ty,
6552 6553
                             &vec[ast::arg] args,
                             &vec[ast::ty_param] ty_params) {
L
Lindsey Kuper 已提交
6554 6555 6556
    // Skip the implicit arguments 0, 1, and 2.  TODO: Pull out 3u and define
    // it as a constant, since we're using it in several places in trans this
    // way.
6557

6558
    auto arg_n = 3u;
6559
    alt (ty_self) {
6560
        case (some(?tt)) {
6561
            cx.llself = some[val_self_pair](rec(v=cx.llenv, t=tt._1));
6562
        }
6563
        case (none) {
6564
            auto i = 0u;
6565 6566
            for (ast::ty_param tp in ty_params) {
                auto llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
6567
                assert (llarg as int != 0);
6568
                cx.lltydescs += [llarg];
6569
                arg_n += 1u;
6570
                i += 1u;
6571
            }
6572
        }
6573
    }
L
Lindsey Kuper 已提交
6574 6575 6576
    // If the function is actually an iter, populate the lliterbody field of
    // the function context with the ValueRef that we get from
    // llvm::LLVMGetParam for the iter's body.
6577

6578 6579
    if (proto == ast::proto_iter) {
        auto llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
6580
        assert (llarg as int != 0);
6581 6582 6583
        cx.lliterbody = some[ValueRef](llarg);
        arg_n += 1u;
    }
6584

L
Lindsey Kuper 已提交
6585 6586
    // Populate the llargs field of the function context with the ValueRefs
    // that we get from llvm::LLVMGetParam for each argument.
6587 6588
    for (ast::arg arg in args) {
        auto llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
6589
        assert (llarg as int != 0);
6590 6591 6592 6593 6594
        cx.llargs.insert(arg.id, llarg);
        arg_n += 1u;
    }
}

6595

6596 6597 6598
// 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.
6599
fn copy_any_self_to_alloca(@fn_ctxt fcx, option::t[ty_self_pair] ty_self) {
6600
    auto bcx = llallocas_block_ctxt(fcx);
6601
    alt ({ fcx.llself }) {
L
Lindsey Kuper 已提交
6602
        case (some(?pair)) {
6603
            alt (ty_self) {
L
Lindsey Kuper 已提交
6604
                case (some[ty_self_pair](?tt)) {
6605
                    auto a = alloca(bcx, tt._0);
L
Lindsey Kuper 已提交
6606
                    bcx.build.Store(pair.v, a);
6607
                    fcx.llself = some[val_self_pair](rec(v=a, t=pair.t));
6608 6609 6610
                }
            }
        }
6611
        case (_) { }
6612
    }
6613 6614
}

6615
fn copy_args_to_allocas(@fn_ctxt fcx, vec[ast::arg] args,
6616
                        vec[ty::arg] arg_tys) {
6617 6618
    auto bcx = new_raw_block_ctxt(fcx, fcx.llcopyargs);
    let uint arg_n = 0u;
6619
    for (ast::arg aarg in args) {
6620
        if (aarg.mode == ast::val) {
6621
            auto arg_t = type_of_arg(bcx.fcx.lcx, fcx.sp, arg_tys.(arg_n));
6622
            auto a = alloca(bcx, arg_t);
6623
            auto argval = bcx.fcx.llargs.get(aarg.id);
6624
            bcx.build.Store(argval, a);
6625
            // Overwrite the llargs entry for this arg with its alloca.
6626

6627
            bcx.fcx.llargs.insert(aarg.id, a);
6628
        }
6629 6630 6631 6632
        arg_n += 1u;
    }
}

6633
fn add_cleanups_for_args(&@block_ctxt bcx, vec[ast::arg] args,
6634
                         vec[ty::arg] arg_tys) {
6635
    let uint arg_n = 0u;
6636
    for (ast::arg aarg in args) {
6637
        if (aarg.mode == ast::val) {
6638 6639
            auto argval = bcx.fcx.llargs.get(aarg.id);
            find_scope_cx(bcx).cleanups +=
6640
                [clean(bind drop_slot(_, argval, arg_tys.(arg_n).ty))];
6641 6642 6643 6644 6645
        }
        arg_n += 1u;
    }
}

G
Graydon Hoare 已提交
6646
fn is_terminated(&@block_ctxt cx) -> bool {
6647 6648
    auto inst = llvm::LLVMGetLastInstruction(cx.llbb);
    ret llvm::LLVMIsATerminatorInst(inst) as int != 0;
6649 6650
}

6651
fn arg_tys_of_fn(&@crate_ctxt ccx, ast::ann ann) -> vec[ty::arg] {
6652
    alt (ty::struct(ccx.tcx, ty::ann_to_type(ccx.tcx, ann))) {
6653
        case (ty::ty_fn(_, ?arg_tys, _, _, _)) { ret arg_tys; }
6654 6655 6656
    }
}

6657 6658
fn ret_ty_of_fn_ty(&@crate_ctxt ccx, ty::t t) -> ty::t {
    alt (ty::struct(ccx.tcx, t)) {
6659
        case (ty::ty_fn(_, _, ?ret_ty, _, _)) { ret ret_ty; }
6660 6661 6662
    }
}

6663
fn ret_ty_of_fn(&@crate_ctxt ccx, ast::ann ann) -> ty::t {
6664
    ret ret_ty_of_fn_ty(ccx, ty::ann_to_type(ccx.tcx, ann));
6665 6666
}

L
Lindsey Kuper 已提交
6667
fn populate_fn_ctxt_from_llself(@fn_ctxt fcx, val_self_pair llself) {
6668
    auto bcx = llallocas_block_ctxt(fcx);
6669
    let vec[ty::t] field_tys = [];
6670
    for (ast::obj_field f in bcx.fcx.lcx.obj_fields) {
6671
        field_tys += [node_ann_type(bcx.fcx.lcx.ccx, f.ann)];
6672
    }
6673 6674 6675
    // Synthesize a tuple type for the fields so that GEP_tup_like() can work
    // its magic.

6676
    auto fields_tup_ty = ty::mk_imm_tup(fcx.lcx.ccx.tcx, field_tys);
6677
    auto n_typarams = vec::len[ast::ty_param](bcx.fcx.lcx.obj_typarams);
6678
    let TypeRef llobj_box_ty = T_obj_ptr(bcx.fcx.lcx.ccx.tn, n_typarams);
6679
    auto box_cell =
6680
        bcx.build.GEP(llself.v, [C_int(0), C_int(abi::obj_field_box)]);
6681 6682
    auto box_ptr = bcx.build.Load(box_cell);
    box_ptr = bcx.build.PointerCast(box_ptr, llobj_box_ty);
6683 6684 6685 6686
    auto obj_typarams =
        bcx.build.GEP(box_ptr,
                      [C_int(0), C_int(abi::box_rc_field_body),
                       C_int(abi::obj_body_elt_typarams)]);
6687 6688 6689
    // The object fields immediately follow the type parameters, so we skip
    // over them to get the pointer.

6690 6691
    auto et = llvm::LLVMGetElementType(val_ty(obj_typarams));
    auto obj_fields = bcx.build.Add(vp2i(bcx, obj_typarams), llsize_of(et));
6692 6693 6694
    // If we can (i.e. the type is statically sized), then cast the resulting
    // fields pointer to the appropriate LLVM type. If not, just leave it as
    // i8 *.
6695

6696
    if (!ty::type_has_dynamic_size(fcx.lcx.ccx.tcx, fields_tup_ty)) {
6697
        auto llfields_ty = type_of(fcx.lcx.ccx, fcx.sp, fields_tup_ty);
6698
        obj_fields = vi2p(bcx, obj_fields, T_ptr(llfields_ty));
6699
    } else { obj_fields = vi2p(bcx, obj_fields, T_ptr(T_i8())); }
6700
    let int i = 0;
6701
    for (ast::ty_param p in fcx.lcx.obj_typarams) {
6702 6703
        let ValueRef lltyparam =
            bcx.build.GEP(obj_typarams, [C_int(0), C_int(i)]);
6704
        lltyparam = bcx.build.Load(lltyparam);
6705
        fcx.lltydescs += [lltyparam];
6706 6707 6708
        i += 1;
    }
    i = 0;
6709
    for (ast::obj_field f in fcx.lcx.obj_fields) {
6710
        auto rslt = GEP_tup_like(bcx, fields_tup_ty, obj_fields, [0, i]);
6711
        bcx = llallocas_block_ctxt(fcx);
6712
        auto llfield = rslt.val;
6713
        fcx.llobjfields.insert(f.id, llfield);
6714 6715
        i += 1;
    }
6716
    fcx.llallocas = bcx.llbb;
6717 6718
}

6719

6720 6721 6722 6723 6724 6725 6726
// Ties up the llallocas -> llcopyargs -> llderivedtydescs -> lltop edges.
fn finish_fn(&@fn_ctxt fcx, BasicBlockRef lltop) {
    new_builder(fcx.llallocas).Br(fcx.llcopyargs);
    new_builder(fcx.llcopyargs).Br(fcx.llderivedtydescs);
    new_builder(fcx.llderivedtydescs).Br(lltop);
}

6727

6728 6729
// trans_fn: creates an LLVM function corresponding to a source language
// function.
6730
fn trans_fn(@local_ctxt cx, &span sp, &ast::_fn f, ValueRef llfndecl,
6731 6732
            option::t[ty_self_pair] ty_self, &vec[ast::ty_param] ty_params,
            &ast::ann ann) {
6733
    set_uwtable(llfndecl);
L
Lindsey Kuper 已提交
6734
    // Set up arguments to the function.
6735

6736 6737 6738 6739
    auto fcx = new_fn_ctxt(cx, sp, llfndecl);
    create_llargs_for_fn_args(fcx, f.proto, ty_self,
                              ret_ty_of_fn(cx.ccx, ann), f.decl.inputs,
                              ty_params);
6740
    copy_any_self_to_alloca(fcx, ty_self);
6741 6742 6743
    alt ({ fcx.llself }) {
        case (some(?llself)) { populate_fn_ctxt_from_llself(fcx, llself); }
        case (_) { }
6744
    }
6745
    auto arg_tys = arg_tys_of_fn(fcx.lcx.ccx, ann);
6746
    copy_args_to_allocas(fcx, f.decl.inputs, arg_tys);
L
Lindsey Kuper 已提交
6747 6748
    // Create the first basic block in the function and keep a handle on it to
    //  pass to finish_fn later.
6749

6750
    auto bcx = new_top_block_ctxt(fcx);
6751
    add_cleanups_for_args(bcx, f.decl.inputs, arg_tys);
6752
    auto lltop = bcx.llbb;
6753
    auto block_ty = node_ann_type(cx.ccx, f.body.node.a);
L
Lindsey Kuper 已提交
6754 6755 6756 6757
    // This call to trans_block is the place where we bridge between
    // translation calls that don't have a return value (trans_crate,
    // trans_mod, trans_item, trans_obj, et cetera) and those that do
    // (trans_block, trans_expr, et cetera).
6758

6759 6760 6761 6762 6763
    auto res =
        if (!ty::type_is_nil(cx.ccx.tcx, block_ty) &&
                !ty::type_is_bot(cx.ccx.tcx, block_ty)) {
            trans_block(bcx, f.body, save_in(fcx.llretptr))
        } else { trans_block(bcx, f.body, return) };
6764
    if (!is_terminated(res.bcx)) {
6765 6766
        // FIXME: until LLVM has a unit type, we are moving around
        // C_nil values rather than their void type.
6767

6768
        res.bcx.build.RetVoid();
6769
    }
L
Lindsey Kuper 已提交
6770
    // Insert the mandatory first few basic blocks before lltop.
6771

6772
    finish_fn(fcx, lltop);
6773 6774
}

6775

L
Lindsey Kuper 已提交
6776 6777
// Create a vtable for an object being translated.  Returns a pointer into
// read-only memory.
6778 6779
fn create_vtbl(@local_ctxt cx, TypeRef llself_ty, ty::t self_ty,
               &ast::_obj ob, &vec[ast::ty_param] ty_params) -> ValueRef {
6780 6781
    auto dtor = C_null(T_ptr(T_i8()));
    alt (ob.dtor) {
6782
        case (some(?d)) {
6783
            auto dtor_1 = trans_dtor(cx, llself_ty, self_ty, ty_params, d);
6784
            dtor = llvm::LLVMConstBitCast(dtor_1, val_ty(dtor));
6785
        }
6786
        case (none) { }
6787
    }
6788
    let vec[ValueRef] methods = [dtor];
6789
    fn meth_lteq(&@ast::method a, &@ast::method b) -> bool {
6790
        ret str::lteq(a.node.ident, b.node.ident);
6791
    }
6792 6793
    auto meths =
        std::sort::merge_sort[@ast::method](bind meth_lteq(_, _), ob.methods);
6794
    for (@ast::method m in meths) {
6795
        auto llfnty = T_nil();
6796
        alt (ty::struct(cx.ccx.tcx, node_ann_type(cx.ccx, m.node.ann))) {
6797
            case (ty::ty_fn(?proto, ?inputs, ?output, _, _)) {
6798 6799 6800 6801
                llfnty =
                    type_of_fn_full(cx.ccx, m.span, proto,
                                    some[TypeRef](llself_ty), inputs, output,
                                    vec::len[ast::ty_param](ty_params));
6802 6803
            }
        }
6804 6805
        let @local_ctxt mcx =
            @rec(path=cx.path + ["method", m.node.ident] with *cx);
6806
        let str s = mangle_internal_name_by_path(mcx.ccx, mcx.path);
6807 6808
        let ValueRef llfn =
            decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty);
6809 6810
        cx.ccx.item_ids.insert(m.node.id, llfn);
        cx.ccx.item_symbols.insert(m.node.id, s);
6811
        trans_fn(mcx, m.span, m.node.meth, llfn,
6812 6813
                 some[ty_self_pair](tup(llself_ty, self_ty)), ty_params,
                 m.node.ann);
6814
        methods += [llfn];
G
Graydon Hoare 已提交
6815
    }
6816
    auto vtbl = C_struct(methods);
6817 6818 6819
    auto vtbl_name = mangle_internal_name_by_path(cx.ccx, cx.path + ["vtbl"]);
    auto gvar =
        llvm::LLVMAddGlobal(cx.ccx.llmod, val_ty(vtbl), str::buf(vtbl_name));
6820 6821
    llvm::LLVMSetInitializer(gvar, vtbl);
    llvm::LLVMSetGlobalConstant(gvar, True);
6822 6823
    llvm::LLVMSetLinkage(gvar,
                         lib::llvm::LLVMInternalLinkage as llvm::Linkage);
6824
    ret gvar;
G
Graydon Hoare 已提交
6825 6826
}

6827 6828
fn trans_dtor(@local_ctxt cx, TypeRef llself_ty, ty::t self_ty,
              &vec[ast::ty_param] ty_params, &@ast::method dtor) -> ValueRef {
6829
    auto llfnty = T_dtor(cx.ccx, dtor.span, llself_ty);
6830
    let str s = mangle_internal_name_by_path(cx.ccx, cx.path + ["drop"]);
6831 6832 6833
    let ValueRef llfn = decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty);
    cx.ccx.item_ids.insert(dtor.node.id, llfn);
    cx.ccx.item_symbols.insert(dtor.node.id, s);
6834
    trans_fn(cx, dtor.span, dtor.node.meth, llfn,
6835 6836
             some[ty_self_pair](tup(llself_ty, self_ty)), ty_params,
             dtor.node.ann);
6837 6838 6839
    ret llfn;
}

6840

6841 6842
// trans_obj: creates an LLVM function that is the object constructor for the
// object being translated.
6843
fn trans_obj(@local_ctxt cx, &span sp, &ast::_obj ob, ast::def_id oid,
6844
             &vec[ast::ty_param] ty_params, &ast::ann ann) {
6845 6846 6847
    // To make a function, we have to create a function context and, inside
    // that, a number of block contexts for which code is generated.

6848 6849
    auto ccx = cx.ccx;
    auto llctor_decl = ccx.item_ids.get(oid);
6850 6851 6852 6853
    // Much like trans_fn, we must create an LLVM function, but since we're
    // starting with an ast::_obj rather than an ast::_fn, we have some setup
    // work to do.

L
Lindsey Kuper 已提交
6854 6855
    // The fields of our object will become the arguments to the function
    // we're creating.
6856

6857
    let vec[ast::arg] fn_args = [];
6858
    for (ast::obj_field f in ob.fields) {
6859 6860
        fn_args +=
            [rec(mode=ast::alias(false), ty=f.ty, ident=f.ident, id=f.id)];
6861
    }
6862
    auto fcx = new_fn_ctxt(cx, sp, llctor_decl);
L
Lindsey Kuper 已提交
6863
    // Both regular arguments and type parameters are handled here.
6864

6865 6866
    create_llargs_for_fn_args(fcx, ast::proto_fn, none[ty_self_pair],
                              ret_ty_of_fn(ccx, ann), fn_args, ty_params);
6867
    let vec[ty::arg] arg_tys = arg_tys_of_fn(ccx, ann);
6868
    copy_args_to_allocas(fcx, fn_args, arg_tys);
L
Lindsey Kuper 已提交
6869
    //  Create the first block context in the function and keep a handle on it
6870
    //  to pass to finish_fn later.
6871

6872 6873
    auto bcx = new_top_block_ctxt(fcx);
    auto lltop = bcx.llbb;
L
Lindsey Kuper 已提交
6874 6875
    // Pick up the type of this object by looking at our own output type, that
    // is, the output type of the object constructor we're building.
6876

6877
    auto self_ty = ret_ty_of_fn(ccx, ann);
6878
    auto llself_ty = type_of(ccx, sp, self_ty);
L
Lindsey Kuper 已提交
6879 6880 6881 6882 6883
    // Set up the two-word pair that we're going to return from the object
    // constructor we're building.  The two elements of this pair will be a
    // vtable pointer and a body pointer.  (llretptr already points to the
    // place where this two-word pair should go; it was pre-allocated by the
    // caller of the function.)
6884

6885
    auto pair = bcx.fcx.llretptr;
L
Lindsey Kuper 已提交
6886 6887 6888 6889
    // Grab onto the first and second elements of the pair.
    // abi::obj_field_vtbl and abi::obj_field_box simply specify words 0 and 1
    // of 'pair'.

6890 6891 6892 6893
    auto pair_vtbl =
        bcx.build.GEP(pair, [C_int(0), C_int(abi::obj_field_vtbl)]);
    auto pair_box =
        bcx.build.GEP(pair, [C_int(0), C_int(abi::obj_field_box)]);
L
Lindsey Kuper 已提交
6894 6895 6896 6897
    // Make a vtable for this object: a static array of pointers to functions.
    // It will be located in the read-only memory of the executable we're
    // creating and will contain ValueRefs for all of this object's methods.
    // create_vtbl returns a pointer to the vtable, which we store.
6898

L
Lindsey Kuper 已提交
6899
    auto vtbl = create_vtbl(cx, llself_ty, self_ty, ob, ty_params);
6900
    bcx.build.Store(vtbl, pair_vtbl);
L
Lindsey Kuper 已提交
6901 6902 6903
    // Next we have to take care of the other half of the pair we're
    // returning: a boxed (reference-counted) tuple containing a tydesc,
    // typarams, and fields.
6904

L
Lindsey Kuper 已提交
6905 6906 6907 6908 6909 6910 6911
    // FIXME: What about with_obj?  Do we have to think about it here?
    // (Pertains to issue #417.)

    let TypeRef llbox_ty = T_opaque_obj_ptr(ccx.tn);
    // FIXME: we should probably also allocate a box for empty objs that have
    // a dtor, since otherwise they are never dropped, and the dtor never
    // runs.
6912

6913
    if (vec::len[ast::ty_param](ty_params) == 0u &&
6914
            vec::len[ty::arg](arg_tys) == 0u) {
L
Lindsey Kuper 已提交
6915 6916 6917
        // If the object we're translating has no fields or type parameters,
        // there's not much to do.

6918
        // Store null into pair, if no args or typarams.
6919

6920 6921
        bcx.build.Store(C_null(llbox_ty), pair_box);
    } else {
L
Lindsey Kuper 已提交
6922 6923
        // Otherwise, we have to synthesize a big structural type for the
        // object body.
6924

6925
        let vec[ty::t] obj_fields = [];
6926
        for (ty::arg a in arg_tys) { vec::push[ty::t](obj_fields, a.ty); }
L
Lindsey Kuper 已提交
6927 6928
        // Tuple type for fields: [field, ...]

6929
        let ty::t fields_ty = ty::mk_imm_tup(ccx.tcx, obj_fields);
L
Lindsey Kuper 已提交
6930
        // Tuple type for typarams: [typaram, ...]
6931

6932
        auto tydesc_ty = ty::mk_type(ccx.tcx);
6933
        let vec[ty::t] tps = [];
6934
        for (ast::ty_param tp in ty_params) {
6935
            vec::push[ty::t](tps, tydesc_ty);
6936
        }
6937
        let ty::t typarams_ty = ty::mk_imm_tup(ccx.tcx, tps);
L
Lindsey Kuper 已提交
6938
        // Tuple type for body: [tydesc_ty, [typaram, ...], [field, ...]]
6939

6940 6941
        let ty::t body_ty =
            ty::mk_imm_tup(ccx.tcx, [tydesc_ty, typarams_ty, fields_ty]);
6942 6943
        // Hand this type we've synthesized off to trans_malloc_boxed, which
        // allocates a box, including space for a refcount.
6944

6945
        auto box = trans_malloc_boxed(bcx, body_ty);
6946
        bcx = box.bcx;
6947 6948
        // mk_imm_box throws a refcount into the type we're synthesizing, so
        // that it looks like: [rc, [tydesc_ty, [typaram, ...], [field, ...]]]
L
Lindsey Kuper 已提交
6949

6950
        let ty::t boxed_body_ty = ty::mk_imm_box(ccx.tcx, body_ty);
6951
        // Grab onto the refcount and body parts of the box we allocated.
6952

6953 6954 6955 6956 6957 6958 6959
        auto rc =
            GEP_tup_like(bcx, boxed_body_ty, box.val,
                         [0, abi::box_rc_field_refcnt]);
        bcx = rc.bcx;
        auto body =
            GEP_tup_like(bcx, boxed_body_ty, box.val,
                         [0, abi::box_rc_field_body]);
6960 6961
        bcx = body.bcx;
        bcx.build.Store(C_int(1), rc.val);
6962 6963
        // Put together a tydesc for the body, so that the object can later be
        // freed by calling through its tydesc.
6964 6965 6966 6967 6968 6969

        // Every object (not just those with type parameters) needs to have a
        // tydesc to describe its body, since all objects have unknown type to
        // the user of the object.  So the tydesc is needed to keep track of
        // the types of the object's fields, so that the fields can be freed
        // later.
6970

6971
        auto body_tydesc =
6972
            GEP_tup_like(bcx, body_ty, body.val,
6973
                         [0, abi::obj_body_elt_tydesc]);
6974
        bcx = body_tydesc.bcx;
6975 6976 6977
        auto ti = none[@tydesc_info];
        auto body_td = get_tydesc(bcx, body_ty, true, ti);
        lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
6978
        lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
6979 6980
        bcx = body_td.bcx;
        bcx.build.Store(body_td.val, body_tydesc.val);
6981 6982 6983 6984 6985 6986 6987
        // Copy the object's type parameters and fields into the space we
        // allocated for the object body.  (This is something like saving the
        // lexical environment of a function in its closure: the "captured
        // typarams" are any type parameters that are passed to the object
        // constructor and are then available to the object's methods.
        // Likewise for the object's fields.)

6988
        // Copy typarams into captured typarams.
6989

6990 6991
        auto body_typarams =
            GEP_tup_like(bcx, body_ty, body.val,
6992
                         [0, abi::obj_body_elt_typarams]);
6993 6994
        bcx = body_typarams.bcx;
        let int i = 0;
6995
        for (ast::ty_param tp in ty_params) {
6996
            auto typaram = bcx.fcx.lltydescs.(i);
6997 6998
            auto capture =
                GEP_tup_like(bcx, typarams_ty, body_typarams.val, [0, i]);
6999
            bcx = capture.bcx;
7000
            bcx = copy_val(bcx, INIT, capture.val, typaram, tydesc_ty).bcx;
7001 7002
            i += 1;
        }
7003
        // Copy args into body fields.
7004

7005
        auto body_fields =
7006
            GEP_tup_like(bcx, body_ty, body.val,
7007
                         [0, abi::obj_body_elt_fields]);
7008
        bcx = body_fields.bcx;
7009
        i = 0;
7010
        for (ast::obj_field f in ob.fields) {
7011
            auto arg = bcx.fcx.llargs.get(f.id);
7012
            arg = load_if_immediate(bcx, arg, arg_tys.(i).ty);
7013 7014
            auto field =
                GEP_tup_like(bcx, fields_ty, body_fields.val, [0, i]);
7015
            bcx = field.bcx;
7016
            bcx = copy_val(bcx, INIT, field.val, arg, arg_tys.(i).ty).bcx;
7017 7018 7019
            i += 1;
        }
        // Store box ptr in outer pair.
7020

7021
        auto p = bcx.build.PointerCast(box.val, llbox_ty);
7022
        bcx.build.Store(p, pair_box);
7023
    }
7024
    bcx.build.RetVoid();
L
Lindsey Kuper 已提交
7025
    // Insert the mandatory first few basic blocks before lltop.
7026

7027
    finish_fn(fcx, lltop);
7028 7029
}

7030 7031 7032
fn trans_tag_variant(@local_ctxt cx, ast::def_id tag_id,
                     &ast::variant variant, int index,
                     &vec[ast::ty_param] ty_params) {
7033
    if (vec::len[ast::variant_arg](variant.node.args) == 0u) {
7034
        ret; // nullary constructors are just constants
7035

7036
    }
7037
    // Translate variant arguments to function arguments.
7038

7039
    let vec[ast::arg] fn_args = [];
7040
    auto i = 0u;
7041
    for (ast::variant_arg varg in variant.node.args) {
7042 7043 7044 7045 7046
        fn_args +=
            [rec(mode=ast::alias(false),
                 ty=varg.ty,
                 ident="arg" + uint::to_str(i, 10u),
                 id=varg.id)];
7047
    }
7048
    assert (cx.ccx.item_ids.contains_key(variant.node.id));
7049
    let ValueRef llfndecl = cx.ccx.item_ids.get(variant.node.id);
7050
    auto fcx = new_fn_ctxt(cx, variant.span, llfndecl);
7051 7052 7053
    create_llargs_for_fn_args(fcx, ast::proto_fn, none[ty_self_pair],
                              ret_ty_of_fn(cx.ccx, variant.node.ann), fn_args,
                              ty_params);
7054
    let vec[ty::t] ty_param_substs = [];
7055
    i = 0u;
7056
    for (ast::ty_param tp in ty_params) {
7057
        ty_param_substs += [ty::mk_param(cx.ccx.tcx, i)];
7058
        i += 1u;
7059
    }
7060
    auto arg_tys = arg_tys_of_fn(cx.ccx, variant.node.ann);
7061
    copy_args_to_allocas(fcx, fn_args, arg_tys);
7062 7063
    auto bcx = new_top_block_ctxt(fcx);
    auto lltop = bcx.llbb;
7064 7065
    // Cast the tag to a type we can GEP into.

7066 7067 7068
    auto lltagptr =
        bcx.build.PointerCast(fcx.llretptr, T_opaque_tag_ptr(fcx.lcx.ccx.tn));
    auto lldiscrimptr = bcx.build.GEP(lltagptr, [C_int(0), C_int(0)]);
7069
    bcx.build.Store(C_int(index), lldiscrimptr);
7070
    auto llblobptr = bcx.build.GEP(lltagptr, [C_int(0), C_int(1)]);
7071
    i = 0u;
7072
    for (ast::variant_arg va in variant.node.args) {
7073 7074 7075
        auto rslt =
            GEP_tag(bcx, llblobptr, tag_id, variant.node.id, ty_param_substs,
                    i as int);
7076 7077
        bcx = rslt.bcx;
        auto lldestptr = rslt.val;
7078 7079 7080 7081
        // If this argument to this function is a tag, it'll have come in to
        // this function as an opaque blob due to the way that type_of()
        // works. So we have to cast to the destination's view of the type.

7082 7083
        auto llargptr =
            bcx.build.PointerCast(fcx.llargs.get(va.id), val_ty(lldestptr));
7084 7085
        auto arg_ty = arg_tys.(i).ty;
        auto llargval;
7086 7087
        if (ty::type_is_structural(cx.ccx.tcx, arg_ty) ||
                ty::type_has_dynamic_size(cx.ccx.tcx, arg_ty)) {
7088
            llargval = llargptr;
7089
        } else { llargval = bcx.build.Load(llargptr); }
7090
        rslt = copy_val(bcx, INIT, lldestptr, llargval, arg_ty);
7091
        bcx = rslt.bcx;
7092 7093 7094
        i += 1u;
    }
    bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
7095
    bcx.build.RetVoid();
7096
    finish_fn(fcx, lltop);
7097 7098
}

7099

7100 7101 7102
// FIXME: this should do some structural hash-consing to avoid
// duplicate constants. I think. Maybe LLVM has a magical mode
// that does so later on?
7103
fn trans_const_expr(&@crate_ctxt cx, @ast::expr e) -> ValueRef {
7104
    alt (e.node) {
7105
        case (ast::expr_lit(?lit, ?ann)) { ret trans_lit(cx, *lit, ann); }
7106 7107 7108
        case (_) {
            cx.sess.span_unimpl(e.span, "consts that's not a plain literal");
        }
7109 7110 7111
    }
}

7112 7113
fn trans_const(&@crate_ctxt cx, @ast::expr e, &ast::def_id cid,
               &ast::ann ann) {
7114 7115
    auto t = node_ann_type(cx, ann);
    auto v = trans_const_expr(cx, e);
7116 7117
    // The scalars come back as 1st class LLVM vals
    // which we have to stick into global constants.
7118

7119
    auto g = cx.consts.get(cid);
7120 7121
    llvm::LLVMSetInitializer(g, v);
    llvm::LLVMSetGlobalConstant(g, True);
7122 7123
}

7124
fn trans_item(@local_ctxt cx, &ast::item item) {
7125
    alt (item.node) {
7126
        case (ast::item_fn(?name, ?f, ?tps, _, ?fid, ?ann)) {
7127
            auto sub_cx = extend_path(cx, name);
7128
            auto llfndecl = cx.ccx.item_ids.get(fid);
7129 7130
            trans_fn(sub_cx, item.span, f, llfndecl, none[ty_self_pair], tps,
                     ann);
7131
        }
7132
        case (ast::item_obj(?name, ?ob, ?tps, _, ?oid, ?ann)) {
7133 7134 7135
            auto sub_cx =
                @rec(obj_typarams=tps, obj_fields=ob.fields
                     with *extend_path(cx, name));
7136
            trans_obj(sub_cx, item.span, ob, oid.ctor, tps, ann);
7137
        }
7138
        case (ast::item_mod(?name, ?m, _, _)) {
7139 7140 7141
            auto sub_cx =
                @rec(path=cx.path + [name],
                     module_path=cx.module_path + [name] with *cx);
7142
            trans_mod(sub_cx, m);
7143
        }
7144
        case (ast::item_tag(?name, ?variants, ?tps, _, ?tag_id, _)) {
7145
            auto sub_cx = extend_path(cx, name);
7146
            auto i = 0;
7147
            for (ast::variant variant in variants) {
7148
                trans_tag_variant(sub_cx, tag_id, variant, i, tps);
7149
                i += 1;
7150 7151
            }
        }
7152
        case (ast::item_const(?name, _, ?expr, _, ?cid, ?ann)) {
7153
            trans_const(cx.ccx, expr, cid, ann);
7154
        }
7155
        case (_) {/* fall through */ }
7156 7157 7158
    }
}

7159
fn trans_mod(@local_ctxt cx, &ast::_mod m) {
7160
    for (@ast::item item in m.items) { trans_item(cx, *item); }
7161 7162
}

7163 7164
fn get_pair_fn_ty(TypeRef llpairty) -> TypeRef {
    // Bit of a kludge: pick the fn typeref out of the pair.
7165

7166
    ret struct_elt(llpairty, 0u);
7167 7168
}

7169 7170
fn decl_fn_and_pair(&@crate_ctxt ccx, &span sp, vec[str] path, str flav,
                    vec[ast::ty_param] ty_params, &ast::ann ann,
7171
                    ast::def_id id) {
7172
    auto llfty;
7173
    alt (ty::struct(ccx.tcx, node_ann_type(ccx, ann))) {
7174
        case (ty::ty_fn(?proto, ?inputs, ?output, _, _)) {
7175 7176 7177
            llfty =
                type_of_fn(ccx, sp, proto, inputs, output,
                           vec::len[ast::ty_param](ty_params));
7178 7179
        }
        case (_) {
7180
            ccx.sess.bug("decl_fn_and_pair(): fn item doesn't have fn type!");
7181 7182
        }
    }
7183 7184
    let bool is_main =
        str::eq(vec::top(path), "main") && !ccx.sess.get_opts().shared;
7185
    // Declare the function itself.
7186

7187 7188 7189 7190
    let str s =
        if (is_main) {
            "_rust_main"
        } else { mangle_internal_name_by_path(ccx, path) };
7191
    let ValueRef llfn = decl_internal_fastcall_fn(ccx.llmod, s, llfty);
7192
    // Declare the global constant pair that points to it.
7193

7194
    let str ps = mangle_exported_name(ccx, path, node_ann_type(ccx, ann));
7195
    register_fn_pair(ccx, ps, llfty, llfn, id);
7196
    if (is_main) {
7197 7198 7199
        if (ccx.main_fn != none[ValueRef]) {
            ccx.sess.span_err(sp, "multiple 'main' functions");
        }
7200 7201
        llvm::LLVMSetLinkage(llfn,
                             lib::llvm::LLVMExternalLinkage as llvm::Linkage);
7202 7203
        ccx.main_fn = some(llfn);
    }
7204 7205
}

7206 7207
fn create_fn_pair(&@crate_ctxt cx, str ps, TypeRef llfnty, ValueRef llfn,
                  bool external) -> ValueRef {
7208 7209
    auto gvar =
        llvm::LLVMAddGlobal(cx.llmod, T_fn_pair(cx.tn, llfnty), str::buf(ps));
7210
    auto pair = C_struct([llfn, C_null(T_opaque_closure_ptr(cx.tn))]);
7211 7212
    llvm::LLVMSetInitializer(gvar, pair);
    llvm::LLVMSetGlobalConstant(gvar, True);
7213
    if (!external) {
7214 7215
        llvm::LLVMSetLinkage(gvar,
                             lib::llvm::LLVMInternalLinkage as llvm::Linkage);
7216
    }
7217 7218
    ret gvar;
}
7219

7220 7221 7222
fn register_fn_pair(&@crate_ctxt cx, str ps, TypeRef llfnty, ValueRef llfn,
                    ast::def_id id) {
    // FIXME: We should also hide the unexported pairs in crates.
7223 7224 7225

    auto gvar =
        create_fn_pair(cx, ps, llfnty, llfn, cx.sess.get_opts().shared);
7226
    cx.item_ids.insert(id, llfn);
P
Patrick Walton 已提交
7227
    cx.item_symbols.insert(id, ps);
7228 7229 7230
    cx.fn_pairs.insert(id, gvar);
}

7231

7232
// Returns the number of type parameters that the given native function has.
7233
fn native_fn_ty_param_count(&@crate_ctxt cx, &ast::def_id id) -> uint {
7234 7235 7236
    auto count;
    auto native_item = cx.native_items.get(id);
    alt (native_item.node) {
7237
        case (ast::native_item_ty(_, _)) {
7238
            cx.sess.bug("decl_native_fn_and_pair(): native fn isn't " +
7239
                            "actually a fn");
7240
        }
7241
        case (ast::native_item_fn(_, _, _, ?tps, _, _)) {
7242
            count = vec::len[ast::ty_param](tps);
7243 7244 7245 7246 7247
        }
    }
    ret count;
}

7248
fn native_fn_wrapper_type(&@crate_ctxt cx, &span sp, uint ty_param_count,
7249
                          ty::t x) -> TypeRef {
7250 7251
    alt (ty::struct(cx.tcx, x)) {
        case (ty::ty_native_fn(?abi, ?args, ?out)) {
7252
            ret type_of_fn(cx, sp, ast::proto_fn, args, out, ty_param_count);
7253 7254 7255 7256
        }
    }
}

7257 7258
fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, vec[str] path,
                           str name, &ast::ann ann, ast::def_id id) {
7259
    auto num_ty_param = native_fn_ty_param_count(ccx, id);
7260
    // Declare the wrapper.
7261

7262
    auto t = node_ann_type(ccx, ann);
7263
    auto wrapper_type = native_fn_wrapper_type(ccx, sp, num_ty_param, t);
7264
    let str s = mangle_internal_name_by_path(ccx, path);
7265 7266
    let ValueRef wrapper_fn =
        decl_internal_fastcall_fn(ccx.llmod, s, wrapper_type);
7267
    // Declare the global constant pair that points to it.
7268

7269
    let str ps = mangle_exported_name(ccx, path, node_ann_type(ccx, ann));
7270
    register_fn_pair(ccx, ps, wrapper_type, wrapper_fn, id);
7271
    // Build the wrapper.
7272

7273
    auto fcx = new_fn_ctxt(new_local_ctxt(ccx), sp, wrapper_fn);
7274
    auto bcx = new_top_block_ctxt(fcx);
7275
    auto lltop = bcx.llbb;
7276
    // Declare the function itself.
7277

7278
    auto item = ccx.native_items.get(id);
7279
    auto fn_type = node_ann_type(ccx, ann); // NB: has no type params
7280

7281
    auto abi = ty::ty_fn_abi(ccx.tcx, fn_type);
7282 7283 7284
    auto llfnty =
        type_of_native_fn(ccx, sp, abi, ty::ty_fn_args(ccx.tcx, fn_type),
                          ty::ty_fn_ret(ccx.tcx, fn_type), num_ty_param);
7285 7286 7287 7288
    // FIXME: If the returned type is not nil, then we assume it's 32 bits
    // wide. This is obviously wildly unsafe. We should have a better FFI
    // that allows types of different sizes to be returned.

7289 7290
    auto rty_is_nil =
        ty::type_is_nil(ccx.tcx, ty::ty_fn_ret(ccx.tcx, fn_type));
7291
    auto pass_task;
7292
    auto cast_to_i32;
7293
    alt (abi) {
7294
        case (ast::native_abi_rust) { pass_task = true; cast_to_i32 = true; }
7295
        case (ast::native_abi_rust_intrinsic) {
7296
            pass_task = true;
7297
            cast_to_i32 = false;
7298
        }
7299
        case (ast::native_abi_cdecl) {
7300
            pass_task = false;
7301
            cast_to_i32 = true;
7302
        }
7303
        case (ast::native_abi_llvm) {
7304
            pass_task = false;
7305 7306 7307 7308 7309 7310
            cast_to_i32 = false;
        }
    }
    auto lltaskptr;
    if (cast_to_i32) {
        lltaskptr = vp2i(bcx, fcx.lltaskptr);
7311
    } else { lltaskptr = fcx.lltaskptr; }
7312 7313
    let vec[ValueRef] call_args = [];
    if (pass_task) { call_args += [lltaskptr]; }
7314
    auto arg_n = 3u;
7315
    for each (uint i in uint::range(0u, num_ty_param)) {
7316
        auto llarg = llvm::LLVMGetParam(fcx.llfn, arg_n);
7317
        fcx.lltydescs += [llarg];
7318 7319
        assert (llarg as int != 0);
        if (cast_to_i32) {
7320
            call_args += [vp2i(bcx, llarg)];
7321
        } else { call_args += [llarg]; }
7322
        arg_n += 1u;
7323
    }
7324 7325
    fn convert_arg_to_i32(&@block_ctxt cx, ValueRef v, ty::t t, ty::mode mode)
       -> ValueRef {
7326 7327
        if (mode == ty::mo_val) {
            if (ty::type_is_integral(cx.fcx.lcx.ccx.tcx, t)) {
7328
                auto lldsttype = T_int();
7329
                auto llsrctype = type_of(cx.fcx.lcx.ccx, cx.sp, t);
7330
                if (llvm::LLVMGetIntTypeWidth(lldsttype) >
7331
                        llvm::LLVMGetIntTypeWidth(llsrctype)) {
7332
                    ret cx.build.ZExtOrBitCast(v, T_int());
7333
                }
7334
                ret cx.build.TruncOrBitCast(v, T_int());
7335
            }
7336
            if (ty::type_is_fp(cx.fcx.lcx.ccx.tcx, t)) {
7337
                ret cx.build.FPToSI(v, T_int());
7338 7339
            }
        }
7340
        ret vp2i(cx, v);
7341
    }
7342
    fn trans_simple_native_abi(&@block_ctxt bcx, str name,
7343
                               &mutable vec[ValueRef] call_args,
7344 7345
                               ty::t fn_type, uint first_arg_n) ->
       tup(ValueRef, ValueRef) {
7346
        let vec[TypeRef] call_arg_tys = [];
7347
        for (ValueRef arg in call_args) { call_arg_tys += [val_ty(arg)]; }
7348 7349
        auto llnativefnty =
            T_fn(call_arg_tys,
7350
                 type_of(bcx.fcx.lcx.ccx, bcx.sp,
7351
                         ty::ty_fn_ret(bcx.fcx.lcx.ccx.tcx, fn_type)));
7352 7353 7354
        auto llnativefn =
            get_extern_fn(bcx.fcx.lcx.ccx.externs, bcx.fcx.lcx.ccx.llmod,
                          name, lib::llvm::LLVMCCallConv, llnativefnty);
7355 7356 7357 7358
        auto r = bcx.build.Call(llnativefn, call_args);
        auto rptr = bcx.fcx.llretptr;
        ret tup(r, rptr);
    }
7359
    auto args = ty::ty_fn_args(ccx.tcx, fn_type);
7360
    // Build up the list of arguments.
7361

7362
    let vec[tup(ValueRef, ty::t)] drop_args = [];
7363
    auto i = arg_n;
7364 7365
    for (ty::arg arg in args) {
        auto llarg = llvm::LLVMGetParam(fcx.llfn, i);
7366 7367 7368
        assert (llarg as int != 0);
        if (cast_to_i32) {
            auto llarg_i32 = convert_arg_to_i32(bcx, llarg, arg.ty, arg.mode);
7369
            call_args += [llarg_i32];
7370 7371
        } else { call_args += [llarg]; }
        if (arg.mode == ty::mo_val) { drop_args += [tup(llarg, arg.ty)]; }
7372 7373
        i += 1u;
    }
7374 7375 7376
    auto r;
    auto rptr;
    alt (abi) {
7377
        case (ast::native_abi_llvm) {
7378 7379 7380 7381
            auto result =
                trans_simple_native_abi(bcx, name, call_args, fn_type, arg_n);
            r = result._0;
            rptr = result._1;
7382
        }
7383
        case (ast::native_abi_rust_intrinsic) {
7384
            auto external_name = "rust_intrinsic_" + name;
7385 7386 7387 7388 7389
            auto result =
                trans_simple_native_abi(bcx, external_name, call_args,
                                        fn_type, arg_n);
            r = result._0;
            rptr = result._1;
7390
        }
7391
        case (_) {
7392 7393
            r =
                trans_native_call(bcx.build, ccx.glues, lltaskptr,
7394 7395 7396
                                  ccx.externs, ccx.tn, ccx.llmod, name,
                                  pass_task, call_args);
            rptr = bcx.build.BitCast(fcx.llretptr, T_ptr(T_i32()));
G
Graydon Hoare 已提交
7397
        }
7398
    }
7399 7400 7401 7402
    // We don't store the return value if it's nil, to avoid stomping on a nil
    // pointer. This is the only concession made to non-i32 return values. See
    // the FIXME above.

7403
    if (!rty_is_nil) { bcx.build.Store(r, rptr); }
7404
    for (tup(ValueRef, ty::t) d in drop_args) {
7405 7406
        bcx = drop_ty(bcx, d._0, d._1).bcx;
    }
7407
    bcx.build.RetVoid();
7408
    finish_fn(fcx, lltop);
7409 7410
}

7411
fn item_path(&@ast::item item) -> vec[str] {
7412
    alt (item.node) {
7413 7414
        case (ast::item_fn(?name, _, _, _, _, _)) { ret [name]; }
        case (ast::item_obj(?name, _, _, _, _, _)) { ret [name]; }
7415
        case (ast::item_mod(?name, _, _, _)) { ret [name]; }
7416
        case (_) { ret []; }
7417 7418 7419
    }
}

7420 7421
fn collect_native_item(@crate_ctxt ccx, &@ast::native_item i, &vec[str] pt,
                       &vt[vec[str]] v) {
7422
    alt (i.node) {
7423
        case (ast::native_item_fn(?name, _, _, _, ?fid, ?ann)) {
7424 7425
            ccx.native_items.insert(fid, i);
            if (!ccx.obj_methods.contains_key(fid)) {
7426
                decl_native_fn_and_pair(ccx, i.span, pt, name, ann, fid);
7427
            }
7428
        }
7429
        case (ast::native_item_ty(_, ?tid)) {
7430
            ccx.native_items.insert(tid, i);
7431 7432 7433
        }
    }
}
7434

7435 7436
fn collect_item_1(@crate_ctxt ccx, &@ast::item i, &vec[str] pt,
                  &vt[vec[str]] v) {
7437
    visit::visit_item(i, pt + item_path(i), v);
7438
    alt (i.node) {
7439
        case (ast::item_const(?name, _, _, _, ?cid, ?ann)) {
7440
            auto typ = node_ann_type(ccx, ann);
7441 7442 7443 7444 7445 7446
            auto g =
                llvm::LLVMAddGlobal(ccx.llmod, type_of(ccx, i.span, typ),
                                    str::buf(ccx.names.next(name)));
            llvm::LLVMSetLinkage(g,
                                 lib::llvm::LLVMInternalLinkage as
                                     llvm::Linkage);
7447 7448
            ccx.items.insert(cid, i);
            ccx.consts.insert(cid, g);
7449
        }
7450
        case (ast::item_mod(?name, ?m, _, ?mid)) { ccx.items.insert(mid, i); }
7451
        case (ast::item_native_mod(_, _, _, ?mid)) {
7452 7453
            ccx.items.insert(mid, i);
        }
7454
        case (ast::item_ty(_, _, _, _, ?did, _)) { ccx.items.insert(did, i); }
7455
        case (ast::item_tag(?name, ?variants, ?tps, _, ?tag_id, _)) {
7456
            ccx.items.insert(tag_id, i);
7457
        }
7458
        case (_) { }
7459 7460 7461
    }
}

7462 7463
fn collect_item_2(&@crate_ctxt ccx, &@ast::item i, &vec[str] pt,
                  &vt[vec[str]] v) {
7464 7465
    auto new_pt = pt + item_path(i);
    visit::visit_item(i, new_pt, v);
7466
    alt (i.node) {
7467
        case (ast::item_fn(?name, ?f, ?tps, _, ?fid, ?ann)) {
7468 7469
            ccx.items.insert(fid, i);
            if (!ccx.obj_methods.contains_key(fid)) {
7470
                decl_fn_and_pair(ccx, i.span, new_pt, "fn", tps, ann, fid);
7471
            }
7472
        }
7473
        case (ast::item_obj(?name, ?ob, ?tps, _, ?oid, ?ann)) {
7474
            ccx.items.insert(oid.ctor, i);
7475 7476
            decl_fn_and_pair(ccx, i.span, new_pt, "obj_ctor", tps, ann,
                             oid.ctor);
7477
            for (@ast::method m in ob.methods) {
7478
                ccx.obj_methods.insert(m.node.id, ());
7479
            }
7480
        }
7481
        case (_) { }
7482 7483 7484
    }
}

7485
fn collect_items(&@crate_ctxt ccx, @ast::crate crate) {
7486
    auto visitor0 = visit::default_visitor();
7487 7488 7489 7490 7491
    auto visitor1 =
        @rec(visit_native_item=bind collect_native_item(ccx, _, _, _),
             visit_item=bind collect_item_1(ccx, _, _, _) with *visitor0);
    auto visitor2 =
        @rec(visit_item=bind collect_item_2(ccx, _, _, _) with *visitor0);
7492 7493 7494 7495
    visit::visit_crate(*crate, [], visit::vtor(visitor1));
    visit::visit_crate(*crate, [], visit::vtor(visitor2));
}

7496 7497
fn collect_tag_ctor(@crate_ctxt ccx, &@ast::item i, &vec[str] pt,
                    &vt[vec[str]] v) {
7498 7499
    auto new_pt = pt + item_path(i);
    visit::visit_item(i, new_pt, v);
7500
    alt (i.node) {
7501
        case (ast::item_tag(_, ?variants, ?tps, _, _, _)) {
7502
            for (ast::variant variant in variants) {
7503
                if (vec::len[ast::variant_arg](variant.node.args) != 0u) {
7504
                    decl_fn_and_pair(ccx, i.span,
7505 7506
                                     new_pt + [variant.node.name], "tag", tps,
                                     variant.node.ann, variant.node.id);
7507 7508 7509
                }
            }
        }
7510
        case (_) {/* fall through */ }
7511 7512 7513
    }
}

7514
fn collect_tag_ctors(&@crate_ctxt ccx, @ast::crate crate) {
7515 7516 7517
    auto visitor =
        @rec(visit_item=bind collect_tag_ctor(ccx, _, _, _)
             with *visit::default_visitor());
7518
    visit::visit_crate(*crate, [], visit::vtor(visitor));
7519 7520
}

7521

7522 7523 7524
// The constant translation pass.
fn trans_constant(@crate_ctxt ccx, &@ast::item it, &vec[str] pt,
                  &vt[vec[str]] v) {
7525 7526
    auto new_pt = pt + item_path(it);
    visit::visit_item(it, new_pt, v);
7527
    alt (it.node) {
7528
        case (ast::item_tag(?ident, ?variants, _, _, ?tag_id, _)) {
7529
            auto i = 0u;
7530
            auto n_variants = vec::len[ast::variant](variants);
7531 7532
            while (i < n_variants) {
                auto variant = variants.(i);
7533
                auto discrim_val = C_int(i as int);
7534
                auto p = new_pt + [ident, variant.node.name, "discrim"];
7535
                auto s = mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx));
7536 7537
                auto discrim_gvar =
                    llvm::LLVMAddGlobal(ccx.llmod, T_int(), str::buf(s));
7538 7539
                llvm::LLVMSetInitializer(discrim_gvar, discrim_val);
                llvm::LLVMSetGlobalConstant(discrim_gvar, True);
7540 7541
                ccx.discrims.insert(variant.node.id, discrim_gvar);
                ccx.discrim_symbols.insert(variant.node.id, s);
7542 7543 7544
                i += 1u;
            }
        }
7545
        case (ast::item_const(?name, _, ?expr, _, ?cid, ?ann)) {
7546 7547
            // FIXME: The whole expr-translation system needs cloning to deal
            // with consts.
7548

7549
            auto v = C_int(1);
7550
            ccx.item_ids.insert(cid, v);
7551 7552 7553
            auto s =
                mangle_exported_name(ccx, new_pt + [name],
                                     node_ann_type(ccx, ann));
7554
            ccx.item_symbols.insert(cid, s);
7555
        }
7556
        case (_) { }
7557 7558 7559
    }
}

7560
fn trans_constants(&@crate_ctxt ccx, @ast::crate crate) {
7561 7562 7563
    auto visitor =
        @rec(visit_item=bind trans_constant(ccx, _, _, _)
             with *visit::default_visitor());
7564
    visit::visit_crate(*crate, [], visit::vtor(visitor));
7565 7566
}

G
Graydon Hoare 已提交
7567
fn vp2i(&@block_ctxt cx, ValueRef v) -> ValueRef {
7568 7569 7570
    ret cx.build.PtrToInt(v, T_int());
}

G
Graydon Hoare 已提交
7571
fn vi2p(&@block_ctxt cx, ValueRef v, TypeRef t) -> ValueRef {
7572 7573 7574
    ret cx.build.IntToPtr(v, t);
}

7575
fn p2i(ValueRef v) -> ValueRef { ret llvm::LLVMConstPtrToInt(v, T_int()); }
7576

7577
fn i2p(ValueRef v, TypeRef t) -> ValueRef {
7578
    ret llvm::LLVMConstIntToPtr(v, t);
7579 7580
}

G
Graydon Hoare 已提交
7581
fn create_typedefs(&@crate_ctxt cx) {
7582 7583
    llvm::LLVMAddTypeName(cx.llmod, str::buf("task"), T_task(cx.tn));
    llvm::LLVMAddTypeName(cx.llmod, str::buf("tydesc"), T_tydesc(cx.tn));
7584 7585
}

7586 7587 7588 7589 7590 7591 7592 7593 7594
fn declare_intrinsics(ModuleRef llmod) -> hashmap[str, ValueRef] {
    let vec[TypeRef] T_memmove32_args =
        [T_ptr(T_i8()), T_ptr(T_i8()), T_i32(), T_i32(), T_i1()];
    let vec[TypeRef] T_memmove64_args =
        [T_ptr(T_i8()), T_ptr(T_i8()), T_i64(), T_i32(), T_i1()];
    let vec[TypeRef] T_memset32_args =
        [T_ptr(T_i8()), T_i8(), T_i32(), T_i32(), T_i1()];
    let vec[TypeRef] T_memset64_args =
        [T_ptr(T_i8()), T_i8(), T_i64(), T_i32(), T_i1()];
7595
    let vec[TypeRef] T_trap_args = [];
7596 7597 7598 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609
    auto memmove32 =
        decl_cdecl_fn(llmod, "llvm.memmove.p0i8.p0i8.i32",
                      T_fn(T_memmove32_args, T_void()));
    auto memmove64 =
        decl_cdecl_fn(llmod, "llvm.memmove.p0i8.p0i8.i64",
                      T_fn(T_memmove64_args, T_void()));
    auto memset32 =
        decl_cdecl_fn(llmod, "llvm.memset.p0i8.i32",
                      T_fn(T_memset32_args, T_void()));
    auto memset64 =
        decl_cdecl_fn(llmod, "llvm.memset.p0i8.i64",
                      T_fn(T_memset64_args, T_void()));
    auto trap =
        decl_cdecl_fn(llmod, "llvm.trap", T_fn(T_trap_args, T_void()));
7610
    auto intrinsics = new_str_hash[ValueRef]();
7611 7612
    intrinsics.insert("llvm.memmove.p0i8.p0i8.i32", memmove32);
    intrinsics.insert("llvm.memmove.p0i8.p0i8.i64", memmove64);
7613 7614
    intrinsics.insert("llvm.memset.p0i8.i32", memset32);
    intrinsics.insert("llvm.memset.p0i8.i64", memset64);
7615 7616
    intrinsics.insert("llvm.trap", trap);
    ret intrinsics;
7617 7618
}

G
Graydon Hoare 已提交
7619
fn trace_str(&@block_ctxt cx, str s) {
7620
    cx.build.Call(cx.fcx.lcx.ccx.upcalls.trace_str,
7621
                  [cx.fcx.lltaskptr, C_cstr(cx.fcx.lcx.ccx, s)]);
7622 7623
}

G
Graydon Hoare 已提交
7624
fn trace_word(&@block_ctxt cx, ValueRef v) {
7625
    cx.build.Call(cx.fcx.lcx.ccx.upcalls.trace_word, [cx.fcx.lltaskptr, v]);
7626 7627
}

G
Graydon Hoare 已提交
7628
fn trace_ptr(&@block_ctxt cx, ValueRef v) {
7629 7630 7631
    trace_word(cx, cx.build.PtrToInt(v, T_int()));
}

G
Graydon Hoare 已提交
7632
fn trap(&@block_ctxt bcx) {
7633
    let vec[ValueRef] v = [];
7634
    bcx.build.Call(bcx.fcx.lcx.ccx.intrinsics.get("llvm.trap"), v);
7635
}
7636

7637
fn decl_no_op_type_glue(ModuleRef llmod, type_names tn) -> ValueRef {
7638
    auto ty = T_fn([T_taskptr(tn), T_ptr(T_i8())], T_void());
7639
    ret decl_fastcall_fn(llmod, abi::no_op_type_glue_name(), ty);
7640 7641 7642
}

fn make_no_op_type_glue(ValueRef fun) {
7643
    auto bb_name = str::buf("_rust_no_op_type_glue_bb");
7644
    auto llbb = llvm::LLVMAppendBasicBlock(fun, bb_name);
7645
    new_builder(llbb).RetVoid();
7646 7647
}

G
Graydon Hoare 已提交
7648
fn vec_fill(&@block_ctxt bcx, ValueRef v) -> ValueRef {
7649 7650
    ret bcx.build.Load(bcx.build.GEP(v,
                                     [C_int(0), C_int(abi::vec_elt_fill)]));
7651 7652
}

G
Graydon Hoare 已提交
7653
fn vec_p0(&@block_ctxt bcx, ValueRef v) -> ValueRef {
7654
    auto p = bcx.build.GEP(v, [C_int(0), C_int(abi::vec_elt_data)]);
7655 7656 7657
    ret bcx.build.PointerCast(p, T_ptr(T_i8()));
}

G
Graydon Hoare 已提交
7658
fn make_glues(ModuleRef llmod, &type_names tn) -> @glue_fns {
7659
    ret @rec(no_op_type_glue=decl_no_op_type_glue(llmod, tn));
7660 7661
}

7662
fn make_common_glue(&session::session sess, &str output) {
7663
    // FIXME: part of this is repetitive and is probably a good idea
7664
    // to autogen it.
7665

7666
    auto llmod =
7667
        llvm::LLVMModuleCreateWithNameInContext(str::buf("rust_out"),
7668
                                                llvm::LLVMGetGlobalContext());
7669 7670
    llvm::LLVMSetDataLayout(llmod, str::buf(x86::get_data_layout()));
    llvm::LLVMSetTarget(llmod, str::buf(x86::get_target_triple()));
7671
    auto td = mk_target_data(x86::get_data_layout());
7672
    auto tn = mk_type_names();
7673
    auto intrinsics = declare_intrinsics(llmod);
7674
    llvm::LLVMSetModuleInlineAsm(llmod, str::buf(x86::get_module_asm()));
7675
    auto glues = make_glues(llmod, tn);
7676
    link::write::run_passes(sess, llmod, output);
7677 7678
}

G
Graydon Hoare 已提交
7679
fn create_module_map(&@crate_ctxt ccx) -> ValueRef {
7680
    auto elttype = T_struct([T_int(), T_int()]);
7681
    auto maptype = T_array(elttype, ccx.module_data.size() + 1u);
7682 7683
    auto map =
        llvm::LLVMAddGlobal(ccx.llmod, maptype, str::buf("_rust_mod_map"));
7684
    let vec[ValueRef] elts = [];
7685
    for each (@tup(str, ValueRef) item in ccx.module_data.items()) {
7686
        auto elt = C_struct([p2i(C_cstr(ccx, item._0)), p2i(item._1)]);
7687
        vec::push[ValueRef](elts, elt);
7688
    }
7689
    auto term = C_struct([C_int(0), C_int(0)]);
7690
    vec::push[ValueRef](elts, term);
7691
    llvm::LLVMSetInitializer(map, C_array(elttype, elts));
7692 7693 7694
    ret map;
}

7695

7696
// FIXME use hashed metadata instead of crate names once we have that
G
Graydon Hoare 已提交
7697
fn create_crate_map(&@crate_ctxt ccx) -> ValueRef {
7698
    let vec[ValueRef] subcrates = [];
7699 7700 7701
    auto i = 1;
    while (ccx.sess.has_external_crate(i)) {
        auto name = ccx.sess.get_external_crate(i).name;
7702 7703 7704
        auto cr =
            llvm::LLVMAddGlobal(ccx.llmod, T_int(),
                                str::buf("_rust_crate_map_" + name));
7705
        vec::push[ValueRef](subcrates, p2i(cr));
7706 7707
        i += 1;
    }
7708
    vec::push[ValueRef](subcrates, C_int(0));
7709 7710
    auto mapname;
    if (ccx.sess.get_opts().shared) {
7711
        mapname = ccx.crate_meta_name;
7712
    } else { mapname = "toplevel"; }
7713
    auto sym_name = "_rust_crate_map_" + mapname;
7714
    auto arrtype = T_array(T_int(), vec::len[ValueRef](subcrates));
7715
    auto maptype = T_struct([T_int(), arrtype]);
7716
    auto map = llvm::LLVMAddGlobal(ccx.llmod, maptype, str::buf(sym_name));
7717 7718 7719 7720 7721
    llvm::LLVMSetLinkage(map,
                         lib::llvm::LLVMExternalLinkage as llvm::Linkage);
    llvm::LLVMSetInitializer(map,
                             C_struct([p2i(create_module_map(ccx)),
                                       C_array(T_int(), subcrates)]));
7722 7723 7724
    ret map;
}

7725 7726
fn trans_crate(&session::session sess, &@ast::crate crate, &ty::ctxt tcx,
               &str output) -> ModuleRef {
7727
    auto llmod =
7728
        llvm::LLVMModuleCreateWithNameInContext(str::buf("rust_out"),
7729
                                                llvm::LLVMGetGlobalContext());
7730 7731
    llvm::LLVMSetDataLayout(llmod, str::buf(x86::get_data_layout()));
    llvm::LLVMSetTarget(llmod, str::buf(x86::get_target_triple()));
7732
    auto td = mk_target_data(x86::get_data_layout());
7733
    auto tn = mk_type_names();
7734
    auto intrinsics = declare_intrinsics(llmod);
7735
    auto glues = make_glues(llmod, tn);
7736 7737
    auto hasher = ty::hash_ty;
    auto eqer = ty::eq_ty;
7738 7739 7740 7741 7742 7743
    auto tag_sizes = map::mk_hashmap[ty::t, uint](hasher, eqer);
    auto tydescs = map::mk_hashmap[ty::t, @tydesc_info](hasher, eqer);
    auto lltypes = map::mk_hashmap[ty::t, TypeRef](hasher, eqer);
    auto sha1s = map::mk_hashmap[ty::t, str](hasher, eqer);
    auto abbrevs = map::mk_hashmap[ty::t, metadata::ty_abbrev](hasher, eqer);
    auto short_names = map::mk_hashmap[ty::t, str](hasher, eqer);
7744
    auto sha = std::sha1::mk_sha1();
7745 7746 7747 7748 7749 7750 7751 7752 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781
    auto ccx =
        @rec(sess=sess,
             llmod=llmod,
             td=td,
             tn=tn,
             externs=new_str_hash[ValueRef](),
             intrinsics=intrinsics,
             item_ids=new_def_hash[ValueRef](),
             items=new_def_hash[@ast::item](),
             native_items=new_def_hash[@ast::native_item](),
             item_symbols=new_def_hash[str](),
             mutable main_fn=none[ValueRef],
             crate_meta_name=crate_meta_name(sess, *crate, output),
             crate_meta_vers=crate_meta_vers(sess, *crate),
             crate_meta_extras_hash=crate_meta_extras_hash(sha, *crate),
             tag_sizes=tag_sizes,
             discrims=new_def_hash[ValueRef](),
             discrim_symbols=new_def_hash[str](),
             fn_pairs=new_def_hash[ValueRef](),
             consts=new_def_hash[ValueRef](),
             obj_methods=new_def_hash[()](),
             tydescs=tydescs,
             module_data=new_str_hash[ValueRef](),
             lltypes=lltypes,
             glues=glues,
             names=namegen(0),
             sha=sha,
             type_sha1s=sha1s,
             type_abbrevs=abbrevs,
             type_short_names=short_names,
             tcx=tcx,
             stats=rec(mutable n_static_tydescs=0u,
                       mutable n_derived_tydescs=0u,
                       mutable n_glues_created=0u,
                       mutable n_null_glues=0u,
                       mutable n_real_glues=0u),
             upcalls=upcall::declare_upcalls(tn, llmod));
7782
    auto cx = new_local_ctxt(ccx);
7783
    create_typedefs(ccx);
7784
    collect_items(ccx, crate);
7785 7786
    collect_tag_ctors(ccx, crate);
    trans_constants(ccx, crate);
7787
    trans_mod(cx, crate.node.module);
7788
    auto crate_map = create_crate_map(ccx);
7789
    emit_tydescs(ccx);
7790
    // Translate the metadata:
7791

7792
    middle::metadata::write_metadata(cx.ccx, crate);
7793 7794 7795 7796 7797 7798 7799 7800
    if (ccx.sess.get_opts().stats) {
        log_err "--- trans stats ---";
        log_err #fmt("n_static_tydescs: %u", ccx.stats.n_static_tydescs);
        log_err #fmt("n_derived_tydescs: %u", ccx.stats.n_derived_tydescs);
        log_err #fmt("n_glues_created: %u", ccx.stats.n_glues_created);
        log_err #fmt("n_null_glues: %u", ccx.stats.n_null_glues);
        log_err #fmt("n_real_glues: %u", ccx.stats.n_real_glues);
    }
7801
    ret llmod;
7802 7803 7804 7805 7806 7807 7808 7809
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
7810
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
7811 7812
// End:
//