trans.rs 316.1 KB
Newer Older
L
Lindsey Kuper 已提交
1 2 3 4 5 6
// 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 已提交
7 8
//
// Hopefully useful general knowledge about trans:
9
//
L
Lindsey Kuper 已提交
10 11 12 13 14
//   * 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.
15 16 17 18 19 20
import std::int;
import std::str;
import std::uint;
import std::vec;
import std::str::rustrt::sbuf;
import std::vec::rustrt::vbuf;
21 22 23 24 25
import std::map;
import std::map::hashmap;
import std::option;
import std::option::some;
import std::option::none;
26
import std::fs;
27 28 29 30
import front::ast;
import front::creader;
import driver::session;
import middle::ty;
31
import back::link;
32 33 34 35
import back::x86;
import back::abi;
import back::upcall;
import middle::ty::pat_ty;
36
import visit::vt;
37 38 39 40
import util::common;
import util::common::istr;
import util::common::new_def_hash;
import util::common::new_str_hash;
41
import util::common::local_rhs_span;
42
import util::common::span;
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
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;
60 61 62 63 64 65 66 67
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;
68 69 70
import pretty::ppaux::ty_to_str;
import pretty::ppaux::ty_to_short_str;
import pretty::pprust::expr_to_str;
71

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

76 77
type derived_tydesc_info = rec(ValueRef lltydesc, bool escapes);

78
type glue_fns = rec(ValueRef no_op_type_glue);
79

80 81 82 83 84 85 86 87 88 89 90
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);

91

92 93 94 95 96 97 98 99
/*
 * 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.
 *
100
 * A "native" is an extern that references C code. Called with cdecl.
101 102 103 104 105 106
 *
 * 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.
 *
 */
107 108 109 110 111 112 113
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);

114

115
// Crate context.  Every crate we compile has one of these.
116 117 118 119 120 121 122
type crate_ctxt =
    rec(session::session sess,
        ModuleRef llmod,
        target_data td,
        type_names tn,
        hashmap[str, ValueRef] externs,
        hashmap[str, ValueRef] intrinsics,
123 124 125 126

        // A mapping from the def_id of each item in this crate to the address
        // of the first instruction of the item's definition in the executable
        // we're generating.
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 158 159 160 161
        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);
162

163

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

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

169

170
// Function context.  Every LLVM function we create will have one of these.
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
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.

192 193 194
        // A block for all the function's static allocas, so that LLVM will
        // coalesce them into a single alloca call.
        mutable BasicBlockRef llstaticallocas,
195 196

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

202 203 204 205 206
        // The first block containing derived tydescs received from the
        // runtime.  See description of derived_tydescs, below.
        mutable BasicBlockRef llderivedtydescs_first,

        // The last block of the llderivedtydescs group.
207 208
        mutable BasicBlockRef llderivedtydescs,

209 210 211 212 213
        // A block for all of the dynamically sized allocas.  This must be
        // after llderivedtydescs, because these sometimes depend on
        // information computed from derived tydescs.
        mutable BasicBlockRef lldynamicallocas,

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 259 260 261 262 263 264 265 266 267 268 269 270
        // 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 ); }
271

272
tag block_kind {
273

274 275 276 277
    // 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.
278
    SCOPE_BLOCK;
279 280 281 282 283

    // 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?)
284
    LOOP_SCOPE_BLOCK(option::t[@block_ctxt], @block_ctxt);
285 286 287 288 289

    // 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.
290 291 292
    NON_SCOPE_BLOCK;
}

293

294 295 296 297 298
// 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.
299 300 301 302 303 304 305
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,
306

307 308 309
        // The llvm::builder object serving as an interface to LLVM's
        // LLVMBuild* functions.
        builder build,
310

311 312
        // The block pointing to this one in the function's digraph.
        block_parent parent,
313

314 315
        // The 'kind' of basic block this is.
        block_kind kind,
316

317 318 319 320
        // 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,
321

322 323 324 325 326 327
        // 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);
328

329

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

334
type result = rec(@block_ctxt bcx, ValueRef val);
335

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

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

342
fn ty_str(type_names tn, TypeRef t) -> str {
343
    ret lib::llvm::type_to_str(tn, t);
344 345
}

346 347 348
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)); }
349

350

351 352 353 354 355 356 357 358 359
// 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));
}

360 361

// LLVM type constructors.
362 363 364 365 366 367 368 369 370 371 372
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.
373

374
    ret llvm::LLVMVoidType();
375 376
}

377 378 379
fn T_nil() -> TypeRef {
    // NB: See above in T_void().

380
    ret llvm::LLVMInt1Type();
381 382
}

383
fn T_i1() -> TypeRef { ret llvm::LLVMInt1Type(); }
384

385
fn T_i8() -> TypeRef { ret llvm::LLVMInt8Type(); }
386

387
fn T_i16() -> TypeRef { ret llvm::LLVMInt16Type(); }
388

389
fn T_i32() -> TypeRef { ret llvm::LLVMInt32Type(); }
390

391
fn T_i64() -> TypeRef { ret llvm::LLVMInt64Type(); }
392

393
fn T_f32() -> TypeRef { ret llvm::LLVMFloatType(); }
394

395 396 397
fn T_f64() -> TypeRef { ret llvm::LLVMDoubleType(); }

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

399 400
fn T_int() -> TypeRef {
    // FIXME: switch on target type.
401

402 403 404
    ret T_i32();
}

405 406
fn T_float() -> TypeRef {
    // FIXME: switch on target type.
407

408 409 410
    ret T_f64();
}

411
fn T_char() -> TypeRef { ret T_i32(); }
412

413 414
fn T_size_t() -> TypeRef {
    // FIXME: switch on target type.
415

416 417 418
    ret T_i32();
}

419
fn T_fn(vec[TypeRef] inputs, TypeRef output) -> TypeRef {
420 421
    ret llvm::LLVMFunctionType(output, vec::buf[TypeRef](inputs),
                               vec::len[TypeRef](inputs), False);
422 423
}

G
Graydon Hoare 已提交
424
fn T_fn_pair(&type_names tn, TypeRef tfn) -> TypeRef {
425
    ret T_struct([T_ptr(tfn), T_opaque_closure_ptr(tn)]);
426 427
}

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

G
Graydon Hoare 已提交
430
fn T_struct(&vec[TypeRef] elts) -> TypeRef {
431 432
    ret llvm::LLVMStructType(vec::buf[TypeRef](elts), vec::len[TypeRef](elts),
                             False);
433 434
}

435
fn T_opaque() -> TypeRef { ret llvm::LLVMOpaqueType(); }
436

G
Graydon Hoare 已提交
437
fn T_task(&type_names tn) -> TypeRef {
438
    auto s = "task";
439 440 441 442 443 444 445 446
    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
447 448 449 450

                  T_int(), // Domain pointer
                           // Crate cache pointer
                            T_int()]);
451 452
    tn.associate(s, t);
    ret t;
453 454
}

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

458
    let vec[TypeRef] tydesc_elts =
459
        vec::init_elt[TypeRef](T_nil(), abi::n_tydesc_fields as uint);
460
    llvm::LLVMGetStructElementTypes(T_tydesc(tn),
461
                                    vec::buf[TypeRef](tydesc_elts));
462
    auto t = llvm::LLVMGetElementType(tydesc_elts.(field));
463 464 465
    ret t;
}

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

474
fn T_dtor(&@crate_ctxt ccx, &span sp, TypeRef llself_ty) -> TypeRef {
475
    ret type_of_fn_full(ccx, sp, ast::proto_fn, some[TypeRef](llself_ty),
476
                        vec::empty[ty::arg](), ty::mk_nil(ccx.tcx), 0u);
477 478
}

G
Graydon Hoare 已提交
479
fn T_cmp_glue_fn(&type_names tn) -> TypeRef {
480
    auto s = "cmp_glue_fn";
481
    if (tn.name_has_type(s)) { ret tn.get_type(s); }
482
    auto t = T_tydesc_field(tn, abi::tydesc_field_cmp_glue);
483 484
    tn.associate(s, t);
    ret t;
485 486
}

G
Graydon Hoare 已提交
487
fn T_tydesc(&type_names tn) -> TypeRef {
488
    auto s = "tydesc";
489
    if (tn.name_has_type(s)) { ret tn.get_type(s); }
490
    auto th = mk_type_handle();
491
    auto abs_tydesc = llvm::LLVMResolveTypeHandle(th.llth);
492
    auto tydescpp = T_ptr(T_ptr(abs_tydesc));
493
    auto pvoid = T_ptr(T_i8());
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
    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
512

513 514
    llvm::LLVMRefineType(abs_tydesc, tydesc);
    auto t = llvm::LLVMResolveTypeHandle(th.llth);
515 516
    tn.associate(s, t);
    ret t;
517 518
}

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

521
fn T_vec(TypeRef t) -> TypeRef {
522 523 524
    ret T_struct([T_int(), // Refcount
                   T_int(), // Alloc
                   T_int(), // Fill
525 526 527 528

                  T_int(), // Pad
                           // Body elements
                            T_array(t, 0u)]);
529 530
}

531 532
fn T_opaque_vec_ptr() -> TypeRef { ret T_ptr(T_vec(T_int())); }

533

534 535 536
// Interior vector.
//
// TODO: Support user-defined vector sizes.
537
fn T_ivec(TypeRef t) -> TypeRef {
538 539 540 541
    ret T_struct([T_int(), // Length ("fill"; if zero, heapified)
                   T_int(), // Alloc
                   T_array(t, abi::ivec_default_length)]); // Body elements

542 543
}

544

545 546
// Note that the size of this one is in bytes.
fn T_opaque_ivec() -> TypeRef {
547 548 549 550
    ret T_struct([T_int(), // Length ("fill"; if zero, heapified)
                   T_int(), // Alloc
                   T_array(T_i8(), 0u)]); // Body elements

551 552
}

553
fn T_ivec_heap_part(TypeRef t) -> TypeRef {
554 555 556
    ret T_struct([T_int(), // Real length
                   T_array(t, 0u)]); // Body elements

557 558
}

559

560 561
// 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.
562
fn T_ivec_heap(TypeRef t) -> TypeRef {
563 564 565 566
    ret T_struct([T_int(), // Length (zero)
                   T_int(), // Alloc
                   T_ptr(T_ivec_heap_part(t))]); // Pointer

567 568 569
}

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

573 574
}

575
fn T_opaque_ivec_heap() -> TypeRef {
576 577 578
    ret T_struct([T_int(), // Length (zero)
                   T_int(), // Alloc
                   T_ptr(T_opaque_ivec_heap_part())]); // Pointer
579

580 581
}

582 583 584
fn T_str() -> TypeRef { ret T_vec(T_i8()); }

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

B
Brian Anderson 已提交
586
fn T_port(TypeRef t) -> TypeRef {
587
    ret T_struct([T_int()]); // Refcount
588

B
Brian Anderson 已提交
589 590 591
}

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

594 595
}

596 597 598
fn T_taskptr(&type_names tn) -> TypeRef { ret T_ptr(T_task(tn)); }


599
// This type must never be used directly; it must always be cast away.
G
Graydon Hoare 已提交
600
fn T_typaram(&type_names tn) -> TypeRef {
601
    auto s = "typaram";
602
    if (tn.name_has_type(s)) { ret tn.get_type(s); }
603
    auto t = T_i8();
604 605
    tn.associate(s, t);
    ret t;
606 607
}

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

610
fn T_closure_ptr(&type_names tn, TypeRef lltarget_ty, TypeRef llbindings_ty,
611
                 uint n_ty_params) -> TypeRef {
612
    // NB: keep this in sync with code in trans_bind; we're making
613
    // an LLVM typeref structure that has the same "shape" as the ty::t
614
    // it constructs.
615 616 617

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

G
Graydon Hoare 已提交
620
fn T_opaque_closure_ptr(&type_names tn) -> TypeRef {
621
    auto s = "*closure";
622 623 624 625
    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);
626 627
    tn.associate(s, t);
    ret t;
628 629
}

G
Graydon Hoare 已提交
630
fn T_tag(&type_names tn, uint size) -> TypeRef {
631
    auto s = "tag_" + uint::to_str(size, 10u);
632
    if (tn.name_has_type(s)) { ret tn.get_type(s); }
633
    auto t = T_struct([T_int(), T_array(T_i8(), size)]);
634 635 636 637
    tn.associate(s, t);
    ret t;
}

G
Graydon Hoare 已提交
638
fn T_opaque_tag(&type_names tn) -> TypeRef {
639
    auto s = "opaque_tag";
640
    if (tn.name_has_type(s)) { ret tn.get_type(s); }
641
    auto t = T_struct([T_int(), T_i8()]);
642 643 644 645
    tn.associate(s, t);
    ret t;
}

G
Graydon Hoare 已提交
646
fn T_opaque_tag_ptr(&type_names tn) -> TypeRef {
647 648 649
    ret T_ptr(T_opaque_tag(tn));
}

G
Graydon Hoare 已提交
650
fn T_captured_tydescs(&type_names tn, uint n) -> TypeRef {
651
    ret T_struct(vec::init_elt[TypeRef](T_ptr(T_tydesc(tn)), n));
652 653
}

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

658
    fn T_obj(type_names tn, uint n_captured_tydescs) -> TypeRef {
659
        ret T_struct([T_ptr(T_tydesc(tn)),
660
                      T_captured_tydescs(tn, n_captured_tydescs)]);
661 662
    }
    ret T_ptr(T_box(T_obj(tn, n_captured_tydescs)));
663 664
}

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

667
fn T_opaque_port_ptr() -> TypeRef { ret T_ptr(T_i8()); }
668

669
fn T_opaque_chan_ptr() -> TypeRef { ret T_ptr(T_i8()); }
670

671

672 673 674 675
// 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.
676
fn type_of(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef {
677
    if (ty::type_has_dynamic_size(cx.tcx, t)) {
678
        cx.sess.span_fatal(sp,
679 680
                         "type_of() called on a type with dynamic size: " +
                             ty_to_str(cx.tcx, t));
681
    }
682
    ret type_of_inner(cx, sp, t);
683 684
}

685 686
fn type_of_explicit_args(&@crate_ctxt cx, &span sp, &vec[ty::arg] inputs) ->
   vec[TypeRef] {
687
    let vec[TypeRef] atys = [];
688 689
    for (ty::arg arg in inputs) {
        if (ty::type_has_dynamic_size(cx.tcx, arg.ty)) {
690
            assert (arg.mode != ty::mo_val);
691
            atys += [T_typaram_ptr(cx.tn)];
692
        } else {
693
            let TypeRef t;
694
            alt (arg.mode) {
695
                case (ty::mo_alias(_)) {
696
                    t = T_ptr(type_of_inner(cx, sp, arg.ty));
697
                }
698
                case (_) { t = type_of_inner(cx, sp, arg.ty); }
699
            }
700
            atys += [t];
701 702 703 704
        }
    }
    ret atys;
}
705

706

707 708 709 710 711 712
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args
713 714 715
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 {
716
    let vec[TypeRef] atys = [];
717
    // Arg 0: Output pointer.
718

719
    if (ty::type_has_dynamic_size(cx.tcx, output)) {
720
        atys += [T_typaram_ptr(cx.tn)];
721
    } else { atys += [T_ptr(type_of_inner(cx, sp, output))]; }
722
    // Arg 1: task pointer.
723

724
    atys += [T_taskptr(cx.tn)];
725
    // Arg 2: Env (closure-bindings / self-obj)
726

727
    alt (obj_self) {
728 729
        case (some(?t)) { assert (t as int != 0); atys += [t]; }
        case (_) { atys += [T_opaque_closure_ptr(cx.tn)]; }
730
    }
731
    // Args >3: ty params, if not acquired via capture...
732

733 734 735
    if (obj_self == none[TypeRef]) {
        auto i = 0u;
        while (i < ty_param_count) {
736
            atys += [T_ptr(T_tydesc(cx.tn))];
737 738
            i += 1u;
        }
739
    }
740
    if (proto == ast::proto_iter) {
741 742 743
        // 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.
744

745
        atys +=
746
            [T_fn_pair(cx.tn,
747
                       type_of_fn_full(cx, sp, ast::proto_fn, none[TypeRef],
748
                                       [rec(mode=ty::mo_alias(false),
749 750
                                            ty=output)], ty::mk_nil(cx.tcx),
                                       0u))];
751
    }
752
    // ... then explicit args.
753

754
    atys += type_of_explicit_args(cx, sp, inputs);
755
    ret T_fn(atys, llvm::LLVMVoidType());
756 757
}

758 759 760
fn type_of_fn(&@crate_ctxt cx, &span sp, ast::proto proto,
              &vec[ty::arg] inputs, &ty::t output, uint ty_param_count) ->
   TypeRef {
761
    ret type_of_fn_full(cx, sp, proto, none[TypeRef], inputs, output,
762
                        ty_param_count);
763 764
}

765
fn type_of_native_fn(&@crate_ctxt cx, &span sp, ast::native_abi abi,
766 767
                     &vec[ty::arg] inputs, &ty::t output, uint ty_param_count)
   -> TypeRef {
768
    let vec[TypeRef] atys = [];
769
    if (abi == ast::native_abi_rust) {
770
        atys += [T_taskptr(cx.tn)];
771
        auto t = ty::ty_native_fn(abi, inputs, output);
772 773
        auto i = 0u;
        while (i < ty_param_count) {
774
            atys += [T_ptr(T_tydesc(cx.tn))];
775 776 777
            i += 1u;
        }
    }
778 779
    atys += type_of_explicit_args(cx, sp, inputs);
    ret T_fn(atys, type_of_inner(cx, sp, output));
780 781
}

782
fn type_of_inner(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef {
783 784
    // Check the cache.

785
    if (cx.lltypes.contains_key(t)) { ret cx.lltypes.get(t); }
786
    let TypeRef llty = 0 as TypeRef;
787 788 789
    alt (ty::struct(cx.tcx, t)) {
        case (ty::ty_native) { llty = T_ptr(T_i8()); }
        case (ty::ty_nil) { llty = T_nil(); }
790 791 792 793
        case (ty::ty_bot) {
            llty = T_nil(); /* ...I guess? */

        }
794 795 796 797 798
        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)) {
799
            alt (tm) {
800 801 802 803 804 805 806 807 808 809
                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(); }
810 811
            }
        }
812 813
        case (ty::ty_char) { llty = T_char(); }
        case (ty::ty_str) { llty = T_ptr(T_str()); }
814
        case (ty::ty_istr) { llty = T_ivec(T_i8()); }
815 816
        case (ty::ty_tag(_, _)) {
            if (ty::type_has_dynamic_size(cx.tcx, t)) {
817 818
                llty = T_opaque_tag(cx.tn);
            } else {
819
                auto size = static_size_of_tag(cx, sp, t);
820 821
                llty = T_tag(cx.tn, size);
            }
822
        }
823
        case (ty::ty_box(?mt)) {
824
            llty = T_ptr(T_box(type_of_inner(cx, sp, mt.ty)));
825
        }
826
        case (ty::ty_vec(?mt)) {
827
            llty = T_ptr(T_vec(type_of_inner(cx, sp, mt.ty)));
828
        }
829
        case (ty::ty_ivec(?mt)) {
830 831
            if (ty::type_has_dynamic_size(cx.tcx, mt.ty)) {
                llty = T_opaque_ivec();
832
            } else { llty = T_ivec(type_of_inner(cx, sp, mt.ty)); }
833
        }
834
        case (ty::ty_ptr(?mt)) { llty = T_ptr(type_of_inner(cx, sp, mt.ty)); }
835
        case (ty::ty_port(?t)) {
836
            llty = T_ptr(T_port(type_of_inner(cx, sp, t)));
B
Brian Anderson 已提交
837
        }
838
        case (ty::ty_chan(?t)) {
839
            llty = T_ptr(T_chan(type_of_inner(cx, sp, t)));
B
Brian Anderson 已提交
840
        }
841
        case (ty::ty_task) { llty = T_taskptr(cx.tn); }
842
        case (ty::ty_tup(?elts)) {
843
            let vec[TypeRef] tys = [];
844
            for (ty::mt elt in elts) {
845
                tys += [type_of_inner(cx, sp, elt.ty)];
846
            }
847
            llty = T_struct(tys);
848
        }
849
        case (ty::ty_rec(?fields)) {
850
            let vec[TypeRef] tys = [];
851
            for (ty::field f in fields) {
852
                tys += [type_of_inner(cx, sp, f.mt.ty)];
853
            }
854
            llty = T_struct(tys);
855
        }
856
        case (ty::ty_fn(?proto, ?args, ?out, _, _)) {
857
            llty = T_fn_pair(cx.tn, type_of_fn(cx, sp, proto, args, out, 0u));
858
        }
859
        case (ty::ty_native_fn(?abi, ?args, ?out)) {
860
            auto nft = native_fn_wrapper_type(cx, sp, 0u, t);
861
            llty = T_fn_pair(cx.tn, nft);
862
        }
863
        case (ty::ty_obj(?meths)) {
864
            auto th = mk_type_handle();
865
            auto self_ty = llvm::LLVMResolveTypeHandle(th.llth);
866
            let vec[TypeRef] mtys = [T_ptr(T_i8())];
867
            for (ty::method m in meths) {
868
                let TypeRef mty =
869
                    type_of_fn_full(cx, sp, m.proto, some[TypeRef](self_ty),
870
                                    m.inputs, m.output, 0u);
871
                mtys += [T_ptr(mty)];
872
            }
873
            let TypeRef vtbl = T_struct(mtys);
874 875
            let TypeRef pair =
                T_struct([T_ptr(vtbl), T_opaque_obj_ptr(cx.tn)]);
876 877 878
            auto abs_pair = llvm::LLVMResolveTypeHandle(th.llth);
            llvm::LLVMRefineType(abs_pair, pair);
            abs_pair = llvm::LLVMResolveTypeHandle(th.llth);
879
            llty = abs_pair;
880
        }
881
        case (ty::ty_var(_)) {
882
            cx.tcx.sess.span_fatal(sp, "trans::type_of called on ty_var");
883
        }
884
        case (ty::ty_param(_)) { llty = T_i8(); }
885
        case (ty::ty_type) { llty = T_ptr(T_tydesc(cx.tn)); }
886
    }
887
    assert (llty as int != 0);
888
    if (cx.sess.get_opts().save_temps) {
889 890
        llvm::LLVMAddTypeName(cx.llmod, str::buf(ty_to_short_str(cx.tcx, t)),
                              llty);
891
    }
892
    cx.lltypes.insert(t, llty);
893
    ret llty;
894 895
}

896
fn type_of_arg(@local_ctxt cx, &span sp, &ty::arg arg) -> TypeRef {
897 898
    alt (ty::struct(cx.ccx.tcx, arg.ty)) {
        case (ty::ty_param(_)) {
899
            if (arg.mode != ty::mo_val) { ret T_typaram_ptr(cx.ccx.tn); }
900 901 902
        }
        case (_) {
            // fall through
903

904 905
        }
    }
906
    auto typ;
907
    if (arg.mode != ty::mo_val) {
908
        typ = T_ptr(type_of_inner(cx.ccx, sp, arg.ty));
909
    } else { typ = type_of_inner(cx.ccx, sp, arg.ty); }
910
    ret typ;
911 912
}

913
fn type_of_ty_param_count_and_ty(@local_ctxt lcx, &span sp,
914 915
                                 &ty::ty_param_count_and_ty tpt) -> TypeRef {
    alt (ty::struct(lcx.ccx.tcx, tpt._1)) {
916
        case (ty::ty_fn(?proto, ?inputs, ?output, _, _)) {
917 918
            auto llfnty =
                type_of_fn(lcx.ccx, sp, proto, inputs, output, tpt._0);
919
            ret T_fn_pair(lcx.ccx.tn, llfnty);
920 921 922
        }
        case (_) {
            // fall through
923

924 925
        }
    }
926
    ret type_of(lcx.ccx, sp, tpt._1);
927 928
}

929
fn type_of_or_i8(&@block_ctxt bcx, ty::t typ) -> TypeRef {
930
    if (ty::type_has_dynamic_size(bcx.fcx.lcx.ccx.tcx, typ)) { ret T_i8(); }
931 932 933
    ret type_of(bcx.fcx.lcx.ccx, bcx.sp, typ);
}

934

935 936
// Name sanitation. LLVM will happily accept identifiers with weird names, but
// gas doesn't!
G
Graydon Hoare 已提交
937
fn sanitize(&str s) -> str {
938 939
    auto result = "";
    for (u8 c in s) {
940
        if (c == '@' as u8) {
941 942
            result += "boxed_";
        } else {
943
            if (c == ',' as u8) {
944 945
                result += "_";
            } else {
946
                if (c == '{' as u8 || c == '(' as u8) {
947 948
                    result += "_of_";
                } else {
949 950 951
                    if (c != 10u8 && c != '}' as u8 && c != ')' as u8 &&
                            c != ' ' as u8 && c != '\t' as u8 &&
                            c != ';' as u8) {
952
                        auto v = [c];
953
                        result += str::from_bytes(v);
954 955 956
                    }
                }
            }
957 958 959 960 961
        }
    }
    ret result;
}

962

963 964
// LLVM constant constructors.
fn C_null(TypeRef t) -> ValueRef { ret llvm::LLVMConstNull(t); }
965

966
fn C_integral(TypeRef t, uint u, Bool sign_extend) -> ValueRef {
967
    // FIXME: We can't use LLVM::ULongLong with our existing minimal native
968
    // API, which only knows word-sized args.
969
    //
970
    // ret llvm::LLVMConstInt(T_int(), t as LLVM::ULongLong, False);
971
    //
972

973
    ret llvm::LLVMRustConstSmallInt(t, u, sign_extend);
974 975
}

G
Graydon Hoare 已提交
976
fn C_float(&str s) -> ValueRef {
977
    ret llvm::LLVMConstRealOfString(T_float(), str::buf(s));
978 979
}

G
Graydon Hoare 已提交
980
fn C_floating(&str s, TypeRef t) -> ValueRef {
981
    ret llvm::LLVMConstRealOfString(t, str::buf(s));
982 983
}

984 985
fn C_nil() -> ValueRef {
    // NB: See comment above in T_void().
986

987
    ret C_integral(T_i1(), 0u, False);
988 989
}

990 991
fn C_bool(bool b) -> ValueRef {
    if (b) {
992
        ret C_integral(T_bool(), 1u, False);
993
    } else { ret C_integral(T_bool(), 0u, False); }
994 995
}

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

998 999 1000
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); }
1001

1002

1003 1004
// This is a 'c-like' raw string, which differs from
// our boxed-and-length-annotated strings.
G
Graydon Hoare 已提交
1005
fn C_cstr(&@crate_ctxt cx, &str s) -> ValueRef {
1006
    auto sc = llvm::LLVMConstString(str::buf(s), str::byte_len(s), False);
1007 1008 1009
    auto g =
        llvm::LLVMAddGlobal(cx.llmod, val_ty(sc),
                            str::buf(cx.names.next("str")));
1010 1011
    llvm::LLVMSetInitializer(g, sc);
    llvm::LLVMSetGlobalConstant(g, True);
1012
    llvm::LLVMSetLinkage(g, lib::llvm::LLVMInternalLinkage as llvm::Linkage);
1013
    ret g;
1014 1015
}

1016

1017
// A rust boxed-and-length-annotated string.
G
Graydon Hoare 已提交
1018
fn C_str(&@crate_ctxt cx, &str s) -> ValueRef {
1019
    auto len = str::byte_len(s);
1020 1021 1022 1023 1024 1025 1026 1027 1028
    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")));
1029 1030
    llvm::LLVMSetInitializer(g, box);
    llvm::LLVMSetGlobalConstant(g, True);
1031
    llvm::LLVMSetLinkage(g, lib::llvm::LLVMInternalLinkage as llvm::Linkage);
1032
    ret llvm::LLVMConstPointerCast(g, T_ptr(T_str()));
1033 1034
}

1035 1036
fn C_zero_byte_arr(uint size) -> ValueRef {
    auto i = 0u;
1037
    let vec[ValueRef] elts = [];
1038
    while (i < size) { elts += [C_u8(0u)]; i += 1u; }
1039
    ret llvm::LLVMConstArray(T_i8(), vec::buf[ValueRef](elts),
1040
                             vec::len[ValueRef](elts));
1041 1042
}

G
Graydon Hoare 已提交
1043
fn C_struct(&vec[ValueRef] elts) -> ValueRef {
1044
    ret llvm::LLVMConstStruct(vec::buf[ValueRef](elts),
1045
                              vec::len[ValueRef](elts), False);
1046 1047
}

G
Graydon Hoare 已提交
1048
fn C_array(TypeRef ty, &vec[ValueRef] elts) -> ValueRef {
1049
    ret llvm::LLVMConstArray(ty, vec::buf[ValueRef](elts),
1050
                             vec::len[ValueRef](elts));
1051 1052
}

G
Graydon Hoare 已提交
1053
fn decl_fn(ModuleRef llmod, &str name, uint cc, TypeRef llty) -> ValueRef {
1054
    let ValueRef llfn = llvm::LLVMAddFunction(llmod, str::buf(name), llty);
1055
    llvm::LLVMSetFunctionCallConv(llfn, cc);
1056 1057 1058
    ret llfn;
}

G
Graydon Hoare 已提交
1059
fn decl_cdecl_fn(ModuleRef llmod, &str name, TypeRef llty) -> ValueRef {
1060
    ret decl_fn(llmod, name, lib::llvm::LLVMCCallConv, llty);
1061 1062
}

G
Graydon Hoare 已提交
1063
fn decl_fastcall_fn(ModuleRef llmod, &str name, TypeRef llty) -> ValueRef {
1064
    ret decl_fn(llmod, name, lib::llvm::LLVMFastCallConv, llty);
1065 1066
}

1067

1068 1069
// Only use this if you are going to actually define the function. It's
// not valid to simply declare a function as internal.
1070 1071
fn decl_internal_fastcall_fn(ModuleRef llmod, &str name, TypeRef llty) ->
   ValueRef {
1072
    auto llfn = decl_fn(llmod, name, lib::llvm::LLVMFastCallConv, llty);
1073 1074
    llvm::LLVMSetLinkage(llfn,
                         lib::llvm::LLVMInternalLinkage as llvm::Linkage);
1075 1076 1077
    ret llfn;
}

G
Graydon Hoare 已提交
1078
fn decl_glue(ModuleRef llmod, type_names tn, &str s) -> ValueRef {
1079
    ret decl_cdecl_fn(llmod, s, T_fn([T_taskptr(tn)], T_void()));
1080 1081
}

1082
fn get_extern_fn(&hashmap[str, ValueRef] externs, ModuleRef llmod, &str name,
1083
                 uint cc, TypeRef ty) -> ValueRef {
1084
    if (externs.contains_key(name)) { ret externs.get(name); }
1085
    auto f = decl_fn(llmod, name, cc, ty);
1086
    externs.insert(name, f);
1087 1088 1089
    ret f;
}

1090 1091 1092
fn get_extern_const(&hashmap[str, ValueRef] externs, ModuleRef llmod,
                    &str name, TypeRef ty) -> ValueRef {
    if (externs.contains_key(name)) { ret externs.get(name); }
1093
    auto c = llvm::LLVMAddGlobal(llmod, ty, str::buf(name));
1094 1095 1096 1097
    externs.insert(name, c);
    ret c;
}

1098 1099
fn get_simple_extern_fn(&hashmap[str, ValueRef] externs, ModuleRef llmod,
                        &str name, int n_args) -> ValueRef {
1100
    auto inputs = vec::init_elt[TypeRef](T_int(), n_args as uint);
1101 1102
    auto output = T_int();
    auto t = T_fn(inputs, output);
1103
    ret get_extern_fn(externs, llmod, name, lib::llvm::LLVMCCallConv, t);
1104 1105
}

G
Graydon Hoare 已提交
1106
fn trans_native_call(&builder b, @glue_fns glues, ValueRef lltaskptr,
1107 1108 1109 1110
                     &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;
1111
    let ValueRef llnative = get_simple_extern_fn(externs, llmod, name, n);
1112
    let vec[ValueRef] call_args = [];
1113
    for (ValueRef a in args) { call_args += [b.ZExtOrBitCast(a, T_int())]; }
1114
    ret b.Call(llnative, call_args);
1115 1116
}

G
Graydon Hoare 已提交
1117
fn trans_non_gc_free(&@block_ctxt cx, ValueRef v) -> result {
1118
    cx.build.Call(cx.fcx.lcx.ccx.upcalls.free,
1119 1120
                  [cx.fcx.lltaskptr, cx.build.PointerCast(v, T_ptr(T_i8())),
                   C_int(0)]);
1121
    ret res(cx, C_int(0));
1122 1123
}

G
Graydon Hoare 已提交
1124
fn find_scope_cx(&@block_ctxt cx) -> @block_ctxt {
1125
    if (cx.kind != NON_SCOPE_BLOCK) { ret cx; }
1126
    alt (cx.parent) {
1127
        case (parent_some(?b)) { ret find_scope_cx(b); }
1128
        case (parent_none) {
1129 1130
            cx.fcx.lcx.ccx.sess.bug("trans::find_scope_cx() " +
                                        "called on parentless block_ctxt");
1131 1132
        }
    }
1133 1134
}

G
Graydon Hoare 已提交
1135
fn umax(&@block_ctxt cx, ValueRef a, ValueRef b) -> ValueRef {
1136
    auto cond = cx.build.ICmp(lib::llvm::LLVMIntULT, a, b);
1137 1138 1139
    ret cx.build.Select(cond, b, a);
}

G
Graydon Hoare 已提交
1140
fn umin(&@block_ctxt cx, ValueRef a, ValueRef b) -> ValueRef {
1141
    auto cond = cx.build.ICmp(lib::llvm::LLVMIntULT, a, b);
1142 1143 1144
    ret cx.build.Select(cond, a, b);
}

G
Graydon Hoare 已提交
1145
fn align_to(&@block_ctxt cx, ValueRef off, ValueRef align) -> ValueRef {
1146 1147 1148 1149 1150
    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));
}

1151

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

1157
fn llsize_of(TypeRef t) -> ValueRef {
1158 1159
    ret llvm::LLVMConstIntCast(lib::llvm::llvm::LLVMSizeOf(t), T_int(),
                               False);
1160 1161
}

1162
fn llalign_of(TypeRef t) -> ValueRef {
1163 1164
    ret llvm::LLVMConstIntCast(lib::llvm::llvm::LLVMAlignOf(t), T_int(),
                               False);
1165 1166
}

1167 1168
fn size_of(&@block_ctxt cx, &ty::t t) -> result {
    if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
1169
        ret res(cx, llsize_of(type_of(cx.fcx.lcx.ccx, cx.sp, t)));
1170 1171 1172 1173
    }
    ret dynamic_size_of(cx, t);
}

1174 1175
fn align_of(&@block_ctxt cx, &ty::t t) -> result {
    if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
1176
        ret res(cx, llalign_of(type_of(cx.fcx.lcx.ccx, cx.sp, t)));
1177 1178 1179 1180
    }
    ret dynamic_align_of(cx, t);
}

G
Graydon Hoare 已提交
1181
fn alloca(&@block_ctxt cx, TypeRef t) -> ValueRef {
1182
    ret new_builder(cx.fcx.llstaticallocas).Alloca(t);
1183 1184
}

G
Graydon Hoare 已提交
1185
fn array_alloca(&@block_ctxt cx, TypeRef t, ValueRef n) -> ValueRef {
1186
    ret new_builder(cx.fcx.lldynamicallocas).ArrayAlloca(t, n);
1187 1188 1189
}


1190 1191 1192 1193
// 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.
1194 1195 1196 1197 1198
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));
1199
            }
1200 1201 1202
            case (ty::ty_vec(_)) {
                ret ty::mk_imm_vec(ccx.tcx, ty::mk_nil(ccx.tcx));
            }
1203 1204 1205
            case (ty::ty_fn(_, _, _, _, _)) {
                ret ty::mk_imm_tup(ccx.tcx,
                                   [ty::mk_imm_box(ccx.tcx,
1206
                                                   ty::mk_nil(ccx.tcx)),
1207
                                    ty::mk_imm_box(ccx.tcx,
1208 1209 1210
                                                   ty::mk_nil(ccx.tcx))]);
            }
            case (ty::ty_obj(_)) {
1211 1212
                ret ty::mk_imm_tup(ccx.tcx,
                                   [ty::mk_imm_box(ccx.tcx,
1213
                                                   ty::mk_nil(ccx.tcx)),
1214
                                    ty::mk_imm_box(ccx.tcx,
1215 1216
                                                   ty::mk_nil(ccx.tcx))]);
            }
1217 1218 1219
            case (_) { ret typ; }
        }
    }
1220
    ret ty::fold_ty(ccx.tcx, ty::fm_general(bind simplifier(ccx, _)), typ);
1221 1222
}

1223

1224
// Computes the size of the data part of a non-dynamically-sized tag.
1225
fn static_size_of_tag(&@crate_ctxt cx, &span sp, &ty::t t) -> uint {
1226
    if (ty::type_has_dynamic_size(cx.tcx, t)) {
1227
        cx.tcx.sess.span_fatal(sp,
1228 1229
                             "dynamically sized type passed to " +
                                 "static_size_of_tag()");
1230
    }
1231
    if (cx.tag_sizes.contains_key(t)) { ret cx.tag_sizes.get(t); }
B
Brian Anderson 已提交
1232
    auto tid;
1233 1234
    let vec[ty::t] subtys;
    alt (ty::struct(cx.tcx, t)) {
1235
        case (ty::ty_tag(?tid_, ?subtys_)) { tid = tid_; subtys = subtys_; }
1236
        case (_) {
1237
            cx.tcx.sess.span_fatal(sp,
1238 1239
                                 "non-tag passed to " +
                                     "static_size_of_tag()");
1240 1241 1242
        }
    }
    // Compute max(variant sizes).
1243

1244
    auto max_size = 0u;
1245 1246
    auto variants = ty::tag_variants(cx.tcx, tid);
    for (ty::variant_info variant in variants) {
1247
        auto tup_ty = simplify_type(cx, ty::mk_imm_tup(cx.tcx, variant.args));
1248 1249
        // Perform any type parameter substitutions.

1250
        tup_ty = ty::substitute_type_params(cx.tcx, subtys, tup_ty);
1251 1252
        // Here we possibly do a recursive call.

1253 1254
        auto this_size = llsize_of_real(cx, type_of(cx, sp, tup_ty));
        if (max_size < this_size) { max_size = this_size; }
1255 1256 1257 1258 1259
    }
    cx.tag_sizes.insert(t, max_size);
    ret max_size;
}

1260 1261
fn dynamic_size_of(&@block_ctxt cx, ty::t t) -> result {
    fn align_elements(&@block_ctxt cx, &vec[ty::t] elts) -> result {
1262 1263 1264 1265 1266 1267 1268 1269
        //
        // 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.
        //
1270

1271 1272 1273
        auto off = C_int(0);
        auto max_align = C_int(1);
        auto bcx = cx;
1274
        for (ty::t e in elts) {
1275 1276 1277 1278 1279
            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);
1280
            off = bcx.build.Add(aligned_off, elt_size.val);
1281 1282 1283 1284 1285
            max_align = umax(bcx, max_align, elt_align.val);
        }
        off = align_to(bcx, off, max_align);
        ret res(bcx, off);
    }
1286 1287
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
        case (ty::ty_param(?p)) {
1288 1289
            auto szptr =
                field_of_tydesc(cx, t, false, abi::tydesc_field_size);
1290
            ret res(szptr.bcx, szptr.bcx.build.Load(szptr.val));
1291
        }
1292
        case (ty::ty_tup(?elts)) {
1293
            let vec[ty::t] tys = [];
1294
            for (ty::mt mt in elts) { tys += [mt.ty]; }
1295
            ret align_elements(cx, tys);
1296
        }
1297
        case (ty::ty_rec(?flds)) {
1298
            let vec[ty::t] tys = [];
1299
            for (ty::field f in flds) { tys += [f.mt.ty]; }
1300
            ret align_elements(cx, tys);
1301
        }
1302
        case (ty::ty_tag(?tid, ?tps)) {
1303 1304
            auto bcx = cx;
            // Compute max(variant sizes).
1305

1306
            let ValueRef max_size = alloca(bcx, T_int());
1307
            bcx.build.Store(C_int(0), max_size);
1308 1309
            auto variants = ty::tag_variants(bcx.fcx.lcx.ccx.tcx, tid);
            for (ty::variant_info variant in variants) {
1310
                // Perform type substitution on the raw argument types.
1311

1312
                let vec[ty::t] raw_tys = variant.args;
1313
                let vec[ty::t] tys = [];
1314
                for (ty::t raw_ty in raw_tys) {
1315 1316 1317
                    auto t =
                        ty::substitute_type_params(cx.fcx.lcx.ccx.tcx, tps,
                                                   raw_ty);
1318
                    tys += [t];
1319
                }
1320 1321 1322 1323 1324 1325
                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);
            }
1326 1327 1328
            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);
1329
        }
1330 1331 1332 1333 1334 1335
        case (ty::ty_ivec(?mt)) {
            auto rslt = field_of_tydesc(cx, mt.ty, false,
                                        abi::tydesc_field_size);
            auto bcx = rslt.bcx;
            auto llunitszptr = rslt.val;
            auto llunitsz = bcx.build.Load(llunitszptr);
1336 1337
            auto llsz = bcx.build.Add(llsize_of(T_opaque_ivec()),
                bcx.build.Mul(llunitsz, C_uint(abi::ivec_default_length)));
1338 1339
            ret res(bcx, llsz);
        }
1340 1341 1342
    }
}

1343 1344 1345
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)) {
1346 1347
            auto aptr =
                field_of_tydesc(cx, t, false, abi::tydesc_field_align);
1348
            ret res(aptr.bcx, aptr.bcx.build.Load(aptr.val));
1349
        }
1350
        case (ty::ty_tup(?elts)) {
1351
            auto a = C_int(1);
1352
            auto bcx = cx;
1353
            for (ty::mt e in elts) {
1354
                auto align = align_of(bcx, e.ty);
1355 1356
                bcx = align.bcx;
                a = umax(bcx, a, align.val);
1357
            }
1358
            ret res(bcx, a);
1359
        }
1360
        case (ty::ty_rec(?flds)) {
1361
            auto a = C_int(1);
1362
            auto bcx = cx;
1363
            for (ty::field f in flds) {
1364
                auto align = align_of(bcx, f.mt.ty);
1365 1366
                bcx = align.bcx;
                a = umax(bcx, a, align.val);
1367
            }
1368
            ret res(bcx, a);
1369
        }
1370
        case (ty::ty_tag(_, _)) {
1371
            ret res(cx, C_int(1)); // FIXME: stub
1372 1373 1374 1375 1376 1377 1378
        }
        case (ty::ty_ivec(?tm)) {
            auto rslt = align_of(cx, tm.ty);
            auto bcx = rslt.bcx;
            auto llunitalign = rslt.val;
            auto llalign = umax(bcx, llalign_of(T_int()), llunitalign);
            ret res(bcx, llalign);
1379
        }
1380 1381 1382
    }
}

1383

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

1394
    if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
1395
        let vec[ValueRef] v = [];
1396
        for (int i in ixs) { v += [C_int(i)]; }
1397
        ret res(cx, cx.build.GEP(base, v));
1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414
    }
    // 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.

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

1422
        assert (len > 1u);
1423 1424 1425 1426
        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.
1427

1428
            assert (ixs.(n) == 0);
1429
            ret split_type(ccx, t, ixs, n + 1u);
1430
        }
1431
        assert (n < len);
1432
        let int ix = ixs.(n);
1433
        let vec[ty::t] prefix = [];
1434 1435
        let int i = 0;
        while (i < ix) {
1436
            vec::push[ty::t](prefix,
1437 1438
                             ty::get_element_type(ccx.tcx, t, i as uint));
            i += 1;
1439
        }
1440
        auto selected = ty::get_element_type(ccx.tcx, t, i as uint);
1441
        if (n == len - 1u) {
1442 1443
            // We are at the innermost index.

1444
            ret rec(prefix=prefix, target=selected);
1445 1446 1447 1448
        } 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.
1449 1450

            auto inner = split_type(ccx, selected, ixs, n + 1u);
1451 1452 1453 1454 1455 1456 1457 1458
            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.

1459
    auto s = split_type(cx.fcx.lcx.ccx, t, ixs, 0u);
1460
    auto prefix_ty = ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, s.prefix);
1461 1462 1463 1464
    auto bcx = cx;
    auto sz = size_of(bcx, prefix_ty);
    bcx = sz.bcx;
    auto raw = bcx.build.PointerCast(base, T_ptr(T_i8()));
1465
    auto bumped = bcx.build.GEP(raw, [sz.val]);
1466
    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, s.target)) {
1467
        ret res(bcx, bumped);
1468
    }
1469
    auto typ = T_ptr(type_of(bcx.fcx.lcx.ccx, bcx.sp, s.target));
1470
    ret res(bcx, bcx.build.PointerCast(bumped, typ));
1471 1472
}

1473

1474 1475 1476 1477
// 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.
1478 1479 1480 1481
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);
1482 1483
    // Synthesize a tuple type so that GEP_tup_like() can work its magic.
    // Separately, store the type of the element we're interested in.
1484

1485
    auto arg_tys = variant.args;
1486
    auto elem_ty = ty::mk_nil(cx.fcx.lcx.ccx.tcx); // typestate infelicity
1487

1488
    auto i = 0;
1489
    let vec[ty::t] true_arg_tys = [];
1490
    for (ty::t aty in arg_tys) {
1491 1492
        auto arg_ty =
            ty::substitute_type_params(cx.fcx.lcx.ccx.tcx, ty_substs, aty);
1493
        true_arg_tys += [arg_ty];
1494
        if (i == ix) { elem_ty = arg_ty; }
1495 1496
        i += 1;
    }
1497
    auto tup_ty = ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, true_arg_tys);
1498 1499
    // Cast the blob pointer to the appropriate type, if we need to (i.e. if
    // the blob pointer isn't dynamically sized).
1500

1501
    let ValueRef llunionptr;
1502
    if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, tup_ty)) {
1503
        auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, tup_ty);
1504
        llunionptr = cx.build.TruncOrBitCast(llblobptr, T_ptr(llty));
1505
    } else { llunionptr = llblobptr; }
1506 1507
    // Do the GEP_tup_like().

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

1511
    auto val;
1512
    if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, elem_ty)) {
1513
        auto llelemty = type_of(rslt.bcx.fcx.lcx.ccx, cx.sp, elem_ty);
1514
        val = rslt.bcx.build.PointerCast(rslt.val, T_ptr(llelemty));
1515
    } else { val = rslt.val; }
1516 1517 1518
    ret res(rslt.bcx, val);
}

1519

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

1526
    auto tydesc = C_null(T_ptr(T_tydesc(cx.fcx.lcx.ccx.tn)));
1527 1528 1529
    auto rval =
        cx.build.Call(cx.fcx.lcx.ccx.upcalls.malloc,
                      [cx.fcx.lltaskptr, llsize, tydesc]);
1530
    ret res(cx, cx.build.PointerCast(rval, llptr_ty));
1531 1532
}

L
Lindsey Kuper 已提交
1533 1534 1535 1536

// 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.
1537
fn trans_malloc_boxed(&@block_ctxt cx, ty::t t) -> result {
1538 1539
    // Synthesize a fake box type structurally so we have something
    // to measure the size of.
L
Lindsey Kuper 已提交
1540 1541 1542 1543 1544

    // 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.
1545 1546 1547 1548 1549 1550

    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]);
1551
    auto box_ptr = ty::mk_imm_box(cx.fcx.lcx.ccx.tcx, t);
1552
    auto sz = size_of(cx, boxed_body);
L
Lindsey Kuper 已提交
1553 1554 1555
    // Grab the TypeRef type of box_ptr, because that's what trans_raw_malloc
    // wants.

1556
    auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, box_ptr);
1557
    ret trans_raw_malloc(sz.bcx, llty, sz.val);
1558 1559 1560
}


1561 1562 1563 1564 1565
// 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.
1566 1567
fn field_of_tydesc(&@block_ctxt cx, &ty::t t, bool escapes, int field) ->
   result {
1568 1569
    auto ti = none[@tydesc_info];
    auto tydesc = get_tydesc(cx, t, escapes, ti);
1570
    ret res(tydesc.bcx,
1571
            tydesc.bcx.build.GEP(tydesc.val, [C_int(0), C_int(field)]));
1572
}
1573

1574

1575
// Given a type containing ty params, build a vector containing a ValueRef for
1576 1577
// 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
1578
// constructing derived tydescs.
1579
fn linearize_ty_params(&@block_ctxt cx, &ty::t t) ->
1580
   tup(vec[uint], vec[ValueRef]) {
1581 1582
    let vec[ValueRef] param_vals = [];
    let vec[uint] param_defs = [];
1583 1584 1585 1586
    type rr =
        rec(@block_ctxt cx,
            mutable vec[ValueRef] vals,
            mutable vec[uint] defs);
1587

1588
    fn linearizer(@rr r, ty::t t) {
1589
        alt (ty::struct(r.cx.fcx.lcx.ccx.tcx, t)) {
1590
            case (ty::ty_param(?pid)) {
1591
                let bool seen = false;
1592
                for (uint d in r.defs) { if (d == pid) { seen = true; } }
1593
                if (!seen) {
1594 1595
                    r.vals += [r.cx.fcx.lltydescs.(pid)];
                    r.defs += [pid];
1596
                }
1597
            }
1598
            case (_) { }
1599 1600
        }
    }
1601
    auto x = @rec(cx=cx, mutable vals=param_vals, mutable defs=param_defs);
1602
    auto f = bind linearizer(x, _);
1603
    ty::walk_ty(cx.fcx.lcx.ccx.tcx, f, t);
1604 1605 1606
    ret tup(x.defs, x.vals);
}

G
Graydon Hoare 已提交
1607
fn trans_stack_local_derived_tydesc(&@block_ctxt cx, ValueRef llsz,
1608 1609
                                    ValueRef llalign, ValueRef llroottydesc,
                                    ValueRef llparamtydescs) -> ValueRef {
1610
    auto llmyroottydesc = alloca(cx, T_tydesc(cx.fcx.lcx.ccx.tn));
1611
    // By convention, desc 0 is the root descriptor.
1612

1613
    llroottydesc = cx.build.Load(llroottydesc);
1614
    cx.build.Store(llroottydesc, llmyroottydesc);
1615
    // Store a pointer to the rest of the descriptors.
1616

1617
    auto llfirstparam = cx.build.GEP(llparamtydescs, [C_int(0), C_int(0)]);
1618
    cx.build.Store(llfirstparam,
1619
                   cx.build.GEP(llmyroottydesc, [C_int(0), C_int(0)]));
1620
    cx.build.Store(llsz, cx.build.GEP(llmyroottydesc, [C_int(0), C_int(1)]));
1621
    cx.build.Store(llalign,
1622
                   cx.build.GEP(llmyroottydesc, [C_int(0), C_int(2)]));
1623
    ret llmyroottydesc;
1624 1625
}

1626 1627
fn get_derived_tydesc(&@block_ctxt cx, &ty::t t, bool escapes,
                      &mutable option::t[@tydesc_info] static_ti) -> result {
1628
    alt (cx.fcx.derived_tydescs.find(t)) {
1629
        case (some(?info)) {
1630

1631 1632 1633 1634
            // 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); }
        }
1635
        case (none) {/* fall through */ }
1636
    }
1637
    cx.fcx.lcx.ccx.stats.n_derived_tydescs += 1u;
1638
    auto bcx = new_raw_block_ctxt(cx.fcx, cx.fcx.llderivedtydescs);
1639
    let uint n_params = ty::count_ty_params(bcx.fcx.lcx.ccx.tcx, t);
1640
    auto tys = linearize_ty_params(bcx, t);
1641 1642
    assert (n_params == vec::len[uint](tys._0));
    assert (n_params == vec::len[ValueRef](tys._1));
1643 1644 1645 1646
    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;
1647 1648 1649 1650 1651 1652
    auto sz = size_of(bcx, t);
    bcx = sz.bcx;
    auto align = align_of(bcx, t);
    bcx = align.bcx;
    auto v;
    if (escapes) {
1653 1654
        auto tydescs =
            alloca(bcx, /* for root*/
1655

1656 1657
                   T_array(T_ptr(T_tydesc(bcx.fcx.lcx.ccx.tn)),
                           1u + n_params));
1658
        auto i = 0;
1659
        auto tdp = bcx.build.GEP(tydescs, [C_int(0), C_int(i)]);
1660
        bcx.build.Store(root, tdp);
1661 1662
        i += 1;
        for (ValueRef td in tys._1) {
1663
            auto tdp = bcx.build.GEP(tydescs, [C_int(0), C_int(i)]);
1664
            bcx.build.Store(td, tdp);
1665 1666
            i += 1;
        }
1667 1668 1669 1670 1671 1672 1673 1674
        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]);
1675
        v = td_val;
1676
    } else {
1677 1678 1679
        auto llparamtydescs =
            alloca(bcx,
                   T_array(T_ptr(T_tydesc(bcx.fcx.lcx.ccx.tn)), n_params));
1680 1681
        auto i = 0;
        for (ValueRef td in tys._1) {
1682
            auto tdp = bcx.build.GEP(llparamtydescs, [C_int(0), C_int(i)]);
1683 1684
            bcx.build.Store(td, tdp);
            i += 1;
1685
        }
1686 1687
        v =
            trans_stack_local_derived_tydesc(bcx, sz.val, align.val, root,
1688
                                             llparamtydescs);
1689
    }
1690 1691
    bcx.fcx.derived_tydescs.insert(t, rec(lltydesc=v, escapes=escapes));
    ret res(cx, v);
1692 1693
}

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

1698
    alt (ty::type_param(cx.fcx.lcx.ccx.tcx, t)) {
1699
        case (some(?id)) { ret res(cx, cx.fcx.lltydescs.(id)); }
1700
        case (none) {/* fall through */ }
1701
    }
1702
    // Does it contain a type param? If so, generate a derived tydesc.
1703

1704
    if (ty::type_contains_params(cx.fcx.lcx.ccx.tcx, t)) {
1705
        ret get_derived_tydesc(cx, t, escapes, static_ti);
1706 1707
    }
    // Otherwise, generate a tydesc if necessary, and return it.
1708

1709
    let vec[uint] tps = [];
1710 1711 1712
    auto info = get_static_tydesc(cx, t, tps);
    static_ti = some[@tydesc_info](info);
    ret res(cx, info.tydesc);
1713 1714
}

1715 1716
fn get_static_tydesc(&@block_ctxt cx, &ty::t t, &vec[uint] ty_params) ->
   @tydesc_info {
1717
    alt (cx.fcx.lcx.ccx.tydescs.find(t)) {
1718
        case (some(?info)) { ret info; }
1719
        case (none) {
1720
            cx.fcx.lcx.ccx.stats.n_static_tydescs += 1u;
1721
            auto info = declare_tydesc(cx.fcx.lcx, cx.sp, t, ty_params);
1722
            cx.fcx.lcx.ccx.tydescs.insert(t, info);
1723 1724
            ret info;
        }
1725
    }
1726 1727
}

1728
fn set_no_inline(ValueRef f) {
1729 1730 1731
    llvm::LLVMAddFunctionAttr(f,
                              lib::llvm::LLVMNoInlineAttribute as
                                  lib::llvm::llvm::Attribute);
1732 1733
}

1734
fn set_uwtable(ValueRef f) {
1735 1736 1737
    llvm::LLVMAddFunctionAttr(f,
                              lib::llvm::LLVMUWTableAttribute as
                                  lib::llvm::llvm::Attribute);
1738 1739
}

1740
fn set_always_inline(ValueRef f) {
1741 1742 1743
    llvm::LLVMAddFunctionAttr(f,
                              lib::llvm::LLVMAlwaysInlineAttribute as
                                  lib::llvm::llvm::Attribute);
1744 1745 1746 1747 1748
}

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);
1749
    } else { set_always_inline(f); }
1750 1751 1752
}


1753
// Generates the declaration for (but doesn't emit) a type descriptor.
1754 1755
fn declare_tydesc(&@local_ctxt cx, &span sp, &ty::t t, vec[uint] ty_params) ->
   @tydesc_info {
1756
    log "+++ declare_tydesc " + ty_to_str(cx.ccx.tcx, t);
1757
    auto ccx = cx.ccx;
1758 1759
    auto llsize;
    auto llalign;
1760
    if (!ty::type_has_dynamic_size(ccx.tcx, t)) {
1761
        auto llty = type_of(ccx, sp, t);
1762 1763 1764 1765 1766
        llsize = llsize_of(llty);
        llalign = llalign_of(llty);
    } else {
        // These will be overwritten as the derived tydesc is generated, so
        // we create placeholder values.
1767

1768 1769 1770
        llsize = C_int(0);
        llalign = C_int(0);
    }
1771 1772
    auto name;
    if (cx.ccx.sess.get_opts().debuginfo) {
1773
        name = mangle_internal_name_by_type_only(cx.ccx, t, "tydesc");
1774
        name = sanitize(name);
1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787
    } 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);
1788
    log "--- declare_tydesc " + ty_to_str(cx.ccx.tcx, t);
1789
    ret info;
1790 1791
}

1792
tag make_generic_glue_helper_fn {
1793
    mgghf_single(fn(&@block_ctxt, ValueRef, &ty::t) );
1794
    mgghf_cmp;
1795 1796
}

1797 1798
fn declare_generic_glue(&@local_ctxt cx, &ty::t t, TypeRef llfnty, &str name)
   -> ValueRef {
1799
    auto fn_nm;
1800
    if (cx.ccx.sess.get_opts().debuginfo) {
1801
        fn_nm = mangle_internal_name_by_type_only(cx.ccx, t, "glue_" + name);
1802
        fn_nm = sanitize(fn_nm);
1803
    } else { fn_nm = mangle_internal_name_by_seq(cx.ccx, "glue_" + name); }
1804
    auto llfn = decl_cdecl_fn(cx.ccx.llmod, fn_nm, llfnty);
1805
    set_glue_inlining(cx, llfn, t);
1806
    ret llfn;
1807
}
1808

1809
fn make_generic_glue(&@local_ctxt cx, &span sp, &ty::t t, ValueRef llfn,
G
Graydon Hoare 已提交
1810 1811
                     &make_generic_glue_helper_fn helper,
                     &vec[uint] ty_params) -> ValueRef {
1812
    auto fcx = new_fn_ctxt(cx, sp, llfn);
1813 1814
    llvm::LLVMSetLinkage(llfn,
                         lib::llvm::LLVMInternalLinkage as llvm::Linkage);
1815
    cx.ccx.stats.n_glues_created += 1u;
1816 1817 1818 1819
    // 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.
1820

1821
    auto llty;
1822
    if (ty::type_has_dynamic_size(cx.ccx.tcx, t)) {
1823
        llty = T_ptr(T_i8());
1824
    } else { llty = T_ptr(type_of(cx.ccx, sp, t)); }
1825
    auto ty_param_count = vec::len[uint](ty_params);
1826
    auto lltyparams = llvm::LLVMGetParam(llfn, 3u);
1827
    auto copy_args_bcx = new_raw_block_ctxt(fcx, fcx.llcopyargs);
1828
    auto lltydescs = vec::empty_mut[ValueRef]();
1829 1830
    auto p = 0u;
    while (p < ty_param_count) {
1831
        auto llparam = copy_args_bcx.build.GEP(lltyparams, [C_int(p as int)]);
1832
        llparam = copy_args_bcx.build.Load(llparam);
1833
        vec::grow_set[ValueRef](lltydescs, ty_params.(p), 0 as ValueRef,
1834 1835 1836
                                llparam);
        p += 1u;
    }
1837
    fcx.lltydescs = vec::freeze[ValueRef](lltydescs);
1838 1839
    auto bcx = new_top_block_ctxt(fcx);
    auto lltop = bcx.llbb;
1840
    auto llrawptr0 = llvm::LLVMGetParam(llfn, 4u);
1841 1842
    auto llval0 = bcx.build.BitCast(llrawptr0, llty);
    alt (helper) {
1843
        case (mgghf_single(?single_fn)) { single_fn(bcx, llval0, t); }
1844
        case (mgghf_cmp) {
1845
            auto llrawptr1 = llvm::LLVMGetParam(llfn, 5u);
1846
            auto llval1 = bcx.build.BitCast(llrawptr1, llty);
1847
            auto llcmpval = llvm::LLVMGetParam(llfn, 6u);
1848
            make_cmp_glue(bcx, llval0, llval1, t, llcmpval);
1849
        }
1850
    }
1851
    finish_fn(fcx, lltop);
1852 1853 1854
    ret llfn;
}

1855 1856 1857 1858 1859
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;
1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901
        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
1902 1903 1904 1905

        auto gvar = ti.tydesc;
        llvm::LLVMSetInitializer(gvar, tydesc);
        llvm::LLVMSetGlobalConstant(gvar, True);
1906 1907
        llvm::LLVMSetLinkage(gvar,
                             lib::llvm::LLVMInternalLinkage as llvm::Linkage);
1908 1909 1910
    }
}

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

1914
    auto bcx;
1915
    if (ty::type_is_boxed(cx.fcx.lcx.ccx.tcx, t)) {
1916
        bcx = incr_refcnt_of_boxed(cx, cx.build.Load(v)).bcx;
1917
    } else if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, t)) {
1918 1919
        bcx = iter_structural_ty(cx, v, t, bind take_ty(_, _, _)).bcx;
    } else { bcx = cx; }
1920
    bcx.build.RetVoid();
1921 1922
}

G
Graydon Hoare 已提交
1923
fn incr_refcnt_of_boxed(&@block_ctxt cx, ValueRef box_ptr) -> result {
1924 1925
    auto rc_ptr =
        cx.build.GEP(box_ptr, [C_int(0), C_int(abi::box_rc_field_refcnt)]);
1926 1927 1928
    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");
1929 1930 1931
    auto const_test =
        cx.build.ICmp(lib::llvm::LLVMIntEQ, C_int(abi::const_refcount as int),
                      rc);
1932 1933 1934 1935 1936 1937 1938
    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());
}

1939 1940
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.
1941

1942
    auto rslt;
1943 1944
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
        case (ty::ty_str) {
1945
            auto v = cx.build.Load(v0);
1946
            rslt = trans_non_gc_free(cx, v);
1947
        }
1948
        case (ty::ty_vec(_)) {
1949
            auto v = cx.build.Load(v0);
1950
            auto res = iter_sequence(cx, v, t, bind drop_ty(_, _, _));
1951
            // FIXME: switch gc/non-gc on layer of the type.
1952

1953
            rslt = trans_non_gc_free(res.bcx, v);
1954
        }
1955
        case (ty::ty_box(?body_mt)) {
1956
            auto v = cx.build.Load(v0);
1957 1958
            auto body =
                cx.build.GEP(v, [C_int(0), C_int(abi::box_rc_field_body)]);
1959 1960 1961 1962
            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.
1963

1964
            rslt = trans_non_gc_free(res.bcx, v);
1965
        }
1966
        case (ty::ty_port(_)) {
1967
            auto v = cx.build.Load(v0);
1968 1969
            cx.build.Call(cx.fcx.lcx.ccx.upcalls.del_port,
                          [cx.fcx.lltaskptr,
1970
                           cx.build.PointerCast(v, T_opaque_port_ptr())]);
1971
            rslt = res(cx, C_int(0));
B
Brian Anderson 已提交
1972
        }
1973
        case (ty::ty_chan(_)) {
1974
            auto v = cx.build.Load(v0);
1975 1976
            cx.build.Call(cx.fcx.lcx.ccx.upcalls.del_chan,
                          [cx.fcx.lltaskptr,
1977
                           cx.build.PointerCast(v, T_opaque_chan_ptr())]);
1978
            rslt = res(cx, C_int(0));
B
Brian Anderson 已提交
1979
        }
E
Eric Holk 已提交
1980 1981
        case (ty::ty_task) {
            // TODO: call upcall_kill
1982

E
Eric Holk 已提交
1983 1984
            rslt = res(cx, C_nil());
        }
1985
        case (ty::ty_obj(_)) {
1986
            auto box_cell =
1987
                cx.build.GEP(v0, [C_int(0), C_int(abi::obj_field_box)]);
1988 1989
            auto b = cx.build.Load(box_cell);
            auto body =
1990
                cx.build.GEP(b, [C_int(0), C_int(abi::box_rc_field_body)]);
1991 1992
            auto tydescptr =
                cx.build.GEP(body,
1993
                             [C_int(0), C_int(abi::obj_body_elt_tydesc)]);
1994 1995 1996
            auto tydesc = cx.build.Load(tydescptr);
            auto cx_ = maybe_call_dtor(cx, v0);
            // Call through the obj's own fields-drop glue first.
1997

1998 1999 2000 2001 2002
            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.
2003

2004
            rslt = trans_non_gc_free(cx_, b);
2005
        }
2006
        case (ty::ty_fn(_, _, _, _, _)) {
2007
            auto box_cell =
2008
                cx.build.GEP(v0, [C_int(0), C_int(abi::fn_field_box)]);
2009 2010
            auto v = cx.build.Load(box_cell);
            // Call through the closure's own fields-drop glue first.
2011

2012
            auto body =
2013
                cx.build.GEP(v, [C_int(0), C_int(abi::box_rc_field_body)]);
2014 2015
            auto bindings =
                cx.build.GEP(body,
2016
                             [C_int(0), C_int(abi::closure_elt_bindings)]);
2017 2018
            auto tydescptr =
                cx.build.GEP(body,
2019
                             [C_int(0), C_int(abi::closure_elt_tydesc)]);
2020 2021 2022 2023 2024
            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.
2025

2026 2027 2028 2029 2030 2031 2032
            rslt = trans_non_gc_free(cx, v);
        }
        case (_) { rslt = res(cx, C_nil()); }
    }
    rslt.bcx.build.RetVoid();
}

2033 2034
fn maybe_free_ivec_heap_part(&@block_ctxt cx, ValueRef v0, ty::t unit_ty) ->
   result {
2035
    auto llunitty = type_of_or_i8(cx, unit_ty);
2036 2037 2038 2039
    auto stack_len =
        cx.build.Load(cx.build.InBoundsGEP(v0,
                                           [C_int(0),
                                            C_uint(abi::ivec_elt_len)]));
2040 2041
    auto maybe_on_heap_cx = new_sub_block_ctxt(cx, "maybe_on_heap");
    auto next_cx = new_sub_block_ctxt(cx, "next");
2042 2043
    auto maybe_on_heap =
        cx.build.ICmp(lib::llvm::LLVMIntEQ, stack_len, C_int(0));
2044 2045 2046
    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.)
2047 2048 2049 2050 2051 2052 2053 2054 2055

    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)
        };
2056 2057 2058 2059 2060
    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());
}

2061 2062
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.
2063

2064 2065
    auto rslt;
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
2066 2067
        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); }
2068
        case (ty::ty_ivec(?tm)) {
2069 2070 2071 2072 2073 2074 2075 2076 2077
            auto v1;
            if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, tm.ty)) {
                v1 = cx.build.PointerCast(v0, T_ptr(T_opaque_ivec()));
            } else {
                v1 = v0;
            }

            rslt = iter_structural_ty(cx, v1, t, drop_ty);
            rslt = maybe_free_ivec_heap_part(rslt.bcx, v1, tm.ty);
2078
        }
2079
        case (ty::ty_box(_)) { rslt = decr_refcnt_maybe_free(cx, v0, v0, t); }
2080 2081 2082 2083 2084 2085
        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);
        }
2086
        case (ty::ty_task) { rslt = decr_refcnt_maybe_free(cx, v0, v0, t); }
2087 2088
        case (ty::ty_obj(_)) {
            auto box_cell =
2089
                cx.build.GEP(v0, [C_int(0), C_int(abi::obj_field_box)]);
2090 2091
            rslt = decr_refcnt_maybe_free(cx, box_cell, v0, t);
        }
2092
        case (ty::ty_fn(_, _, _, _, _)) {
2093
            auto box_cell =
2094
                cx.build.GEP(v0, [C_int(0), C_int(abi::fn_field_box)]);
2095
            rslt = decr_refcnt_maybe_free(cx, box_cell, v0, t);
2096
        }
2097
        case (_) {
2098
            if (ty::type_has_pointers(cx.fcx.lcx.ccx.tcx, t) &&
2099 2100 2101
                    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()); }
2102 2103
        }
    }
2104
    rslt.bcx.build.RetVoid();
2105 2106
}

2107 2108
fn decr_refcnt_maybe_free(&@block_ctxt cx, ValueRef box_ptr_alias,
                          ValueRef full_alias, &ty::t t) -> result {
2109
    auto load_rc_cx = new_sub_block_ctxt(cx, "load rc");
2110
    auto rc_adj_cx = new_sub_block_ctxt(cx, "rc--");
2111
    auto free_cx = new_sub_block_ctxt(cx, "free");
2112
    auto next_cx = new_sub_block_ctxt(cx, "next");
2113
    auto box_ptr = cx.build.Load(box_ptr_alias);
2114 2115
    auto null_test = cx.build.IsNull(box_ptr);
    cx.build.CondBr(null_test, next_cx.llbb, load_rc_cx.llbb);
2116 2117 2118
    auto rc_ptr =
        load_rc_cx.build.GEP(box_ptr,
                             [C_int(0), C_int(abi::box_rc_field_refcnt)]);
2119 2120
    auto rc = load_rc_cx.build.Load(rc_ptr);
    auto const_test =
2121 2122
        load_rc_cx.build.ICmp(lib::llvm::LLVMIntEQ,
                              C_int(abi::const_refcount as int), rc);
2123
    load_rc_cx.build.CondBr(const_test, next_cx.llbb, rc_adj_cx.llbb);
2124 2125
    rc = rc_adj_cx.build.Sub(rc, C_int(1));
    rc_adj_cx.build.Store(rc, rc_ptr);
2126
    auto zero_test = rc_adj_cx.build.ICmp(lib::llvm::LLVMIntEQ, C_int(0), rc);
2127
    rc_adj_cx.build.CondBr(zero_test, free_cx.llbb, next_cx.llbb);
2128 2129
    auto free_res =
        free_ty(free_cx, load_if_immediate(free_cx, full_alias, t), t);
2130 2131 2132
    free_res.bcx.build.Br(next_cx.llbb);
    auto t_else = T_nil();
    auto v_else = C_nil();
2133 2134 2135 2136
    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]);
2137
    ret res(next_cx, phi);
2138 2139
}

2140

2141
// Structural comparison: a rather involved form of glue.
G
Graydon Hoare 已提交
2142
fn maybe_name_value(&@crate_ctxt cx, ValueRef v, &str s) {
2143
    if (cx.sess.get_opts().save_temps) {
2144
        llvm::LLVMSetValueName(v, str::buf(s));
2145 2146 2147
    }
}

2148
fn make_cmp_glue(&@block_ctxt cx, ValueRef lhs0, ValueRef rhs0, &ty::t t,
2149 2150 2151
                 ValueRef llop) {
    auto lhs = load_if_immediate(cx, lhs0, t);
    auto rhs = load_if_immediate(cx, rhs0, t);
2152
    if (ty::type_is_scalar(cx.fcx.lcx.ccx.tcx, t)) {
2153
        make_scalar_cmp_glue(cx, lhs, rhs, t, llop);
2154
    } else if (ty::type_is_box(cx.fcx.lcx.ccx.tcx, t)) {
2155 2156
        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)]);
2157 2158 2159 2160
        auto t_inner =
            alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
                case (ty::ty_box(?ti)) { ti.ty }
            };
2161
        auto rslt = call_cmp_glue(cx, lhs, rhs, t_inner, llop);
2162 2163
        rslt.bcx.build.Store(rslt.val, cx.fcx.llretptr);
        rslt.bcx.build.RetVoid();
2164 2165
    } else if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, t) ||
                   ty::type_is_sequence(cx.fcx.lcx.ccx.tcx, t)) {
2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176
        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
2177
         * for pairwise element equality: If we have equality, our assumption
2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193
         * 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());
2194
        maybe_name_value(cx.fcx.lcx.ccx, flag, "flag");
2195
        auto r;
2196
        if (ty::type_is_sequence(cx.fcx.lcx.ccx.tcx, t)) {
2197 2198
            // If we hit == all the way through the minimum-shared-length
            // section, default to judging the relative sequence lengths.
2199

2200 2201 2202 2203
            auto lhs_fill;
            auto rhs_fill;
            auto bcx;
            if (ty::sequence_is_interior(cx.fcx.lcx.ccx.tcx, t)) {
2204 2205 2206
                auto st = ty::sequence_element_type(cx.fcx.lcx.ccx.tcx, t);
                auto lad =
                    ivec::get_len_and_data(scx, lhs, st);
2207 2208
                bcx = lad._2;
                lhs_fill = lad._0;
2209 2210
                lad =
                    ivec::get_len_and_data(bcx, rhs, st);
2211 2212 2213 2214 2215 2216 2217
                bcx = lad._2;
                rhs_fill = lad._0;
            } else {
                lhs_fill = vec_fill(scx, lhs);
                rhs_fill = vec_fill(scx, rhs);
                bcx = scx;
            }
2218 2219
            r =
                compare_numerical_values(bcx, lhs_fill, rhs_fill,
2220
                                         unsigned_int, llop);
2221 2222 2223 2224
            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.
2225 2226 2227 2228

            auto result_if_equal =
                scx.build.ICmp(lib::llvm::LLVMIntNE, llop,
                               C_u8(abi::cmp_glue_op_lt));
2229 2230 2231
            scx.build.Store(result_if_equal, flag);
            r = res(scx, C_nil());
        }
2232 2233
        fn inner(@block_ctxt last_cx, bool load_inner, ValueRef flag,
                 ValueRef llop, &@block_ctxt cx, ValueRef av0, ValueRef bv0,
2234
                 ty::t t) -> result {
2235 2236 2237 2238 2239 2240 2241 2242 2243
            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.

2244
                if (!ty::type_has_dynamic_size(last_cx.fcx.lcx.ccx.tcx, t)) {
2245 2246
                    auto llelemty =
                        T_ptr(type_of(last_cx.fcx.lcx.ccx, last_cx.sp, t));
2247 2248 2249 2250 2251 2252 2253 2254
                    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.

2255 2256 2257
            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);
2258
            // Second 'op' comparison: find out how this elt-pair decides.
2259

2260 2261 2262 2263 2264
            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());
        }
2265
        if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, t)) {
2266 2267 2268 2269
            r =
                iter_structural_ty_full(r.bcx, lhs, rhs, t,
                                        bind inner(next, false, flag, llop, _,
                                                   _, _, _));
2270 2271 2272
        } else {
            auto lhs_p0 = vec_p0(r.bcx, lhs);
            auto rhs_p0 = vec_p0(r.bcx, rhs);
2273 2274
            auto min_len =
                umin(r.bcx, vec_fill(r.bcx, lhs), vec_fill(r.bcx, rhs));
2275
            auto rhs_lim = r.bcx.build.GEP(rhs_p0, [min_len]);
2276
            auto elt_ty = ty::sequence_element_type(cx.fcx.lcx.ccx.tcx, t);
2277
            r = size_of(r.bcx, elt_ty);
2278 2279 2280 2281
            r =
                iter_sequence_raw(r.bcx, lhs_p0, rhs_p0, rhs_lim, r.val,
                                  bind inner(next, true, flag, llop, _, _, _,
                                             elt_ty));
2282 2283 2284 2285 2286 2287 2288
        }
        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?
2289

2290
        trans_fail(cx, none[common::span],
2291
                   "attempt to compare values of type " +
2292
                       ty_to_str(cx.fcx.lcx.ccx.tcx, t));
2293 2294 2295
    }
}

2296

2297
// Used only for creating scalar comparsion glue.
2298 2299
tag numerical_type { signed_int; unsigned_int; floating_point; }

2300

2301
// A helper function to create scalar comparison glue.
2302 2303
fn make_scalar_cmp_glue(&@block_ctxt cx, ValueRef lhs, ValueRef rhs, &ty::t t,
                        ValueRef llop) {
2304
    // assert ty::type_is_scalar(cx.fcx.lcx.ccx.tcx, t);
2305

2306 2307
    // In most cases, we need to know whether to do signed, unsigned, or float
    // comparison.
2308

2309
    auto f = bind make_numerical_cmp_glue(cx, lhs, rhs, _, llop);
2310

2311 2312 2313
    // 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)) {
2314
        case (ty::ty_nil) {
2315 2316 2317 2318 2319 2320 2321 2322
            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(_)) {
2323

2324 2325 2326
            // Floating point machine types
            if (ty::type_is_fp(cx.fcx.lcx.ccx.tcx, t)) {
                f(floating_point);
2327 2328 2329
            } else if (
             // Signed, integral machine types
             ty::type_is_signed(cx.fcx.lcx.ccx.tcx, t)) {
2330
                f(signed_int);
2331 2332 2333 2334
            } else 
             // Unsigned, integral machine types
             {
                f(unsigned_int);
2335 2336
            }
        }
2337 2338
        case (ty::ty_char) { f(unsigned_int); }
        case (ty::ty_type) {
2339 2340 2341 2342 2343 2344 2345
            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");
        }
2346 2347 2348
        case (ty::ty_ptr(_)) {
            f(unsigned_int);
        }
2349 2350
        case (_) {
            // Should never get here, because t is scalar.
2351 2352 2353

            cx.fcx.lcx.ccx.sess.bug("non-scalar type passed to " +
                                        "make_scalar_cmp_glue");
2354
        }
2355 2356 2357
    }
}

2358

2359 2360 2361
// A helper function to compare numerical values.
fn compare_numerical_values(&@block_ctxt cx, ValueRef lhs, ValueRef rhs,
                            numerical_type nt, ValueRef llop) -> result {
2362 2363 2364
    auto eq_cmp;
    auto lt_cmp;
    auto le_cmp;
2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386
    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.
2387 2388 2389

    fn generic_cmp(&@block_ctxt cx, numerical_type nt, uint op, ValueRef lhs,
                   ValueRef rhs) -> ValueRef {
2390 2391 2392
        let ValueRef r;
        if (nt == floating_point) {
            r = cx.build.FCmp(op, lhs, rhs);
2393
        } else { r = cx.build.ICmp(op, lhs, rhs); }
2394
        ret r;
2395 2396 2397
    }
    auto last_cx = new_sub_block_ctxt(cx, "last");
    auto eq_cx = new_sub_block_ctxt(cx, "eq");
2398
    auto eq_result = generic_cmp(eq_cx, nt, eq_cmp, lhs, rhs);
2399 2400
    eq_cx.build.Br(last_cx.llbb);
    auto lt_cx = new_sub_block_ctxt(cx, "lt");
2401
    auto lt_result = generic_cmp(lt_cx, nt, lt_cmp, lhs, rhs);
2402 2403
    lt_cx.build.Br(last_cx.llbb);
    auto le_cx = new_sub_block_ctxt(cx, "le");
2404
    auto le_result = generic_cmp(le_cx, nt, le_cmp, lhs, rhs);
2405 2406 2407 2408
    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);
2409 2410 2411
    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);
2412
    auto last_result =
2413 2414
        last_cx.build.Phi(T_i1(), [eq_result, lt_result, le_result],
                          [eq_cx.llbb, lt_cx.llbb, le_cx.llbb]);
2415 2416 2417
    ret res(last_cx, last_result);
}

2418

2419 2420
// A helper function to create numerical comparison glue.
fn make_numerical_cmp_glue(&@block_ctxt cx, ValueRef lhs, ValueRef rhs,
2421
                           numerical_type nt, ValueRef llop) {
2422
    auto r = compare_numerical_values(cx, lhs, rhs, nt, llop);
2423 2424
    r.bcx.build.Store(r.val, r.bcx.fcx.llretptr);
    r.bcx.build.RetVoid();
2425 2426
}

2427 2428

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

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

2432
type val_pair_and_ty_fn =
2433 2434
    fn(&@block_ctxt, ValueRef, ValueRef, ty::t) -> result ;

2435

2436
// Iterates through the elements of a structural type.
2437 2438
fn iter_structural_ty(&@block_ctxt cx, ValueRef v, &ty::t t, val_and_ty_fn f)
   -> result {
2439 2440
    fn adaptor_fn(val_and_ty_fn f, &@block_ctxt cx, ValueRef av, ValueRef bv,
                  ty::t t) -> result {
2441 2442
        ret f(cx, av, t);
    }
2443
    ret iter_structural_ty_full(cx, v, v, t, bind adaptor_fn(f, _, _, _, _));
2444 2445
}

2446 2447 2448
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 已提交
2449
                  &val_pair_and_ty_fn f) -> result {
2450 2451
        auto box_a_ptr = cx.build.Load(box_a_cell);
        auto box_b_ptr = cx.build.Load(box_b_cell);
2452 2453
        auto tnil = ty::mk_nil(cx.fcx.lcx.ccx.tcx);
        auto tbox = ty::mk_imm_box(cx.fcx.lcx.ccx.tcx, tnil);
2454 2455
        auto inner_cx = new_sub_block_ctxt(cx, "iter box");
        auto next_cx = new_sub_block_ctxt(cx, "next");
2456
        auto null_test = cx.build.IsNull(box_a_ptr);
2457
        cx.build.CondBr(null_test, next_cx.llbb, inner_cx.llbb);
2458
        auto r = f(inner_cx, box_a_ptr, box_b_ptr, tbox);
2459
        r.bcx.build.Br(next_cx.llbb);
2460
        ret res(next_cx, C_nil());
2461
    }
2462
    fn iter_ivec(@block_ctxt bcx, ValueRef av, ValueRef bv, ty::t unit_ty,
2463 2464
                 &val_pair_and_ty_fn f) -> result {
        // FIXME: "unimplemented rebinding existing function" workaround
2465

2466 2467 2468 2469 2470 2471 2472 2473
        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;
2474
        auto a_len_and_data = ivec::get_len_and_data(bcx, av, unit_ty);
2475 2476 2477
        auto a_len = a_len_and_data._0;
        auto a_elem = a_len_and_data._1;
        bcx = a_len_and_data._2;
2478
        auto b_len_and_data = ivec::get_len_and_data(bcx, bv, unit_ty);
2479 2480 2481 2482
        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.
2483 2484
        // TODO: Optimize this when the size of the unit type is statically
        // known to not use pointer casts, which tend to confuse LLVM.
2485

2486 2487 2488 2489 2490
        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.
2491

2492 2493 2494 2495
        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());
2496 2497
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
        case (ty::ty_tup(?args)) {
2498
            let int i = 0;
2499
            for (ty::mt arg in args) {
2500
                r = GEP_tup_like(r.bcx, t, av, [0, i]);
2501
                auto elt_a = r.val;
2502
                r = GEP_tup_like(r.bcx, t, bv, [0, i]);
2503
                auto elt_b = r.val;
2504 2505 2506
                r =
                    f(r.bcx, load_if_immediate(r.bcx, elt_a, arg.ty),
                      load_if_immediate(r.bcx, elt_b, arg.ty), arg.ty);
2507 2508 2509
                i += 1;
            }
        }
2510
        case (ty::ty_rec(?fields)) {
2511
            let int i = 0;
2512
            for (ty::field fld in fields) {
2513
                r = GEP_tup_like(r.bcx, t, av, [0, i]);
2514
                auto llfld_a = r.val;
2515
                r = GEP_tup_like(r.bcx, t, bv, [0, i]);
2516
                auto llfld_b = r.val;
2517 2518
                r =
                    f(r.bcx, load_if_immediate(r.bcx, llfld_a, fld.mt.ty),
2519
                      load_if_immediate(r.bcx, llfld_b, fld.mt.ty),
2520
                      fld.mt.ty);
2521 2522 2523
                i += 1;
            }
        }
2524
        case (ty::ty_tag(?tid, ?tps)) {
2525 2526
            auto variants = ty::tag_variants(cx.fcx.lcx.ccx.tcx, tid);
            auto n_variants = vec::len[ty::variant_info](variants);
2527
            // Cast the tags to types we can GEP into.
2528

2529
            auto lltagty = T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn);
2530 2531
            auto av_tag = cx.build.PointerCast(av, lltagty);
            auto bv_tag = cx.build.PointerCast(bv, lltagty);
2532 2533
            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)]);
2534
            auto lldiscrim_a = cx.build.Load(lldiscrim_a_ptr);
2535 2536
            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)]);
2537
            auto lldiscrim_b = cx.build.Load(lldiscrim_b_ptr);
2538 2539 2540
            // NB: we must hit the discriminant first so that structural
            // comparison know not to proceed when the discriminants differ.

2541 2542 2543 2544
            auto bcx = cx;
            bcx =
                f(bcx, lldiscrim_a, lldiscrim_b,
                  ty::mk_int(cx.fcx.lcx.ccx.tcx)).bcx;
2545
            auto unr_cx = new_sub_block_ctxt(bcx, "tag-iter-unr");
2546
            unr_cx.build.Unreachable();
2547 2548
            auto llswitch =
                bcx.build.Switch(lldiscrim_a, unr_cx.llbb, n_variants);
2549
            auto next_cx = new_sub_block_ctxt(bcx, "tag-iter-next");
2550
            auto i = 0u;
2551
            for (ty::variant_info variant in variants) {
2552 2553 2554 2555
                auto variant_cx =
                    new_sub_block_ctxt(bcx,
                                       "tag-iter-variant-" +
                                           uint::to_str(i, 10u));
2556
                llvm::LLVMAddCase(llswitch, C_int(i as int), variant_cx.llbb);
2557
                if (vec::len[ty::t](variant.args) > 0u) {
2558
                    // N-ary variant.
2559

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

2597
                    variant_cx.build.Br(next_cx.llbb);
2598 2599 2600 2601 2602
                }
                i += 1u;
            }
            ret res(next_cx, C_nil());
        }
2603
        case (ty::ty_fn(_, _, _, _, _)) {
2604
            auto box_cell_a =
2605
                cx.build.GEP(av, [C_int(0), C_int(abi::fn_field_box)]);
2606
            auto box_cell_b =
2607
                cx.build.GEP(bv, [C_int(0), C_int(abi::fn_field_box)]);
2608
            ret iter_boxpp(cx, box_cell_a, box_cell_b, f);
2609
        }
2610
        case (ty::ty_obj(_)) {
2611
            auto box_cell_a =
2612
                cx.build.GEP(av, [C_int(0), C_int(abi::obj_field_box)]);
2613
            auto box_cell_b =
2614
                cx.build.GEP(bv, [C_int(0), C_int(abi::obj_field_box)]);
2615
            ret iter_boxpp(cx, box_cell_a, box_cell_b, f);
2616
        }
2617 2618 2619 2620 2621 2622 2623
        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);
        }
2624
        case (_) {
2625
            cx.fcx.lcx.ccx.sess.unimpl("type in iter_structural_ty_full");
2626
        }
2627
    }
2628
    ret r;
2629 2630
}

2631

2632 2633
// Iterates through a pointer range, until the src* hits the src_lim*.
fn iter_sequence_raw(@block_ctxt cx, ValueRef dst,
2634 2635

                         // elt*
2636
                         ValueRef src,
2637 2638

                         // elt*
2639
                         ValueRef src_lim,
2640 2641

                         // elt*
2642
                         ValueRef elt_sz, &val_pair_fn f) -> result {
2643
    auto bcx = cx;
2644
    let ValueRef dst_int = vp2i(bcx, dst);
2645 2646 2647 2648 2649 2650
    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);
2651 2652 2653 2654
    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);
2655
    cond_cx.build.CondBr(end_test, body_cx.llbb, next_cx.llbb);
2656
    auto dst_curr_ptr = vi2p(body_cx, dst_curr, T_ptr(T_i8()));
2657
    auto src_curr_ptr = vi2p(body_cx, src_curr, T_ptr(T_i8()));
2658
    auto body_res = f(body_cx, dst_curr_ptr, src_curr_ptr);
2659
    body_cx = body_res.bcx;
2660
    auto dst_next = body_cx.build.Add(dst_curr, elt_sz);
2661
    auto src_next = body_cx.build.Add(src_curr, elt_sz);
2662
    body_cx.build.Br(cond_cx.llbb);
2663 2664
    cond_cx.build.AddIncomingToPhi(dst_curr, [dst_next], [body_cx.llbb]);
    cond_cx.build.AddIncomingToPhi(src_curr, [src_next], [body_cx.llbb]);
2665 2666 2667
    ret res(next_cx, C_nil());
}

2668
fn iter_sequence_inner(&@block_ctxt cx, ValueRef src,
2669 2670

                           // elt*
2671 2672 2673 2674 2675
                           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 {
2676
        auto llptrty;
2677
        if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, elt_ty)) {
2678
            auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, elt_ty);
2679
            llptrty = T_ptr(llty);
2680
        } else { llptrty = T_ptr(T_ptr(T_i8())); }
2681
        auto p = cx.build.PointerCast(src, llptrty);
2682
        ret f(cx, load_if_immediate(cx, p, elt_ty), elt_ty);
2683
    }
2684
    auto elt_sz = size_of(cx, elt_ty);
2685 2686
    ret iter_sequence_raw(elt_sz.bcx, src, src, src_lim, elt_sz.val,
                          bind adaptor_fn(f, elt_ty, _, _, _));
2687 2688 2689
}


2690
// Iterates through the elements of a vec or str.
2691 2692 2693 2694 2695 2696
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)]);
2697
        auto llunit_ty;
2698
        if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, elt_ty)) {
2699
            llunit_ty = T_i8();
2700
        } else { llunit_ty = type_of(cx.fcx.lcx.ccx, cx.sp, elt_ty); }
2701 2702
        auto bcx = cx;
        auto len = bcx.build.Load(lenptr);
2703
        if (trailing_null) {
2704 2705
            auto unit_sz = size_of(bcx, elt_ty);
            bcx = unit_sz.bcx;
2706
            len = bcx.build.Sub(len, unit_sz.val);
2707
        }
2708 2709
        auto p1 =
            vi2p(bcx, bcx.build.Add(vp2i(bcx, p0), len), T_ptr(llunit_ty));
2710
        ret iter_sequence_inner(bcx, p0, p1, elt_ty, f);
2711
    }
2712 2713
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
        case (ty::ty_vec(?elt)) {
2714
            ret iter_sequence_body(cx, v, elt.ty, f, false);
2715
        }
2716 2717
        case (ty::ty_str) {
            auto et = ty::mk_mach(cx.fcx.lcx.ccx.tcx, common::ty_u8);
2718
            ret iter_sequence_body(cx, v, et, f, true);
2719
        }
2720 2721
        case (_) {
            cx.fcx.lcx.ccx.sess.bug("unexpected type in " +
2722 2723
                                        "trans::iter_sequence: " +
                                        ty_to_str(cx.fcx.lcx.ccx.tcx, t));
2724
        }
2725
    }
2726 2727
}

2728 2729 2730 2731
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);
2732
    lazily_emit_tydesc_glue(cx, abi::tydesc_field_free_glue, static_ti);
2733 2734 2735 2736 2737
    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) {
2738
    for (option::t[@tydesc_info] ti in gi.static_tis) {
2739 2740 2741 2742 2743 2744 2745
        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) {
2746 2747
        case (none) { }
        case (some(?ti)) {
2748 2749 2750
            if (field == abi::tydesc_field_take_glue) {
                alt ({ ti.take_glue }) {
                    case (some(_)) { }
2751
                    case (none) {
2752
                        log #fmt("+++ lazily_emit_tydesc_glue TAKE %s",
2753
                                 ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
2754 2755 2756 2757 2758 2759 2760
                        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;
2761
                        make_generic_glue(lcx, cx.sp, ti.ty, glue_fn,
2762 2763
                                          mgghf_single(tg), ti.ty_params);
                        log #fmt("--- lazily_emit_tydesc_glue TAKE %s",
2764
                                 ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
2765 2766
                    }
                }
2767 2768
            } else if (field == abi::tydesc_field_drop_glue) {
                alt ({ ti.drop_glue }) {
2769 2770
                    case (some(_)) { }
                    case (none) {
2771
                        log #fmt("+++ lazily_emit_tydesc_glue DROP %s",
2772
                                 ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
2773 2774 2775 2776 2777 2778 2779
                        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;
2780
                        make_generic_glue(lcx, cx.sp, ti.ty, glue_fn,
2781 2782
                                          mgghf_single(dg), ti.ty_params);
                        log #fmt("--- lazily_emit_tydesc_glue DROP %s",
2783
                                 ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
2784 2785
                    }
                }
2786 2787
            } else if (field == abi::tydesc_field_free_glue) {
                alt ({ ti.free_glue }) {
2788 2789
                    case (some(_)) { }
                    case (none) {
2790
                        log #fmt("+++ lazily_emit_tydesc_glue FREE %s",
2791
                                 ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
2792 2793 2794 2795 2796 2797 2798
                        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 已提交
2799
                        make_generic_glue(lcx, cx.sp, ti.ty, glue_fn,
2800 2801
                                          mgghf_single(dg), ti.ty_params);
                        log #fmt("--- lazily_emit_tydesc_glue FREE %s",
2802
                                 ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
2803 2804
                    }
                }
2805
            } else if (field == abi::tydesc_field_cmp_glue) {
2806
                alt ({ ti.cmp_glue }) {
2807 2808
                    case (some(_)) { }
                    case (none) {
2809
                        log #fmt("+++ lazily_emit_tydesc_glue CMP %s",
2810
                                 ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
2811 2812 2813 2814 2815 2816
                        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);
2817
                        make_generic_glue(lcx, cx.sp, ti.ty, glue_fn,
2818 2819
                                          mgghf_cmp, ti.ty_params);
                        log #fmt("--- lazily_emit_tydesc_glue CMP %s",
2820
                                 ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
2821 2822 2823 2824 2825 2826 2827
                    }
                }
            }
        }
    }
}

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

2843 2844
fn call_tydesc_glue(&@block_ctxt cx, ValueRef v, &ty::t t, int field) ->
   result {
2845
    let option::t[@tydesc_info] ti = none[@tydesc_info];
2846
    auto td = get_tydesc(cx, t, false, ti);
2847 2848
    call_tydesc_glue_full(td.bcx, spill_if_immediate(td.bcx, v, t), td.val,
                          field, ti);
2849
    ret res(td.bcx, C_nil());
2850 2851
}

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

2874
fn call_cmp_glue(&@block_ctxt cx, ValueRef lhs, ValueRef rhs, &ty::t t,
2875 2876 2877 2878 2879 2880 2881 2882
                 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()));
2883 2884 2885
    auto ti = none[@tydesc_info];
    auto r = get_tydesc(cx, t, false, ti);
    lazily_emit_tydesc_glue(cx, abi::tydesc_field_cmp_glue, ti);
2886
    auto lltydescs =
2887 2888
        r.bcx.build.GEP(r.val,
                        [C_int(0), C_int(abi::tydesc_field_first_param)]);
2889 2890
    lltydescs = r.bcx.build.Load(lltydescs);
    auto llfnptr =
2891
        r.bcx.build.GEP(r.val, [C_int(0), C_int(abi::tydesc_field_cmp_glue)]);
2892 2893
    auto llfn = r.bcx.build.Load(llfnptr);
    auto llcmpresultptr = r.bcx.build.Alloca(T_i1());
2894 2895 2896
    let vec[ValueRef] llargs =
        [llcmpresultptr, r.bcx.fcx.lltaskptr, C_null(T_ptr(T_nil())),
         lltydescs, llrawlhsptr, llrawrhsptr, llop];
2897
    r.bcx.build.Call(llfn, llargs);
2898 2899 2900
    ret res(r.bcx, r.bcx.build.Load(llcmpresultptr));
}

2901
fn take_ty(&@block_ctxt cx, ValueRef v, ty::t t) -> result {
2902
    if (ty::type_has_pointers(cx.fcx.lcx.ccx.tcx, t)) {
2903
        ret call_tydesc_glue(cx, v, t, abi::tydesc_field_take_glue);
2904
    }
2905
    ret res(cx, C_nil());
2906 2907
}

2908
fn drop_slot(&@block_ctxt cx, ValueRef slot, &ty::t t) -> result {
2909
    auto llptr = load_if_immediate(cx, slot, t);
2910 2911
    auto re = drop_ty(cx, llptr, t);
    auto llty = val_ty(slot);
2912
    auto llelemty = lib::llvm::llvm::LLVMGetElementType(llty);
2913 2914
    re.bcx.build.Store(C_null(llelemty), slot);
    ret re;
2915 2916
}

2917
fn drop_ty(&@block_ctxt cx, ValueRef v, ty::t t) -> result {
2918
    if (ty::type_has_pointers(cx.fcx.lcx.ccx.tcx, t)) {
2919
        ret call_tydesc_glue(cx, v, t, abi::tydesc_field_drop_glue);
2920
    }
2921
    ret res(cx, C_nil());
2922 2923
}

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

2931 2932
fn call_memmove(&@block_ctxt cx, ValueRef dst, ValueRef src,
                ValueRef n_bytes) -> result {
2933
    // FIXME: switch to the 64-bit variant when on such a platform.
2934 2935 2936
    // TODO: Provide LLVM with better alignment information when the alignment
    // is statically known (it must be nothing more than a constant int, or
    // LLVM complains -- not even a constant element of a tydesc works).
2937

2938
    auto i = cx.fcx.lcx.ccx.intrinsics;
2939 2940
    assert (i.contains_key("llvm.memmove.p0i8.p0i8.i32"));
    auto memmove = i.get("llvm.memmove.p0i8.p0i8.i32");
2941 2942
    auto src_ptr = cx.build.PointerCast(src, T_ptr(T_i8()));
    auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
2943
    auto size = cx.build.IntCast(n_bytes, T_i32());
2944
    auto align = C_int(0);
2945
    auto volatile = C_bool(false);
2946 2947 2948
    ret res(cx,
            cx.build.Call(memmove,
                          [dst_ptr, src_ptr, size, align, volatile]));
2949 2950
}

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

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

2970 2971
fn memmove_ty(&@block_ctxt cx, ValueRef dst, ValueRef src, &ty::t t) ->
   result {
2972
    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
2973
        auto llsz = size_of(cx, t);
2974
        ret call_memmove(llsz.bcx, dst, src, llsz.val);
2975
    } else { ret res(cx, cx.build.Store(cx.build.Load(src), dst)); }
2976 2977
}

2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990
// Duplicates the heap-owned memory owned by a value of the given type.
fn duplicate_heap_parts(&@block_ctxt cx, ValueRef vptr, ty::t typ) -> result {
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, typ)) {
        case (ty::ty_ivec(?tm)) {
            ret ivec::duplicate_heap_part(cx, vptr, tm.ty);
        }
        case (ty::ty_str) {
            ret ivec::duplicate_heap_part(cx, vptr,
                ty::mk_mach(cx.fcx.lcx.ccx.tcx, common::ty_u8));
        }
    }
}

2991
tag copy_action { INIT; DROP_EXISTING; }
2992

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

3021

M
Michael Sullivan 已提交
3022 3023 3024 3025 3026
// 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.
3027
fn move_val(@block_ctxt cx, copy_action action, ValueRef dst, ValueRef src,
3028
            &ty::t t) -> result {
M
Michael Sullivan 已提交
3029 3030 3031 3032
    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) ||
3033
                   ty::type_is_bot(cx.fcx.lcx.ccx.tcx, t)) {
M
Michael Sullivan 已提交
3034 3035 3036 3037 3038 3039 3040 3041
        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) ||
3042 3043
                   ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
        if (action == DROP_EXISTING) { cx = drop_ty(cx, dst, t).bcx; }
3044
        auto r = memmove_ty(cx, dst, src, t);
M
Michael Sullivan 已提交
3045 3046 3047
        ret zero_alloca(r.bcx, src, t);
    }
    cx.fcx.lcx.ccx.sess.bug("unexpected type in trans::move_val: " +
3048
                                ty_to_str(cx.fcx.lcx.ccx.tcx, t));
M
Michael Sullivan 已提交
3049 3050
}

3051
fn trans_lit(&@crate_ctxt cx, &ast::lit lit, &ast::ann ann) -> ValueRef {
3052
    alt (lit.node) {
3053 3054
        case (ast::lit_int(?i)) { ret C_int(i); }
        case (ast::lit_uint(?u)) { ret C_int(u as int); }
3055
        case (ast::lit_mach_int(?tm, ?i)) {
3056 3057 3058
            // 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.
3059

3060
            auto t = T_int();
3061
            auto s = True;
3062
            alt (tm) {
3063 3064 3065 3066 3067 3068 3069 3070
                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(); }
3071
            }
3072
            ret C_integral(t, i as uint, s);
3073
        }
3074 3075
        case (ast::lit_float(?fs)) { ret C_float(fs); }
        case (ast::lit_mach_float(?tm, ?s)) {
3076
            auto t = T_float();
3077 3078 3079
            alt (tm) {
                case (common::ty_f32) { t = T_f32(); }
                case (common::ty_f64) { t = T_f64(); }
3080 3081 3082
            }
            ret C_floating(s, t);
        }
3083
        case (ast::lit_char(?c)) {
3084
            ret C_integral(T_char(), c as uint, False);
3085
        }
3086 3087 3088
        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); }
3089 3090 3091
    }
}

3092

3093
// Converts an annotation to a type
3094
fn node_ann_type(&@crate_ctxt cx, &ast::ann a) -> ty::t {
3095
    ret ty::ann_to_monotype(cx.tcx, a);
3096 3097
}

3098
fn node_type(&@crate_ctxt cx, &span sp, &ast::ann a) -> TypeRef {
3099
    ret type_of(cx, sp, node_ann_type(cx, a));
3100 3101
}

3102 3103
fn trans_unary(&@block_ctxt cx, ast::unop op, &@ast::expr e, &ast::ann a) ->
   result {
3104
    auto sub = trans_expr(cx, e);
3105
    auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
3106
    alt (op) {
3107
        case (ast::not) {
3108 3109 3110
            sub =
                autoderef(sub.bcx, sub.val,
                          ty::expr_ty(cx.fcx.lcx.ccx.tcx, e));
3111
            ret res(sub.bcx, sub.bcx.build.Not(sub.val));
3112
        }
3113
        case (ast::neg) {
3114 3115 3116 3117
            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) {
3118
                ret res(sub.bcx, sub.bcx.build.FNeg(sub.val));
3119
            } else { ret res(sub.bcx, sub.bcx.build.Neg(sub.val)); }
3120
        }
3121
        case (ast::box(_)) {
3122
            auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
3123
            auto e_val = sub.val;
3124
            auto box_ty = node_ann_type(sub.bcx.fcx.lcx.ccx, a);
3125 3126
            sub = trans_malloc_boxed(sub.bcx, e_ty);
            find_scope_cx(cx).cleanups +=
3127
                [clean(bind drop_ty(_, sub.val, box_ty))];
3128
            auto box = sub.val;
3129 3130 3131 3132 3133 3134 3135
            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)]);
3136
            sub.bcx.build.Store(C_int(1), rc);
3137 3138 3139
            // 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.
3140

3141
            if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, e_ty)) {
3142 3143
                auto llety =
                    T_ptr(type_of(sub.bcx.fcx.lcx.ccx, e.span, e_ty));
3144 3145
                body = sub.bcx.build.PointerCast(body, llety);
            }
3146
            sub = copy_val(sub.bcx, INIT, body, e_val, e_ty);
3147
            ret res(sub.bcx, box);
3148
        }
3149
        case (ast::deref) {
3150 3151 3152
            cx.fcx.lcx.ccx.sess.bug("deref expressions should have been " +
                                        "translated using trans_lval(), not "
                                        + "trans_unary()");
3153
        }
3154 3155 3156
    }
}

3157 3158
fn trans_compare(&@block_ctxt cx0, ast::binop op, &ty::t t0, ValueRef lhs0,
                 ValueRef rhs0) -> result {
3159
    // Autoderef both sides.
3160

3161
    auto cx = cx0;
3162 3163 3164 3165 3166 3167
    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;
3168
    auto t = autoderefed_ty(cx.fcx.lcx.ccx, t0);
3169 3170
    // Determine the operation we need.
    // FIXME: Use or-patterns when we have them.
3171

3172
    auto llop;
3173
    alt (op) {
3174 3175 3176 3177 3178 3179
        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); }
3180
    }
3181
    auto rslt = call_cmp_glue(cx, lhs, rhs, t, llop);
3182

3183 3184
    // Invert the result if necessary.
    // FIXME: Use or-patterns when we have them.
3185
    alt (op) {
3186 3187 3188
        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); }
3189 3190 3191
        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)); }
3192 3193 3194
    }
}

3195 3196
fn trans_vec_append(&@block_ctxt cx, &ty::t t, ValueRef lhs, ValueRef rhs) ->
   result {
3197
    auto elt_ty = ty::sequence_element_type(cx.fcx.lcx.ccx.tcx, t);
3198
    auto skip_null = C_bool(false);
3199 3200
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
        case (ty::ty_str) { skip_null = C_bool(true); }
3201 3202 3203
        case (_) { }
    }
    auto bcx = cx;
3204 3205
    auto ti = none[@tydesc_info];
    auto llvec_tydesc = get_tydesc(bcx, t, false, ti);
3206
    bcx = llvec_tydesc.bcx;
3207 3208 3209 3210
    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);
3211
    lazily_emit_tydesc_glue(cx, abi::tydesc_field_free_glue, ti);
3212
    bcx = llelt_tydesc.bcx;
3213 3214
    auto dst = bcx.build.PointerCast(lhs, T_ptr(T_opaque_vec_ptr()));
    auto src = bcx.build.PointerCast(rhs, T_opaque_vec_ptr());
3215 3216 3217 3218
    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]));
3219 3220
}

3221
mod ivec {
3222

3223 3224
    // Returns the length of an interior vector and a pointer to its first
    // element, in that order.
3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236
    fn get_len_and_data(&@block_ctxt bcx, ValueRef orig_v, ty::t unit_ty)
            -> tup(ValueRef, ValueRef, @block_ctxt) {
        // If this interior vector has dynamic size, we can't assume anything
        // about the LLVM type of the value passed in, so we cast it to an
        // opaque vector type.
        auto v;
        if (ty::type_has_dynamic_size(bcx.fcx.lcx.ccx.tcx, unit_ty)) {
            v = bcx.build.PointerCast(orig_v, T_ptr(T_opaque_ivec()));
        } else {
            v = orig_v;
        }

3237 3238
        auto llunitty = type_of_or_i8(bcx, unit_ty);
        auto stack_len =
3239 3240 3241 3242 3243 3244
            {
                auto p = bcx.build.InBoundsGEP(v,
                                               [C_int(0),
                                                C_uint(abi::ivec_elt_len)]);
                bcx.build.Load(p)
            };
3245 3246
        auto stack_elem =
            bcx.build.InBoundsGEP(v,
3247 3248 3249 3250
                                  [C_int(0), C_uint(abi::ivec_elt_elems),
                                   C_int(0)]);
        auto on_heap =
            bcx.build.ICmp(lib::llvm::LLVMIntEQ, stack_len, C_int(0));
3251 3252 3253 3254 3255
        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);
        auto heap_stub =
            on_heap_cx.build.PointerCast(v, T_ptr(T_ivec_heap(llunitty)));
3256 3257 3258 3259 3260 3261
        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))
            };
3262 3263
        // Check whether the heap pointer is null. If it is, the vector length
        // is truly zero.
3264

3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281
        auto llstubty = T_ivec_heap(llunitty);
        auto llheapptrty = struct_elt(llstubty, abi::ivec_heap_stub_elt_ptr);
        auto heap_ptr_is_null =
            on_heap_cx.build.ICmp(lib::llvm::LLVMIntEQ, heap_ptr,
                                  C_null(T_ptr(llheapptrty)));
        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.

        auto zero_len = C_int(0);
        auto zero_elem = C_null(T_ptr(llunitty));
        zero_len_cx.build.Br(next_cx.llbb);
        // If we're here, then we actually have a heapified vector.

3282 3283 3284 3285 3286 3287
        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)
            };
3288
        auto heap_elem =
3289 3290 3291 3292 3293
            {
                auto v = [C_int(0), C_uint(abi::ivec_heap_elt_elems),
                          C_int(0)];
                nonzero_len_cx.build.InBoundsGEP(heap_ptr,v)
            };
3294 3295 3296 3297 3298
        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.

        auto len =
3299 3300 3301
            next_cx.build.Phi(T_int(), [stack_len, zero_len, heap_len],
                              [bcx.llbb, zero_len_cx.llbb,
                               nonzero_len_cx.llbb]);
3302 3303
        auto elem =
            next_cx.build.Phi(T_ptr(llunitty),
3304 3305 3306
                              [stack_elem, zero_elem, heap_elem],
                              [bcx.llbb, zero_len_cx.llbb,
                               nonzero_len_cx.llbb]);
3307
        ret tup(len, elem, next_cx);
3308 3309
    }

3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336
    // Returns a tuple consisting of a pointer to the newly-reserved space and
    // a block context. Updates the length appropriately.
    fn reserve_space(&@block_ctxt cx, TypeRef llunitty, ValueRef v,
                     ValueRef len_needed) -> result {
        auto stack_len_ptr =
            cx.build.InBoundsGEP(v, [C_int(0), C_uint(abi::ivec_elt_len)]);
        auto stack_len = cx.build.Load(stack_len_ptr);
        auto alen =
            cx.build.Load(cx.build.InBoundsGEP(v,
                                               [C_int(0),
                                                C_uint(abi::ivec_elt_alen)]));
        // 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.

        auto maybe_on_heap =
            cx.build.ICmp(lib::llvm::LLVMIntEQ, stack_len, C_int(0));
        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.

        auto stub_p = [C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)];
3337 3338 3339
        auto stub_ptr =
            maybe_on_heap_cx.build.PointerCast(v,
                                               T_ptr(T_ivec_heap(llunitty)));
3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351
        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)));
        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.
3352

3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369
        auto heap_len_ptr =
            on_heap_cx.build.InBoundsGEP(heap_ptr,
                                         [C_int(0),
                                          C_uint(abi::ivec_heap_elt_len)]);
        auto heap_len = on_heap_cx.build.Load(heap_len_ptr);
        auto new_heap_len = on_heap_cx.build.Add(heap_len, len_needed);
        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);
        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.

        auto heap_data_no_resize =
3370 3371 3372 3373 3374
            {
                auto v = [C_int(0), C_uint(abi::ivec_heap_elt_elems),
                          heap_len_unscaled];
                heap_no_resize_cx.build.InBoundsGEP(heap_ptr,v)
            };
3375 3376 3377 3378 3379
        heap_no_resize_cx.build.Store(new_heap_len, heap_len_ptr);
        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.

3380
        {
3381 3382
            auto p =
                heap_resize_cx.build.PointerCast(v, T_ptr(T_opaque_ivec()));
3383 3384 3385
            heap_resize_cx.build.Call(cx.fcx.lcx.ccx.upcalls.ivec_resize,
                                      [cx.fcx.lltaskptr, p, new_heap_len]);
        }
3386 3387 3388 3389 3390
        auto heap_ptr_resize =
            {
                auto m = heap_resize_cx.build.InBoundsGEP(stub_ptr, stub_p);
                heap_resize_cx.build.Load(m)
            };
3391
        auto heap_data_resize =
3392 3393 3394 3395 3396
            {
                auto v = [C_int(0), C_uint(abi::ivec_heap_elt_elems),
                          heap_len_unscaled];
                heap_resize_cx.build.InBoundsGEP(heap_ptr_resize, v)
            };
3397 3398
        heap_resize_cx.build.Br(next_cx.llbb);
        // We're on the stack. Check whether we need to spill to the heap.
3399

3400 3401 3402 3403 3404 3405 3406 3407 3408
        auto new_stack_len = on_stack_cx.build.Add(stack_len, len_needed);
        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));
        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,
3409
                                 stack_no_spill_cx.llbb, stack_spill_cx.llbb);
3410
        // Case (3): We're on the stack and don't need to spill.
3411

3412 3413 3414 3415 3416 3417 3418 3419 3420
        auto stack_data_no_spill =
            stack_no_spill_cx.build.InBoundsGEP(v,
                                                [C_int(0),
                                                 C_uint(abi::ivec_elt_elems),
                                                 stack_len_unscaled]);
        stack_no_spill_cx.build.Store(new_stack_len, stack_len_ptr);
        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.
3421

3422
        {
3423 3424
            auto p =
                stack_spill_cx.build.PointerCast(v, T_ptr(T_opaque_ivec()));
3425 3426 3427 3428 3429 3430
            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 =
3431 3432 3433 3434
            {
                auto p = stack_spill_cx.build.InBoundsGEP(spill_stub, stub_p);
                stack_spill_cx.build.Load(p)
            };
3435
        auto heap_len_ptr_spill =
3436 3437 3438 3439
            {
                auto v = [C_int(0), C_uint(abi::ivec_heap_elt_len)];
                stack_spill_cx.build.InBoundsGEP(heap_ptr_spill, v)
            };
3440
        auto heap_data_spill =
3441 3442 3443 3444 3445
            {
                auto v = [C_int(0), C_uint(abi::ivec_heap_elt_elems),
                          stack_len_unscaled];
                stack_spill_cx.build.InBoundsGEP(heap_ptr_spill, v)
            };
3446 3447
        stack_spill_cx.build.Br(next_cx.llbb);
        // Phi together the different data pointers to get the result.
3448

3449 3450 3451 3452 3453 3454 3455
        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]);
        ret res(next_cx, data_ptr);
3456
    }
3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469
    fn trans_append(&@block_ctxt cx, &ty::t t, ValueRef orig_lhs,
                    ValueRef orig_rhs) -> result {
        // Cast to opaque interior vector types if necessary.
        auto lhs;
        auto rhs;
        if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
            lhs = cx.build.PointerCast(orig_lhs, T_ptr(T_opaque_ivec()));
            rhs = cx.build.PointerCast(orig_rhs, T_ptr(T_opaque_ivec()));
        } else {
            lhs = orig_lhs;
            rhs = orig_rhs;
        }

3470 3471 3472 3473 3474 3475 3476 3477 3478
        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_append");
            }
3479
        }
3480

3481 3482 3483 3484
        auto rslt = size_of(cx, unit_ty);
        auto bcx = rslt.bcx;
        auto unit_sz = rslt.val;

3485
        // Gather the various type descriptors we'll need.
3486

3487 3488 3489
        // FIXME (issue #511): This is needed to prevent a leak.
        auto no_tydesc_info = none;

3490
        rslt = get_tydesc(bcx, t, false, no_tydesc_info);
3491
        auto vec_tydesc = rslt.val;
3492
        bcx = rslt.bcx;
3493
        rslt = get_tydesc(bcx, unit_ty, false, no_tydesc_info);
3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506
        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_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;
        rslt = reserve_space(bcx, llunitty, lhs, rhs_len);
        auto lhs_data = rslt.val;
        bcx = rslt.bcx;
        // Work out the end pointer.
3507

3508 3509 3510
        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.
3511

3512 3513 3514 3515
        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);
3516 3517
        auto copy_loop_header_cx =
            new_sub_block_ctxt(bcx, "copy_loop_header");
3518 3519 3520 3521
        bcx.build.Br(copy_loop_header_cx.llbb);
        auto copy_dest_ptr = copy_loop_header_cx.build.Load(dest_ptr);
        auto not_yet_at_end =
            copy_loop_header_cx.build.ICmp(lib::llvm::LLVMIntNE,
3522
                                           copy_dest_ptr, lhs_end);
3523 3524 3525 3526 3527
        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);
3528

3529
        auto copy_src_ptr = copy_loop_body_cx.build.Load(src_ptr);
3530 3531 3532 3533 3534
        auto copy_src = load_if_immediate(copy_loop_body_cx, copy_src_ptr,
                                          unit_ty);

        rslt = copy_val(copy_loop_body_cx, INIT, copy_dest_ptr, copy_src,
                        unit_ty);
3535 3536 3537
        auto post_copy_cx = rslt.bcx;
        // Increment both pointers.

3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550
        if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
            // We have to increment by the dynamically-computed size.
            post_copy_cx.build.Store(post_copy_cx.build.InBoundsGEP(
                copy_dest_ptr, [unit_sz]), dest_ptr);
            post_copy_cx.build.Store(post_copy_cx.build.InBoundsGEP(
                copy_src_ptr, [unit_sz]), src_ptr);
        } else {
            post_copy_cx.build.Store(post_copy_cx.build.InBoundsGEP(
                copy_dest_ptr, [C_int(1)]), dest_ptr);
            post_copy_cx.build.Store(post_copy_cx.build.InBoundsGEP(
                copy_src_ptr, [C_int(1)]), src_ptr);
        }

3551 3552 3553
        post_copy_cx.build.Br(copy_loop_header_cx.llbb);
        ret res(next_cx, C_nil());
    }
3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564

    type alloc_result = rec(@block_ctxt bcx,
                            ValueRef llptr,
                            ValueRef llunitsz,
                            ValueRef llalen);

    fn alloc(&@block_ctxt cx, ty::t unit_ty) -> alloc_result {
        auto dynamic = ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, unit_ty);

        auto bcx;
        if (dynamic) {
3565
            bcx = llderivedtydescs_block_ctxt(cx.fcx);
3566 3567 3568 3569 3570 3571 3572 3573
        } else {
            bcx = cx;
        }

        auto llunitsz;
        auto rslt = size_of(bcx, unit_ty);
        bcx = rslt.bcx;
        llunitsz = rslt.val;
3574 3575

        if (dynamic) { cx.fcx.llderivedtydescs = bcx.llbb; }
3576 3577 3578 3579 3580

        auto llalen = bcx.build.Mul(llunitsz,
                                    C_uint(abi::ivec_default_length));

        auto llptr;
3581
        auto llunitty = type_of_or_i8(bcx, unit_ty);
3582
        auto bcx_result;
3583 3584 3585
        if (dynamic) {
            auto llarraysz = bcx.build.Add(llsize_of(T_opaque_ivec()),
                                           llalen);
3586
            auto llvecptr = array_alloca(bcx, T_i8(), llarraysz);
3587 3588

            bcx_result = cx;
3589 3590
            llptr = bcx_result.build.PointerCast(llvecptr,
                                                 T_ptr(T_opaque_ivec()));
3591
        } else {
3592
            llptr = alloca(bcx, T_ivec(llunitty));
3593 3594 3595 3596 3597 3598 3599
            bcx_result = bcx;
        }

        ret rec(bcx=bcx_result,
                llptr=llptr,
                llunitsz=llunitsz,
                llalen=llalen);
3600
    }
3601 3602 3603

    fn trans_add(&@block_ctxt cx, ty::t vec_ty, ValueRef lhs, ValueRef rhs)
            -> result {
3604 3605
        auto bcx = cx;
        auto unit_ty = ty::sequence_element_type(bcx.fcx.lcx.ccx.tcx, vec_ty);
3606 3607 3608 3609 3610 3611 3612

        auto ares = alloc(bcx, unit_ty);
        bcx = ares.bcx;
        auto llvecptr = ares.llptr;
        auto unit_sz = ares.llunitsz;
        auto llalen = ares.llalen;

3613 3614 3615
        find_scope_cx(bcx).cleanups +=
            [clean(bind drop_ty(_, llvecptr, vec_ty))];

3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631
        auto llunitty = type_of_or_i8(bcx, unit_ty);
        auto llheappartty = T_ivec_heap_part(llunitty);
        auto lhs_len_and_data = get_len_and_data(bcx, lhs, unit_ty);
        auto lhs_len = lhs_len_and_data._0;
        auto lhs_data = lhs_len_and_data._1;
        bcx = lhs_len_and_data._2;
        auto rhs_len_and_data = get_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;
        auto lllen = bcx.build.Add(lhs_len, rhs_len);
        // We have three cases to handle here:
        // (1) Length is zero ([] + []).
        // (2) Copy onto stack.
        // (3) Allocate on heap and copy there.

3632 3633
        auto len_is_zero =
            bcx.build.ICmp(lib::llvm::LLVMIntEQ, lllen, C_int(0));
3634 3635 3636 3637
        auto zero_len_cx = new_sub_block_ctxt(bcx, "zero_len");
        auto nonzero_len_cx = new_sub_block_ctxt(bcx, "nonzero_len");
        bcx.build.CondBr(len_is_zero, zero_len_cx.llbb, nonzero_len_cx.llbb);
        // Case (1): Length is zero.
3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654

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

        auto vec_l = [C_int(0), C_uint(abi::ivec_elt_len)];
        auto vec_a = [C_int(0), C_uint(abi::ivec_elt_alen)];

        auto stub_ptr_zero =
            zero_len_cx.build.PointerCast(llvecptr,
                                          T_ptr(T_ivec_heap(llunitty)));
        zero_len_cx.build.Store(C_int(0),
                                zero_len_cx.build.InBoundsGEP(stub_ptr_zero,
                                                              stub_z));
        zero_len_cx.build.Store(llalen,
                                zero_len_cx.build.InBoundsGEP(stub_ptr_zero,
                                                              stub_a));
3655
        zero_len_cx.build.Store(C_null(T_ptr(llheappartty)),
3656 3657
                                zero_len_cx.build.InBoundsGEP(stub_ptr_zero,
                                                              stub_p));
3658 3659 3660
        auto next_cx = new_sub_block_ctxt(bcx, "next");
        zero_len_cx.build.Br(next_cx.llbb);
        // Determine whether we need to spill to the heap.
3661 3662 3663

        auto on_stack =
            nonzero_len_cx.build.ICmp(lib::llvm::LLVMIntULE, lllen, llalen);
3664 3665 3666 3667
        auto stack_cx = new_sub_block_ctxt(bcx, "stack");
        auto heap_cx = new_sub_block_ctxt(bcx, "heap");
        nonzero_len_cx.build.CondBr(on_stack, stack_cx.llbb, heap_cx.llbb);
        // Case (2): Copy onto stack.
3668 3669 3670 3671 3672 3673 3674 3675 3676

        stack_cx.build.Store(lllen,
                             stack_cx.build.InBoundsGEP(llvecptr, vec_l));
        stack_cx.build.Store(llalen,
                             stack_cx.build.InBoundsGEP(llvecptr, vec_a));
        auto dest_ptr_stack =
            stack_cx.build.InBoundsGEP(llvecptr,
                                       [C_int(0), C_uint(abi::ivec_elt_elems),
                                        C_int(0)]);
3677 3678 3679 3680
        auto copy_cx = new_sub_block_ctxt(bcx, "copy");
        stack_cx.build.Br(copy_cx.llbb);
        // Case (3): Allocate on heap and copy there.

3681 3682 3683 3684 3685 3686 3687 3688
        auto stub_ptr_heap =
            heap_cx.build.PointerCast(llvecptr, T_ptr(T_ivec_heap(llunitty)));
        heap_cx.build.Store(C_int(0),
                            heap_cx.build.InBoundsGEP(stub_ptr_heap,
                                                      stub_z));
        heap_cx.build.Store(lllen,
                            heap_cx.build.InBoundsGEP(stub_ptr_heap,
                                                      stub_a));
3689
        auto heap_sz = heap_cx.build.Add(llsize_of(llheappartty), lllen);
3690
        auto rslt = trans_raw_malloc(heap_cx, T_ptr(llheappartty), heap_sz);
3691 3692
        auto heap_part = rslt.val;
        heap_cx = rslt.bcx;
3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706
        heap_cx.build.Store(heap_part,
                            heap_cx.build.InBoundsGEP(stub_ptr_heap,
                                                      stub_p));
        {
            auto v = [C_int(0), C_uint(abi::ivec_heap_elt_len)];
            heap_cx.build.Store(lllen,
                                heap_cx.build.InBoundsGEP(heap_part,
                                                          v));
        }
        auto dest_ptr_heap =
            heap_cx.build.InBoundsGEP(heap_part,
                                      [C_int(0),
                                       C_uint(abi::ivec_heap_elt_elems),
                                       C_int(0)]);
3707 3708 3709
        heap_cx.build.Br(copy_cx.llbb);
        // Emit the copy loop.

3710 3711 3712 3713
        auto first_dest_ptr =
            copy_cx.build.Phi(T_ptr(llunitty),
                              [dest_ptr_stack, dest_ptr_heap],
                              [stack_cx.llbb, heap_cx.llbb]);
3714
        auto lhs_len_unscaled = copy_cx.build.UDiv(lhs_len, unit_sz);
3715 3716
        auto lhs_end_ptr =
            copy_cx.build.InBoundsGEP(lhs_data, [lhs_len_unscaled]);
3717
        auto rhs_len_unscaled = copy_cx.build.UDiv(rhs_len, unit_sz);
3718 3719
        auto rhs_end_ptr =
            copy_cx.build.InBoundsGEP(rhs_data, [rhs_len_unscaled]);
3720 3721 3722 3723 3724 3725 3726 3727 3728
        auto dest_ptr_ptr = alloca(copy_cx, T_ptr(llunitty));
        copy_cx.build.Store(first_dest_ptr, dest_ptr_ptr);
        auto lhs_ptr_ptr = alloca(copy_cx, T_ptr(llunitty));
        copy_cx.build.Store(lhs_data, lhs_ptr_ptr);
        auto rhs_ptr_ptr = alloca(copy_cx, T_ptr(llunitty));
        copy_cx.build.Store(rhs_data, rhs_ptr_ptr);
        auto lhs_copy_cx = new_sub_block_ctxt(bcx, "lhs_copy");
        copy_cx.build.Br(lhs_copy_cx.llbb);
        // Copy in elements from the LHS.
3729

3730
        auto lhs_ptr = lhs_copy_cx.build.Load(lhs_ptr_ptr);
3731 3732 3733
        auto not_at_end_lhs =
            lhs_copy_cx.build.ICmp(lib::llvm::LLVMIntNE, lhs_ptr,
                                   lhs_end_ptr);
3734 3735 3736 3737 3738 3739
        auto lhs_do_copy_cx = new_sub_block_ctxt(bcx, "lhs_do_copy");
        auto rhs_copy_cx = new_sub_block_ctxt(bcx, "rhs_copy");
        lhs_copy_cx.build.CondBr(not_at_end_lhs, lhs_do_copy_cx.llbb,
                                 rhs_copy_cx.llbb);
        auto dest_ptr_lhs_copy = lhs_do_copy_cx.build.Load(dest_ptr_ptr);
        auto lhs_val = load_if_immediate(lhs_do_copy_cx, lhs_ptr, unit_ty);
3740 3741 3742
        rslt =
            copy_val(lhs_do_copy_cx, INIT, dest_ptr_lhs_copy, lhs_val,
                     unit_ty);
3743
        lhs_do_copy_cx = rslt.bcx;
3744 3745 3746 3747 3748 3749 3750 3751
        {
            auto d = lhs_do_copy_cx.build.InBoundsGEP(dest_ptr_lhs_copy,
                                                      [C_int(1)]);
            auto lhs = lhs_do_copy_cx.build.InBoundsGEP(lhs_ptr,
                                                        [C_int(1)]);
            lhs_do_copy_cx.build.Store(d, dest_ptr_ptr);
            lhs_do_copy_cx.build.Store(lhs, lhs_ptr_ptr);
        }
3752 3753
        lhs_do_copy_cx.build.Br(lhs_copy_cx.llbb);
        // Copy in elements from the RHS.
3754

3755
        auto rhs_ptr = rhs_copy_cx.build.Load(rhs_ptr_ptr);
3756 3757 3758
        auto not_at_end_rhs =
            rhs_copy_cx.build.ICmp(lib::llvm::LLVMIntNE, rhs_ptr,
                                   rhs_end_ptr);
3759 3760 3761 3762 3763
        auto rhs_do_copy_cx = new_sub_block_ctxt(bcx, "rhs_do_copy");
        rhs_copy_cx.build.CondBr(not_at_end_rhs, rhs_do_copy_cx.llbb,
                                 next_cx.llbb);
        auto dest_ptr_rhs_copy = rhs_do_copy_cx.build.Load(dest_ptr_ptr);
        auto rhs_val = load_if_immediate(rhs_do_copy_cx, rhs_ptr, unit_ty);
3764 3765 3766
        rslt =
            copy_val(rhs_do_copy_cx, INIT, dest_ptr_rhs_copy, rhs_val,
                     unit_ty);
3767
        rhs_do_copy_cx = rslt.bcx;
3768 3769 3770 3771 3772 3773 3774 3775
        {
            auto d = rhs_do_copy_cx.build.InBoundsGEP(dest_ptr_rhs_copy,
                                                      [C_int(1)]);
            auto rhs = rhs_do_copy_cx.build.InBoundsGEP(rhs_ptr,
                                                        [C_int(1)]);
            rhs_do_copy_cx.build.Store(d, dest_ptr_ptr);
            rhs_do_copy_cx.build.Store(rhs, rhs_ptr_ptr);
        }
3776 3777
        rhs_do_copy_cx.build.Br(rhs_copy_cx.llbb);
        // Finally done!
3778

3779 3780
        ret res(next_cx, llvecptr);
    }
3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831

    // NB: This does *not* adjust reference counts. The caller must have done
    // this via take_ty() beforehand.
    fn duplicate_heap_part(&@block_ctxt cx, ValueRef orig_vptr,
                           ty::t unit_ty) -> result {
        // Cast to an opaque interior vector if we can't trust the pointer
        // type.
        auto vptr;
        if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, unit_ty)) {
            vptr = cx.build.PointerCast(orig_vptr, T_ptr(T_opaque_ivec()));
        } else {
            vptr = orig_vptr;
        }

        auto llunitty = type_of_or_i8(cx, unit_ty);
        auto llheappartty = T_ivec_heap_part(llunitty);

        // Check to see if the vector is heapified.
        auto stack_len_ptr = cx.build.InBoundsGEP(vptr, [C_int(0),
            C_uint(abi::ivec_elt_len)]);
        auto stack_len = cx.build.Load(stack_len_ptr);
        auto stack_len_is_zero = cx.build.ICmp(lib::llvm::LLVMIntEQ,
                                               stack_len, C_int(0));
        auto maybe_on_heap_cx = new_sub_block_ctxt(cx, "maybe_on_heap");
        auto next_cx = new_sub_block_ctxt(cx, "next");
        cx.build.CondBr(stack_len_is_zero, maybe_on_heap_cx.llbb,
                        next_cx.llbb);

        auto stub_ptr = maybe_on_heap_cx.build.PointerCast(vptr,
            T_ptr(T_ivec_heap(llunitty)));
        auto heap_ptr_ptr = maybe_on_heap_cx.build.InBoundsGEP(stub_ptr,
            [C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)]);
        auto heap_ptr = maybe_on_heap_cx.build.Load(heap_ptr_ptr);
        auto heap_ptr_is_nonnull = maybe_on_heap_cx.build.ICmp(
            lib::llvm::LLVMIntNE, heap_ptr, C_null(T_ptr(llheappartty)));
        auto on_heap_cx = new_sub_block_ctxt(cx, "on_heap");
        maybe_on_heap_cx.build.CondBr(heap_ptr_is_nonnull, on_heap_cx.llbb,
                                      next_cx.llbb);

        // Ok, the vector is on the heap. Copy the heap part.
        auto alen_ptr = on_heap_cx.build.InBoundsGEP(stub_ptr,
            [C_int(0), C_uint(abi::ivec_heap_stub_elt_alen)]);
        auto alen = on_heap_cx.build.Load(alen_ptr);

        auto heap_part_sz = on_heap_cx.build.Add(alen,
            llsize_of(T_opaque_ivec_heap_part()));
        auto rslt = trans_raw_malloc(on_heap_cx, T_ptr(llheappartty),
                                     heap_part_sz);
        on_heap_cx = rslt.bcx;
        auto new_heap_ptr = rslt.val;

3832
        rslt = call_memmove(on_heap_cx, new_heap_ptr, heap_ptr, heap_part_sz);
3833 3834 3835 3836 3837 3838 3839
        on_heap_cx = rslt.bcx;

        on_heap_cx.build.Store(new_heap_ptr, heap_ptr_ptr);
        on_heap_cx.build.Br(next_cx.llbb);

        ret res(next_cx, C_nil());
    }
3840 3841
}

3842 3843
fn trans_vec_add(&@block_ctxt cx, &ty::t t, ValueRef lhs, ValueRef rhs) ->
   result {
3844
    auto r = alloc_ty(cx, t);
3845
    auto tmp = r.val;
3846
    r = copy_val(r.bcx, INIT, tmp, lhs, t);
3847
    auto bcx = trans_vec_append(r.bcx, t, tmp, rhs).bcx;
3848
    tmp = load_if_immediate(bcx, tmp, t);
3849
    find_scope_cx(cx).cleanups += [clean(bind drop_ty(_, tmp, t))];
3850
    ret res(bcx, tmp);
3851 3852
}

3853
fn trans_eager_binop(&@block_ctxt cx, ast::binop op, &ty::t intype,
3854
                     ValueRef lhs, ValueRef rhs) -> result {
3855
    auto is_float = false;
3856
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, intype)) {
3857 3858
        case (ty::ty_float) { is_float = true; }
        case (_) { is_float = false; }
3859
    }
3860
    alt (op) {
3861 3862
        case (ast::add) {
            if (ty::type_is_sequence(cx.fcx.lcx.ccx.tcx, intype)) {
3863 3864 3865
                if (ty::sequence_is_interior(cx.fcx.lcx.ccx.tcx, intype)) {
                    ret ivec::trans_add(cx, intype, lhs, rhs);
                }
3866
                ret trans_vec_add(cx, intype, lhs, rhs);
3867
            }
3868 3869
            if (is_float) {
                ret res(cx, cx.build.FAdd(lhs, rhs));
3870
            } else { ret res(cx, cx.build.Add(lhs, rhs)); }
3871
        }
3872
        case (ast::sub) {
3873 3874
            if (is_float) {
                ret res(cx, cx.build.FSub(lhs, rhs));
3875
            } else { ret res(cx, cx.build.Sub(lhs, rhs)); }
3876
        }
3877
        case (ast::mul) {
3878 3879
            if (is_float) {
                ret res(cx, cx.build.FMul(lhs, rhs));
3880
            } else { ret res(cx, cx.build.Mul(lhs, rhs)); }
3881
        }
3882
        case (ast::div) {
3883
            if (is_float) { ret res(cx, cx.build.FDiv(lhs, rhs)); }
3884
            if (ty::type_is_signed(cx.fcx.lcx.ccx.tcx, intype)) {
3885
                ret res(cx, cx.build.SDiv(lhs, rhs));
3886
            } else { ret res(cx, cx.build.UDiv(lhs, rhs)); }
3887
        }
3888
        case (ast::rem) {
3889
            if (is_float) { ret res(cx, cx.build.FRem(lhs, rhs)); }
3890
            if (ty::type_is_signed(cx.fcx.lcx.ccx.tcx, intype)) {
3891
                ret res(cx, cx.build.SRem(lhs, rhs));
3892
            } else { ret res(cx, cx.build.URem(lhs, rhs)); }
3893
        }
3894 3895 3896 3897 3898 3899
        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)); }
3900
        case (_) { ret trans_compare(cx, op, intype, lhs, rhs); }
3901 3902 3903
    }
}

3904
fn autoderef(&@block_ctxt cx, ValueRef v, &ty::t t) -> result {
3905
    let ValueRef v1 = v;
3906
    let ty::t t1 = t;
3907
    while (true) {
3908 3909
        alt (ty::struct(cx.fcx.lcx.ccx.tcx, t1)) {
            case (ty::ty_box(?mt)) {
3910 3911 3912
                auto body =
                    cx.build.GEP(v1,
                                 [C_int(0), C_int(abi::box_rc_field_body)]);
3913
                t1 = mt.ty;
3914 3915 3916 3917
                // 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.
3918

3919
                if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, mt.ty)) {
3920
                    auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, mt.ty);
3921
                    v1 = cx.build.PointerCast(body, T_ptr(llty));
3922
                } else { v1 = body; }
3923
                v1 = load_if_immediate(cx, v1, t1);
3924
            }
3925
            case (_) { break; }
3926 3927
        }
    }
3928
    ret res(cx, v1);
3929 3930
}

3931 3932
fn autoderefed_ty(&@crate_ctxt ccx, &ty::t t) -> ty::t {
    let ty::t t1 = t;
3933
    while (true) {
3934
        alt (ty::struct(ccx.tcx, t1)) {
3935
            case (ty::ty_box(?mt)) { t1 = mt.ty; }
3936
            case (_) { break; }
3937 3938
        }
    }
3939
    ret t1;
3940 3941
}

3942 3943
fn trans_binary(&@block_ctxt cx, ast::binop op, &@ast::expr a, &@ast::expr b)
   -> result {
3944

3945 3946
    // First couple cases are lazy:
    alt (op) {
3947
        case (ast::and) {
3948 3949
            // Lazy-eval and

3950 3951 3952 3953
            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));
3954
            auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
3955
            auto rhs_res = trans_expr(rhs_cx, b);
3956 3957 3958
            rhs_res =
                autoderef(rhs_res.bcx, rhs_res.val,
                          ty::expr_ty(cx.fcx.lcx.ccx.tcx, b));
3959
            auto lhs_false_cx = new_scope_block_ctxt(cx, "lhs false");
3960
            auto lhs_false_res = res(lhs_false_cx, C_bool(false));
3961
            // The following line ensures that any cleanups for rhs
3962
            // are done within the block for rhs. This is necessary
3963 3964 3965
            // because and/or are lazy. So the rhs may never execute,
            // and the cleanups can't be pushed into later code.

3966 3967
            auto rhs_bcx = trans_block_cleanups(rhs_res.bcx, rhs_cx);
            lhs_res.bcx.build.CondBr(lhs_res.val, rhs_cx.llbb,
3968 3969
                                     lhs_false_cx.llbb);
            ret join_results(cx, T_bool(),
3970
                             [lhs_false_res, rec(bcx=rhs_bcx with rhs_res)]);
3971
        }
3972
        case (ast::or) {
3973 3974
            // Lazy-eval or

3975 3976 3977 3978
            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));
3979
            auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
3980
            auto rhs_res = trans_expr(rhs_cx, b);
3981 3982 3983
            rhs_res =
                autoderef(rhs_res.bcx, rhs_res.val,
                          ty::expr_ty(cx.fcx.lcx.ccx.tcx, b));
3984
            auto lhs_true_cx = new_scope_block_ctxt(cx, "lhs true");
3985
            auto lhs_true_res = res(lhs_true_cx, C_bool(true));
3986 3987
            // see the and case for an explanation

3988 3989
            auto rhs_bcx = trans_block_cleanups(rhs_res.bcx, rhs_cx);
            lhs_res.bcx.build.CondBr(lhs_res.val, lhs_true_cx.llbb,
3990
                                     rhs_cx.llbb);
3991
            ret join_results(cx, T_bool(),
3992
                             [lhs_true_res, rec(bcx=rhs_bcx with rhs_res)]);
3993
        }
3994
        case (_) {
3995
            // Remaining cases are eager:
3996

3997
            auto lhs = trans_expr(cx, a);
3998
            auto lhty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, a);
3999
            lhs = autoderef(lhs.bcx, lhs.val, lhty);
4000
            auto rhs = trans_expr(lhs.bcx, b);
4001
            auto rhty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, b);
4002
            rhs = autoderef(rhs.bcx, rhs.val, rhty);
4003
            ret trans_eager_binop(rhs.bcx, op,
4004 4005
                                  autoderefed_ty(cx.fcx.lcx.ccx, lhty),
                                  lhs.val, rhs.val);
4006
        }
4007 4008 4009
    }
}

4010 4011
fn join_results(&@block_ctxt parent_cx, TypeRef t, &vec[result] ins) ->
   result {
4012 4013 4014
    let vec[result] live = [];
    let vec[ValueRef] vals = [];
    let vec[BasicBlockRef] bbs = [];
4015
    for (result r in ins) {
4016
        if (!is_terminated(r.bcx)) {
4017 4018 4019
            live += [r];
            vals += [r.val];
            bbs += [r.bcx.llbb];
4020 4021
        }
    }
4022
    alt (vec::len[result](live)) {
4023 4024 4025 4026
        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.
4027

4028
            assert (vec::len[result](ins) >= 1u);
4029 4030
            ret ins.(0);
        }
4031
        case (_) {/* fall through */ }
4032 4033
    }
    // We have >1 incoming edges. Make a join block and br+phi them into it.
4034

4035
    auto join_cx = new_sub_block_ctxt(parent_cx, "join");
4036
    for (result r in live) { r.bcx.build.Br(join_cx.llbb); }
4037 4038 4039 4040
    auto phi = join_cx.build.Phi(t, vals, bbs);
    ret res(join_cx, phi);
}

4041 4042 4043
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) {
4044
        if (!is_terminated(r.bcx)) { r.bcx.build.Br(out.llbb); }
4045 4046 4047 4048
    }
    ret out;
}

4049
tag out_method { return; save_in(ValueRef); }
4050

4051 4052 4053
fn trans_if(&@block_ctxt cx, &@ast::expr cond, &ast::block thn,
            &option::t[@ast::expr] els, &ast::ann ann, &out_method output) ->
   result {
4054
    auto cond_res = trans_expr(cx, cond);
4055
    auto then_cx = new_scope_block_ctxt(cx, "then");
4056
    auto then_res = trans_block(then_cx, thn, output);
4057
    auto else_cx = new_scope_block_ctxt(cx, "else");
4058 4059
    auto else_res;
    auto expr_llty;
4060
    alt (els) {
4061
        case (some(?elexpr)) {
4062
            alt (elexpr.node) {
4063 4064 4065 4066 4067
                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.
4068 4069 4070 4071

                    let ast::block_ elseif_blk_ =
                        rec(stmts=[], expr=some[@ast::expr](elexpr), a=ann);
                    auto elseif_blk = rec(node=elseif_blk_, span=elexpr.span);
4072
                    else_res = trans_block(else_cx, elseif_blk, output);
4073
                }
4074
                case (ast::expr_block(?blk, _)) {
4075 4076 4077 4078
                    // 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
4079

4080
                    else_res = trans_block(else_cx, blk, output);
4081 4082
                }
            }
4083
            // FIXME: This isn't quite right, particularly re: dynamic types
4084 4085

            auto expr_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann);
4086
            if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, expr_ty)) {
4087
                expr_llty = T_typaram_ptr(cx.fcx.lcx.ccx.tn);
4088
            } else {
4089
                expr_llty = type_of(cx.fcx.lcx.ccx, elexpr.span, expr_ty);
4090
                if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, expr_ty)) {
4091 4092
                    expr_llty = T_ptr(expr_llty);
                }
4093
            }
4094
        }
4095
        case (_) { else_res = res(else_cx, C_nil()); expr_llty = T_nil(); }
4096
    }
4097
    cond_res.bcx.build.CondBr(cond_res.val, then_cx.llbb, else_cx.llbb);
4098
    ret res(join_branches(cx, [then_res, else_res]), C_nil());
4099 4100
}

4101
fn trans_for(&@block_ctxt cx, &@ast::local local, &@ast::expr seq,
4102
             &ast::block body) -> result {
P
Paul Stansifer 已提交
4103
    fn inner(&@block_ctxt cx, @ast::local local, ValueRef curr, ty::t t,
4104
             ast::block body, @block_ctxt outer_next_cx) -> result {
G
Graydon Hoare 已提交
4105
        auto next_cx = new_sub_block_ctxt(cx, "next");
4106
        auto scope_cx =
4107
            new_loop_scope_block_ctxt(cx, option::some[@block_ctxt](next_cx),
4108
                                      outer_next_cx, "for loop scope");
G
Graydon Hoare 已提交
4109 4110
        cx.build.Br(scope_cx.llbb);
        auto local_res = alloc_local(scope_cx, local);
4111
        auto bcx = copy_val(local_res.bcx, INIT, local_res.val, curr, t).bcx;
4112
        scope_cx.cleanups += [clean(bind drop_slot(_, local_res.val, t))];
4113
        bcx = trans_block(bcx, body, return).bcx;
G
Graydon Hoare 已提交
4114 4115 4116
        bcx.build.Br(next_cx.llbb);
        ret res(next_cx, C_nil());
    }
4117
    auto next_cx = new_sub_block_ctxt(cx, "next");
4118
    auto seq_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, seq);
G
Graydon Hoare 已提交
4119
    auto seq_res = trans_expr(cx, seq);
4120 4121
    auto it =
        iter_sequence(seq_res.bcx, seq_res.val, seq_ty,
P
Paul Stansifer 已提交
4122
                      bind inner(_, local, _, _, body, next_cx));
4123 4124
    it.bcx.build.Br(next_cx.llbb);
    ret res(next_cx, it.val);
G
Graydon Hoare 已提交
4125 4126
}

4127 4128 4129 4130 4131

// 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.
4132 4133
fn collect_upvars(&@block_ctxt cx, &ast::block bloc,
                  &ast::def_id initial_decl) -> vec[ast::def_id] {
4134 4135 4136 4137
    type env =
        @rec(mutable vec[ast::def_id] refs,
             hashmap[ast::def_id, ()] decls,
             resolve::def_map def_map);
4138

4139
    fn walk_expr(env e, &@ast::expr expr) {
M
Marijn Haverbeke 已提交
4140
        alt (expr.node) {
4141
            case (ast::expr_path(?path, ?ann)) {
P
Patrick Walton 已提交
4142
                alt (e.def_map.get(ann.id)) {
4143
                    case (ast::def_arg(?did)) {
4144
                        vec::push[ast::def_id](e.refs, did);
M
Marijn Haverbeke 已提交
4145
                    }
4146
                    case (ast::def_local(?did)) {
4147
                        vec::push[ast::def_id](e.refs, did);
M
Marijn Haverbeke 已提交
4148
                    }
4149
                    case (_) { }
M
Marijn Haverbeke 已提交
4150 4151
                }
            }
4152
            case (_) { }
4153 4154
        }
    }
4155 4156
    fn walk_local(env e, &@ast::local local) {
        e.decls.insert(local.node.id, ());
4157
    }
4158
    let vec[ast::def_id] refs = [];
4159
    let hashmap[ast::def_id, ()] decls = new_def_hash[()]();
4160
    decls.insert(initial_decl, ());
4161 4162 4163 4164 4165 4166 4167 4168
    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());
4169
    walk::walk_block(*visitor, bloc);
4170
    // Calculate (refs - decls). This is the set of captured upvars.
4171

4172
    let vec[ast::def_id] result = [];
4173 4174
    for (ast::def_id ref_id_ in e.refs) {
        auto ref_id = ref_id_;
4175
        if (!decls.contains_key(ref_id)) { result += [ref_id]; }
4176 4177 4178 4179
    }
    ret result;
}

4180
fn trans_for_each(&@block_ctxt cx, &@ast::local local, &@ast::expr seq,
4181
                  &ast::block body) -> result {
4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207
    /*
     * 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.

4208
    auto lcx = cx.fcx.lcx;
4209
    // FIXME: possibly support alias-mode here?
4210

4211 4212
    auto decl_ty = node_ann_type(lcx.ccx, local.node.ann);
    auto decl_id = local.node.id;
4213
    auto upvars = collect_upvars(cx, body, decl_id);
4214
    auto upvar_count = vec::len[ast::def_id](upvars);
4215 4216 4217
    auto llbindingsptr;
    if (upvar_count > 0u) {
        // Gather up the upvars.
4218

4219 4220
        let vec[ValueRef] llbindings = [];
        let vec[TypeRef] llbindingtys = [];
4221
        for (ast::def_id did in upvars) {
4222 4223
            auto llbinding;
            alt (cx.fcx.lllocals.find(did)) {
4224
                case (none) {
4225 4226 4227 4228 4229 4230
                    alt (cx.fcx.llupvars.find(did)) {
                        case (none[ValueRef]) {
                            llbinding = cx.fcx.llargs.get(did);
                        }
                        case (some[ValueRef](?llval)) { llbinding = llval; }
                    }
4231
                }
4232
                case (some(?llval)) { llbinding = llval; }
4233
            }
4234 4235
            llbindings += [llbinding];
            llbindingtys += [val_ty(llbinding)];
4236 4237
        }
        // Create an array of bindings and copy in aliases to the upvars.
4238

4239
        llbindingsptr = alloca(cx, T_struct(llbindingtys));
4240 4241
        auto i = 0u;
        while (i < upvar_count) {
4242 4243
            auto llbindingptr =
                cx.build.GEP(llbindingsptr, [C_int(0), C_int(i as int)]);
4244 4245 4246 4247 4248
            cx.build.Store(llbindings.(i), llbindingptr);
            i += 1u;
        }
    } else {
        // Null bindings.
4249

4250
        llbindingsptr = C_null(T_ptr(T_i8()));
4251
    }
4252
    // Create an environment and populate it with the bindings.
4253

4254
    auto tydesc_count = vec::len[ValueRef](cx.fcx.lltydescs);
4255 4256 4257
    auto llenvptrty =
        T_closure_ptr(lcx.ccx.tn, T_ptr(T_nil()), val_ty(llbindingsptr),
                      tydesc_count);
4258
    auto llenvptr = alloca(cx, llvm::LLVMGetElementType(llenvptrty));
4259 4260 4261
    auto llbindingsptrptr =
        cx.build.GEP(llenvptr,
                     [C_int(0), C_int(abi::box_rc_field_body), C_int(2)]);
4262
    cx.build.Store(llbindingsptr, llbindingsptrptr);
4263 4264
    // Copy in our type descriptors, in case the iterator body needs to refer
    // to them.
4265 4266 4267 4268 4269

    auto lltydescsptr =
        cx.build.GEP(llenvptr,
                     [C_int(0), C_int(abi::box_rc_field_body),
                      C_int(abi::closure_elt_ty_params)]);
4270 4271
    auto i = 0u;
    while (i < tydesc_count) {
4272 4273
        auto lltydescptr =
            cx.build.GEP(lltydescsptr, [C_int(0), C_int(i as int)]);
4274 4275 4276
        cx.build.Store(cx.fcx.lltydescs.(i), lltydescptr);
        i += 1u;
    }
4277 4278
    // Step 2: Declare foreach body function.

4279 4280
    let str s =
        mangle_internal_name_by_path_and_seq(lcx.ccx, lcx.path, "foreach");
4281 4282 4283 4284 4285 4286
    // 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.

4287
    auto iter_body_llty =
4288
        type_of_fn_full(lcx.ccx, cx.sp, ast::proto_fn, none[TypeRef],
4289
                        [rec(mode=ty::mo_alias(false), ty=decl_ty)],
4290
                        ty::mk_nil(lcx.ccx.tcx), 0u);
4291 4292
    let ValueRef lliterbody =
        decl_internal_fastcall_fn(lcx.ccx.llmod, s, iter_body_llty);
4293
    auto fcx = new_fn_ctxt(lcx, cx.sp, lliterbody);
4294
    auto copy_args_bcx = new_raw_block_ctxt(fcx, fcx.llcopyargs);
4295
    // Populate the upvars from the environment.
4296 4297 4298

    auto llremoteenvptr =
        copy_args_bcx.build.PointerCast(fcx.llenv, llenvptrty);
4299
    auto llremotebindingsptrptr =
4300
        copy_args_bcx.build.GEP(llremoteenvptr,
4301 4302
                                [C_int(0), C_int(abi::box_rc_field_body),
                                 C_int(abi::closure_elt_bindings)]);
4303 4304
    auto llremotebindingsptr =
        copy_args_bcx.build.Load(llremotebindingsptrptr);
4305
    i = 0u;
4306 4307
    while (i < upvar_count) {
        auto upvar_id = upvars.(i);
4308 4309
        auto llupvarptrptr =
            copy_args_bcx.build.GEP(llremotebindingsptr,
4310
                                    [C_int(0), C_int(i as int)]);
4311
        auto llupvarptr = copy_args_bcx.build.Load(llupvarptrptr);
4312 4313 4314
        fcx.llupvars.insert(upvar_id, llupvarptr);
        i += 1u;
    }
4315
    // Populate the type parameters from the environment.
4316

4317
    auto llremotetydescsptr =
4318
        copy_args_bcx.build.GEP(llremoteenvptr,
4319 4320
                                [C_int(0), C_int(abi::box_rc_field_body),
                                 C_int(abi::closure_elt_ty_params)]);
4321 4322
    i = 0u;
    while (i < tydesc_count) {
4323
        auto llremotetydescptr =
4324 4325
            copy_args_bcx.build.GEP(llremotetydescsptr,
                                    [C_int(0), C_int(i as int)]);
4326
        auto llremotetydesc = copy_args_bcx.build.Load(llremotetydescptr);
4327
        fcx.lltydescs += [llremotetydesc];
4328 4329
        i += 1u;
    }
4330
    // Add an upvar for the loop variable alias.
4331

4332
    fcx.llupvars.insert(decl_id, llvm::LLVMGetParam(fcx.llfn, 3u));
4333 4334
    auto bcx = new_top_block_ctxt(fcx);
    auto lltop = bcx.llbb;
4335
    auto r = trans_block(bcx, body, return);
4336
    finish_fn(fcx, lltop);
4337
    r.bcx.build.RetVoid();
4338

4339
    // Step 3: Call iter passing [lliterbody, llenv], plus other args.
4340
    alt (seq.node) {
4341
        case (ast::expr_call(?f, ?args, ?ann)) {
4342 4343 4344
            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)]);
4345
            cx.build.Store(lliterbody, code_cell);
4346 4347 4348 4349 4350
            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));
4351
            cx.build.Store(llenvblobptr, env_cell);
4352
            // log "lliterbody: " + val_str(lcx.ccx.tn, lliterbody);
4353 4354 4355

            r =
                trans_call(cx, f, some[ValueRef](cx.build.Load(pair)), args,
4356
                           ann);
4357
            ret res(r.bcx, C_nil());
4358 4359
        }
    }
4360 4361
}

4362 4363
fn trans_while(&@block_ctxt cx, &@ast::expr cond, &ast::block body) ->
   result {
4364
    auto cond_cx = new_scope_block_ctxt(cx, "while cond");
4365
    auto next_cx = new_sub_block_ctxt(cx, "next");
4366 4367 4368
    auto body_cx =
        new_loop_scope_block_ctxt(cx, option::none[@block_ctxt], next_cx,
                                  "while loop body");
4369
    auto body_res = trans_block(body_cx, body, return);
4370 4371
    auto cond_res = trans_expr(cond_cx, cond);
    body_res.bcx.build.Br(cond_cx.llbb);
4372 4373
    auto cond_bcx = trans_block_cleanups(cond_res.bcx, cond_cx);
    cond_bcx.build.CondBr(cond_res.val, body_cx.llbb, next_cx.llbb);
4374
    cx.build.Br(cond_cx.llbb);
4375 4376 4377
    ret res(next_cx, C_nil());
}

4378 4379
fn trans_do_while(&@block_ctxt cx, &ast::block body, &@ast::expr cond) ->
   result {
4380
    auto next_cx = new_sub_block_ctxt(cx, "next");
4381 4382 4383
    auto body_cx =
        new_loop_scope_block_ctxt(cx, option::none[@block_ctxt], next_cx,
                                  "do-while loop body");
4384
    auto body_res = trans_block(body_cx, body, return);
4385
    auto cond_res = trans_expr(body_res.bcx, cond);
4386
    cond_res.bcx.build.CondBr(cond_res.val, body_cx.llbb, next_cx.llbb);
4387
    cx.build.Br(body_cx.llbb);
4388 4389 4390
    ret res(next_cx, body_res.val);
}

P
Patrick Walton 已提交
4391

4392
// Pattern matching translation
4393
fn trans_pat_match(&@block_ctxt cx, &@ast::pat pat, ValueRef llval,
G
Graydon Hoare 已提交
4394
                   &@block_ctxt next_cx) -> result {
P
Patrick Walton 已提交
4395
    alt (pat.node) {
4396 4397 4398
        case (ast::pat_wild(_)) { ret res(cx, llval); }
        case (ast::pat_bind(_, _, _)) { ret res(cx, llval); }
        case (ast::pat_lit(?lt, ?ann)) {
4399
            auto lllit = trans_lit(cx.fcx.lcx.ccx, *lt, ann);
4400
            auto lltype = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann);
4401
            auto lleq = trans_compare(cx, ast::eq, lltype, llval, lllit);
4402 4403
            auto matched_cx = new_sub_block_ctxt(lleq.bcx, "matched_cx");
            lleq.bcx.build.CondBr(lleq.val, matched_cx.llbb, next_cx.llbb);
4404 4405
            ret res(matched_cx, llval);
        }
4406
        case (ast::pat_tag(?id, ?subpats, ?ann)) {
4407 4408 4409 4410
            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)]);
4411
            auto lldiscrim = cx.build.Load(lldiscrimptr);
4412 4413
            auto vdef =
                ast::variant_def_ids(cx.fcx.lcx.ccx.tcx.def_map.get(ann.id));
P
Patrick Walton 已提交
4414
            auto variant_tag = 0;
4415
            auto variants = ty::tag_variants(cx.fcx.lcx.ccx.tcx, vdef._0);
P
Patrick Walton 已提交
4416
            auto i = 0;
4417
            for (ty::variant_info v in variants) {
4418
                auto this_variant_id = v.id;
4419
                if (vdef._1._0 == this_variant_id._0 &&
4420
                        vdef._1._1 == this_variant_id._1) {
P
Patrick Walton 已提交
4421 4422 4423 4424 4425
                    variant_tag = i;
                }
                i += 1;
            }
            auto matched_cx = new_sub_block_ctxt(cx, "matched_cx");
4426 4427 4428
            auto lleq =
                cx.build.ICmp(lib::llvm::LLVMIntEQ, lldiscrim,
                              C_int(variant_tag));
P
Patrick Walton 已提交
4429
            cx.build.CondBr(lleq, matched_cx.llbb, next_cx.llbb);
4430
            auto ty_params = ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx, ann);
4431
            if (vec::len[@ast::pat](subpats) > 0u) {
4432 4433
                auto llblobptr =
                    matched_cx.build.GEP(lltagptr, [C_int(0), C_int(1)]);
P
Patrick Walton 已提交
4434
                auto i = 0;
4435
                for (@ast::pat subpat in subpats) {
4436 4437 4438
                    auto rslt =
                        GEP_tag(matched_cx, llblobptr, vdef._0, vdef._1,
                                ty_params, i);
4439 4440
                    auto llsubvalptr = rslt.val;
                    matched_cx = rslt.bcx;
4441 4442 4443 4444 4445 4446
                    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 已提交
4447
                    matched_cx = subpat_res.bcx;
4448
                    i += 1;
P
Patrick Walton 已提交
4449 4450 4451 4452 4453 4454 4455
                }
            }
            ret res(matched_cx, llval);
        }
    }
}

4456 4457
fn trans_pat_binding(&@block_ctxt cx, &@ast::pat pat, ValueRef llval,
                     bool bind_alias) -> result {
P
Patrick Walton 已提交
4458
    alt (pat.node) {
4459 4460 4461
        case (ast::pat_wild(_)) { ret res(cx, llval); }
        case (ast::pat_lit(_, _)) { ret res(cx, llval); }
        case (ast::pat_bind(?id, ?def_id, ?ann)) {
4462 4463 4464 4465 4466 4467 4468 4469
            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;
4470
                maybe_name_value(cx.fcx.lcx.ccx, dst, id);
4471
                bcx.fcx.lllocals.insert(def_id, dst);
4472
                bcx.cleanups += [clean(bind drop_slot(_, dst, t))];
4473
                ret copy_val(bcx, INIT, dst, llval, t);
4474
            }
P
Patrick Walton 已提交
4475
        }
4476
        case (ast::pat_tag(_, ?subpats, ?ann)) {
4477
            if (vec::len[@ast::pat](subpats) == 0u) { ret res(cx, llval); }
4478 4479
            // Get the appropriate variant for this tag.

4480 4481 4482 4483 4484
            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));
4485
            auto llblobptr = cx.build.GEP(lltagptr, [C_int(0), C_int(1)]);
4486
            auto ty_param_substs =
4487
                ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx, ann);
P
Patrick Walton 已提交
4488 4489
            auto this_cx = cx;
            auto i = 0;
4490
            for (@ast::pat subpat in subpats) {
4491 4492 4493
                auto rslt =
                    GEP_tag(this_cx, llblobptr, vdef._0, vdef._1,
                            ty_param_substs, i);
4494
                this_cx = rslt.bcx;
4495 4496
                auto subpat_res =
                    trans_pat_binding(this_cx, subpat, rslt.val, true);
P
Patrick Walton 已提交
4497
                this_cx = subpat_res.bcx;
4498
                i += 1;
P
Patrick Walton 已提交
4499 4500 4501 4502 4503 4504
            }
            ret res(this_cx, llval);
        }
    }
}

4505 4506
fn trans_alt(&@block_ctxt cx, &@ast::expr expr, &vec[ast::arm] arms,
             &ast::ann ann, &out_method output) -> result {
P
Patrick Walton 已提交
4507 4508
    auto expr_res = trans_expr(cx, expr);
    auto this_cx = expr_res.bcx;
4509
    let vec[result] arm_results = [];
4510
    for (ast::arm arm in arms) {
P
Patrick Walton 已提交
4511
        auto next_cx = new_sub_block_ctxt(expr_res.bcx, "next");
4512 4513
        auto match_res =
            trans_pat_match(this_cx, arm.pat, expr_res.val, next_cx);
P
Patrick Walton 已提交
4514 4515
        auto binding_cx = new_scope_block_ctxt(match_res.bcx, "binding");
        match_res.bcx.build.Br(binding_cx.llbb);
4516 4517
        auto binding_res =
            trans_pat_binding(binding_cx, arm.pat, expr_res.val, false);
4518
        auto block_res = trans_block(binding_res.bcx, arm.block, output);
4519
        arm_results += [block_res];
P
Patrick Walton 已提交
4520 4521
        this_cx = next_cx;
    }
4522
    auto default_cx = this_cx;
4523 4524 4525
    auto default_res =
        trans_fail(default_cx, some[common::span](expr.span),
                   "non-exhaustive match failure");
4526
    // FIXME: This isn't quite right, particularly re: dynamic types
4527

4528
    auto expr_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann);
4529
    auto expr_llty;
4530
    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, expr_ty)) {
4531
        expr_llty = T_typaram_ptr(cx.fcx.lcx.ccx.tn);
4532
    } else {
4533
        expr_llty = type_of(cx.fcx.lcx.ccx, expr.span, expr_ty);
4534
        if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, expr_ty)) {
4535 4536 4537
            expr_llty = T_ptr(expr_llty);
        }
    }
4538
    ret res(join_branches(cx, arm_results), C_nil());
P
Patrick Walton 已提交
4539 4540
}

4541 4542 4543 4544
type generic_info =
    rec(ty::t item_type,
        vec[option::t[@tydesc_info]] static_tis,
        vec[ValueRef] tydescs);
4545

4546 4547 4548 4549 4550 4551
type lval_result =
    rec(result res,
        bool is_mem,
        option::t[generic_info] generic,
        option::t[ValueRef] llobj,
        option::t[ty::t] method_ty);
4552

G
Graydon Hoare 已提交
4553
fn lval_mem(&@block_ctxt cx, ValueRef val) -> lval_result {
4554 4555
    ret rec(res=res(cx, val),
            is_mem=true,
4556
            generic=none[generic_info],
4557
            llobj=none[ValueRef],
4558
            method_ty=none[ty::t]);
4559 4560
}

G
Graydon Hoare 已提交
4561
fn lval_val(&@block_ctxt cx, ValueRef val) -> lval_result {
4562 4563
    ret rec(res=res(cx, val),
            is_mem=false,
4564
            generic=none[generic_info],
4565
            llobj=none[ValueRef],
4566
            method_ty=none[ty::t]);
4567
}
4568

4569 4570
fn trans_external_path(&@block_ctxt cx, &ast::def_id did,
                       &ty::ty_param_count_and_ty tpt) -> lval_result {
4571
    auto lcx = cx.fcx.lcx;
4572
    auto name = creader::get_symbol(lcx.ccx.sess, did);
4573 4574 4575
    auto v =
        get_extern_const(lcx.ccx.externs, lcx.ccx.llmod, name,
                         type_of_ty_param_count_and_ty(lcx, cx.sp, tpt));
4576 4577 4578
    ret lval_val(cx, v);
}

4579 4580
fn lval_generic_fn(&@block_ctxt cx, &ty::ty_param_count_and_ty tpt,
                   &ast::def_id fn_id, &ast::ann ann) -> lval_result {
4581
    auto lv;
4582
    if (cx.fcx.lcx.ccx.sess.get_targ_crate_num() == fn_id._0) {
4583
        // Internal reference.
4584

4585
        assert (cx.fcx.lcx.ccx.fn_pairs.contains_key(fn_id));
4586
        lv = lval_val(cx, cx.fcx.lcx.ccx.fn_pairs.get(fn_id));
4587 4588
    } else {
        // External reference.
4589

4590
        lv = trans_external_path(cx, fn_id, tpt);
4591
    }
4592 4593
    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);
4594
    if (vec::len[ty::t](tys) != 0u) {
4595
        auto bcx = lv.res.bcx;
4596 4597
        let vec[ValueRef] tydescs = [];
        let vec[option::t[@tydesc_info]] tis = [];
4598
        for (ty::t t in tys) {
4599
            // TODO: Doesn't always escape.
4600

4601 4602
            auto ti = none[@tydesc_info];
            auto td = get_tydesc(bcx, t, true, ti);
4603
            tis += [ti];
4604
            bcx = td.bcx;
4605
            vec::push[ValueRef](tydescs, td.val);
4606
        }
4607 4608 4609 4610
        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);
4611 4612 4613 4614
    }
    ret lv;
}

4615
fn lookup_discriminant(&@local_ctxt lcx, &ast::def_id tid, &ast::def_id vid)
4616
   -> ValueRef {
4617
    alt (lcx.ccx.discrims.find(vid)) {
4618
        case (none) {
4619
            // It's an external discriminant that we haven't seen yet.
4620

4621
            assert (lcx.ccx.sess.get_targ_crate_num() != vid._0);
4622
            auto sym = creader::get_symbol(lcx.ccx.sess, vid);
4623 4624 4625 4626 4627
            auto gvar =
                llvm::LLVMAddGlobal(lcx.ccx.llmod, T_int(), str::buf(sym));
            llvm::LLVMSetLinkage(gvar,
                                 lib::llvm::LLVMExternalLinkage as
                                     llvm::Linkage);
4628
            llvm::LLVMSetGlobalConstant(gvar, True);
4629
            lcx.ccx.discrims.insert(vid, gvar);
4630 4631
            ret gvar;
        }
4632
        case (some(?llval)) { ret llval; }
4633 4634 4635
    }
}

4636
fn trans_path(&@block_ctxt cx, &ast::path p, &ast::ann ann) -> lval_result {
P
Patrick Walton 已提交
4637
    alt (cx.fcx.lcx.ccx.tcx.def_map.get(ann.id)) {
4638
        case (ast::def_arg(?did)) {
4639
            alt (cx.fcx.llargs.find(did)) {
4640
                case (none) {
4641 4642
                    assert (cx.fcx.llupvars.contains_key(did));
                    ret lval_mem(cx, cx.fcx.llupvars.get(did));
G
Graydon Hoare 已提交
4643
                }
4644
                case (some(?llval)) { ret lval_mem(cx, llval); }
4645 4646
            }
        }
4647
        case (ast::def_local(?did)) {
4648
            alt (cx.fcx.lllocals.find(did)) {
4649
                case (none) {
4650 4651
                    assert (cx.fcx.llupvars.contains_key(did));
                    ret lval_mem(cx, cx.fcx.llupvars.get(did));
4652
                }
4653
                case (some(?llval)) { ret lval_mem(cx, llval); }
4654 4655
            }
        }
4656
        case (ast::def_binding(?did)) {
4657 4658 4659
            assert (cx.fcx.lllocals.contains_key(did));
            ret lval_mem(cx, cx.fcx.lllocals.get(did));
        }
4660
        case (ast::def_obj_field(?did)) {
4661 4662 4663
            assert (cx.fcx.llobjfields.contains_key(did));
            ret lval_mem(cx, cx.fcx.llobjfields.get(did));
        }
4664
        case (ast::def_fn(?did)) {
4665
            auto tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, did);
4666 4667
            ret lval_generic_fn(cx, tyt, did, ann);
        }
4668
        case (ast::def_obj(?did)) {
4669
            auto tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, did);
4670 4671
            ret lval_generic_fn(cx, tyt, did, ann);
        }
4672
        case (ast::def_variant(?tid, ?vid)) {
4673
            auto v_tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, vid);
4674
            alt (ty::struct(cx.fcx.lcx.ccx.tcx, v_tyt._1)) {
4675
                case (ty::ty_fn(_, _, _, _, _)) {
4676
                    // N-ary variant.
4677

4678
                    ret lval_generic_fn(cx, v_tyt, vid, ann);
4679
                }
4680 4681
                case (_) {
                    // Nullary variant.
4682

4683 4684 4685 4686 4687 4688 4689
                    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;
4690 4691
                    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, tag_ty))
                       {
4692 4693
                        lltagty = T_opaque_tag(cx.fcx.lcx.ccx.tn);
                    } else {
4694
                        lltagty = type_of(cx.fcx.lcx.ccx, p.span, tag_ty);
4695
                    }
4696 4697 4698 4699 4700 4701 4702
                    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);
4703
                    ret lval_val(alloc_result.bcx, lltagptr);
G
Graydon Hoare 已提交
4704 4705 4706
                }
            }
        }
4707
        case (ast::def_const(?did)) {
4708
            // TODO: externals
4709

4710 4711 4712
            assert (cx.fcx.lcx.ccx.consts.contains_key(did));
            ret lval_mem(cx, cx.fcx.lcx.ccx.consts.get(did));
        }
4713
        case (ast::def_native_fn(?did)) {
4714
            auto tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, did);
4715 4716 4717
            ret lval_generic_fn(cx, tyt, did, ann);
        }
        case (_) {
4718
            cx.fcx.lcx.ccx.sess.span_unimpl(cx.sp, "def variant in trans");
4719 4720 4721 4722
        }
    }
}

4723
fn trans_field(&@block_ctxt cx, &span sp, ValueRef v, &ty::t t0,
4724
               &ast::ident field, &ast::ann ann) -> lval_result {
4725
    auto r = autoderef(cx, v, t0);
4726
    auto t = autoderefed_ty(cx.fcx.lcx.ccx, t0);
4727 4728 4729
    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);
4730
            auto v = GEP_tup_like(r.bcx, t, r.val, [0, ix as int]);
4731
            ret lval_mem(v.bcx, v.val);
4732
        }
4733
        case (ty::ty_rec(?fields)) {
4734 4735
            let uint ix =
                ty::field_idx(cx.fcx.lcx.ccx.sess, sp, field, fields);
4736
            auto v = GEP_tup_like(r.bcx, t, r.val, [0, ix as int]);
4737
            ret lval_mem(v.bcx, v.val);
4738
        }
4739
        case (ty::ty_obj(?methods)) {
4740 4741 4742 4743 4744
            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)]);
4745
            vtbl = r.bcx.build.Load(vtbl);
4746
            // +1 because slot #0 contains the destructor
4747

4748
            auto v = r.bcx.build.GEP(vtbl, [C_int(0), C_int(ix + 1u as int)]);
4749
            auto lvo = lval_mem(r.bcx, v);
4750 4751 4752
            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)
4753
                    with lvo);
4754
        }
4755 4756 4757
        case (_) {
            cx.fcx.lcx.ccx.sess.unimpl("field variant in trans_field");
        }
4758 4759 4760
    }
}

4761 4762
fn trans_index(&@block_ctxt cx, &span sp, &@ast::expr base, &@ast::expr idx,
               &ast::ann ann) -> lval_result {
4763
    // Is this an interior vector?
4764

4765 4766
    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);
4767 4768
    auto is_interior =
        ty::sequence_is_interior(cx.fcx.lcx.ccx.tcx, base_ty_no_boxes);
G
Graydon Hoare 已提交
4769
    auto lv = trans_expr(cx, base);
4770
    lv = autoderef(lv.bcx, lv.val, base_ty);
G
Graydon Hoare 已提交
4771 4772
    auto ix = trans_expr(lv.bcx, idx);
    auto v = lv.val;
4773
    auto bcx = ix.bcx;
4774
    // Cast to an LLVM integer. Rust is less strict than LLVM in this regard.
4775

4776
    auto ix_val;
4777 4778
    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());
4779 4780 4781 4782
    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());
4783
    } else { ix_val = ix.val; }
4784
    auto unit_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
4785
    auto unit_sz = size_of(bcx, unit_ty);
4786
    bcx = unit_sz.bcx;
4787
    maybe_name_value(cx.fcx.lcx.ccx, unit_sz.val, "unit_sz");
4788
    auto scaled_ix = bcx.build.Mul(ix_val, unit_sz.val);
4789
    maybe_name_value(cx.fcx.lcx.ccx, scaled_ix, "scaled_ix");
4790 4791
    auto interior_len_and_data;
    if (is_interior) {
4792
        auto rslt = ivec::get_len_and_data(bcx, v, unit_ty);
4793 4794
        interior_len_and_data = some(tup(rslt._0, rslt._1));
        bcx = rslt._2;
4795
    } else { interior_len_and_data = none; }
4796 4797 4798 4799 4800 4801 4802 4803
    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);
        }
    }
4804
    auto bounds_check = bcx.build.ICmp(lib::llvm::LLVMIntULT, scaled_ix, lim);
4805 4806 4807
    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);
4808 4809
    // fail: bad bounds check.

4810 4811
    auto fail_res =
        trans_fail(fail_cx, some[common::span](sp), "bounds check");
4812 4813 4814 4815
    auto body;
    alt (interior_len_and_data) {
        case (some(?lad)) { body = lad._1; }
        case (none) {
4816 4817 4818 4819
            body =
                next_cx.build.GEP(v,
                                  [C_int(0), C_int(abi::vec_elt_data),
                                   C_int(0)]);
4820 4821
        }
    }
4822
    auto elt;
4823
    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, unit_ty)) {
4824 4825
        body = next_cx.build.PointerCast(body, T_ptr(T_i8()));
        elt = next_cx.build.GEP(body, [scaled_ix]);
4826
    } else {
4827
        elt = next_cx.build.GEP(body, [ix_val]);
4828
        // We're crossing a box boundary here, so we may need to pointer cast.
4829

4830
        auto llunitty = type_of(next_cx.fcx.lcx.ccx, sp, unit_ty);
4831
        elt = next_cx.build.PointerCast(elt, T_ptr(llunitty));
4832
    }
4833
    ret lval_mem(next_cx, elt);
4834 4835
}

4836

4837 4838 4839
// 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).
4840
fn trans_lval(&@block_ctxt cx, &@ast::expr e) -> lval_result {
4841
    alt (e.node) {
4842
        case (ast::expr_path(?p, ?ann)) { ret trans_path(cx, p, ann); }
4843
        case (ast::expr_field(?base, ?ident, ?ann)) {
4844
            auto r = trans_expr(cx, base);
4845
            auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, base);
4846
            ret trans_field(r.bcx, e.span, r.val, t, ident, ann);
4847
        }
4848
        case (ast::expr_index(?base, ?idx, ?ann)) {
4849 4850
            ret trans_index(cx, e.span, base, idx, ann);
        }
4851 4852
        case (ast::expr_unary(?unop, ?base, ?ann)) {
            assert (unop == ast::deref);
4853
            auto sub = trans_expr(cx, base);
4854 4855 4856
            auto val =
                sub.bcx.build.GEP(sub.val,
                                  [C_int(0), C_int(abi::box_rc_field_body)]);
4857 4858
            ret lval_mem(sub.bcx, val);
        }
4859
        case (ast::expr_self_method(?ident, ?ann)) {
4860
            alt ({ cx.fcx.llself }) {
L
Lindsey Kuper 已提交
4861
                case (some(?pair)) {
4862 4863
                    auto r = pair.v;
                    auto t = pair.t;
4864 4865 4866 4867 4868
                    ret trans_field(cx, e.span, r, t, ident, ann);
                }
                case (_) {
                    // Shouldn't happen.

4869 4870 4871
                    cx.fcx.lcx.ccx.sess.bug("trans_lval called on " +
                                                "expr_self_method in " +
                                                "a context without llself");
4872
                }
4873 4874
            }
        }
4875
        case (_) {
4876 4877 4878 4879 4880
            ret rec(res=trans_expr(cx, e),
                    is_mem=false,
                    generic=none,
                    llobj=none,
                    method_ty=none);
4881
        }
G
Graydon Hoare 已提交
4882 4883 4884
    }
}

G
Graydon Hoare 已提交
4885
fn int_cast(&@block_ctxt bcx, TypeRef lldsttype, TypeRef llsrctype,
4886
            ValueRef llsrc, bool signed) -> ValueRef {
4887 4888
    if (llvm::LLVMGetIntTypeWidth(lldsttype) >
            llvm::LLVMGetIntTypeWidth(llsrctype)) {
4889 4890
        if (signed) {
            // Widening signed cast.
4891

4892 4893 4894
            ret bcx.build.SExtOrBitCast(llsrc, lldsttype);
        }
        // Widening unsigned cast.
4895

4896 4897 4898 4899 4900
        ret bcx.build.ZExtOrBitCast(llsrc, lldsttype);
    }
    ret bcx.build.TruncOrBitCast(llsrc, lldsttype);
}

4901
fn trans_cast(&@block_ctxt cx, &@ast::expr e, &ast::ann ann) -> result {
4902 4903
    auto e_res = trans_expr(cx, e);
    auto llsrctype = val_ty(e_res.val);
4904
    auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
4905
    auto lldsttype = type_of(cx.fcx.lcx.ccx, e.span, t);
4906
    if (!ty::type_is_fp(cx.fcx.lcx.ccx.tcx, t)) {
4907

4908
        // TODO: native-to-native casts
4909
        if (ty::type_is_native(cx.fcx.lcx.ccx.tcx,
4910 4911 4912 4913
                               ty::expr_ty(cx.fcx.lcx.ccx.tcx, e))) {
            e_res =
                res(e_res.bcx,
                    e_res.bcx.build.PtrToInt(e_res.val, lldsttype));
4914
        } else if (ty::type_is_native(cx.fcx.lcx.ccx.tcx, t)) {
4915 4916 4917
            e_res =
                res(e_res.bcx,
                    e_res.bcx.build.IntToPtr(e_res.val, lldsttype));
4918
        } else {
4919 4920 4921 4922
            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)));
4923
        }
4924
    } else { cx.fcx.lcx.ccx.sess.unimpl("fp cast"); }
4925 4926 4927
    ret e_res;
}

4928 4929 4930
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,
4931
                    uint ty_param_count) -> ValueRef {
4932
    // Construct a thunk-call with signature incoming_fty, and that copies
4933
    // args forward into a call to outgoing_fty:
4934

4935 4936 4937 4938 4939 4940
    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);
4941
    auto fcx = new_fn_ctxt(cx, sp, llthunk);
4942
    auto bcx = new_top_block_ctxt(fcx);
4943
    auto lltop = bcx.llbb;
4944
    auto llclosure_ptr_ty =
4945
        type_of(cx.ccx, sp, ty::mk_imm_box(cx.ccx.tcx, closure_ty));
4946
    auto llclosure = bcx.build.PointerCast(fcx.llenv, llclosure_ptr_ty);
4947 4948 4949
    auto lltarget =
        GEP_tup_like(bcx, closure_ty, llclosure,
                     [0, abi::box_rc_field_body, abi::closure_elt_target]);
4950
    bcx = lltarget.bcx;
4951 4952
    auto lltargetclosure =
        bcx.build.GEP(lltarget.val, [C_int(0), C_int(abi::fn_field_box)]);
4953
    lltargetclosure = bcx.build.Load(lltargetclosure);
4954 4955
    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);
4956
    auto llretptr = fcx.llretptr;
4957
    if (ty::type_has_dynamic_size(cx.ccx.tcx, outgoing_ret_ty)) {
4958
        llretptr = bcx.build.PointerCast(llretptr, T_typaram_ptr(cx.ccx.tn));
4959
    }
4960
    let vec[ValueRef] llargs = [llretptr, fcx.lltaskptr, lltargetclosure];
4961
    // Copy in the type parameters.
4962

4963 4964 4965
    let uint i = 0u;
    while (i < ty_param_count) {
        auto lltyparam_ptr =
4966
            GEP_tup_like(bcx, closure_ty, llclosure,
4967 4968
                         [0, abi::box_rc_field_body,
                          abi::closure_elt_ty_params, i as int]);
4969
        bcx = lltyparam_ptr.bcx;
4970
        auto td = bcx.build.Load(lltyparam_ptr.val);
4971 4972
        llargs += [td];
        fcx.lltydescs += [td];
4973 4974
        i += 1u;
    }
4975
    let uint a = 3u; // retptr, task ptr, env come first
4976

4977
    let int b = 0;
4978
    let uint outgoing_arg_index = 0u;
4979
    let vec[TypeRef] llout_arg_tys =
4980
        type_of_explicit_args(cx.ccx, sp, outgoing_args);
4981
    for (option::t[@ast::expr] arg in args) {
4982 4983
        auto out_arg = outgoing_args.(outgoing_arg_index);
        auto llout_arg_ty = llout_arg_tys.(outgoing_arg_index);
4984
        alt (arg) {
4985 4986 4987 4988
            case (
                 // Arg provided at binding time; thunk copies it from
                 // closure.
                 some(?e)) {
4989
                auto e_ty = ty::expr_ty(cx.ccx.tcx, e);
4990 4991
                auto bound_arg =
                    GEP_tup_like(bcx, closure_ty, llclosure,
4992 4993
                                 [0, abi::box_rc_field_body,
                                  abi::closure_elt_bindings, b]);
4994
                bcx = bound_arg.bcx;
4995
                auto val = bound_arg.val;
4996
                if (out_arg.mode == ty::mo_val) {
4997 4998 4999 5000 5001 5002 5003
                    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);
                    }
5004
                } else if (ty::type_contains_params(cx.ccx.tcx, out_arg.ty)) {
5005
                    assert (out_arg.mode != ty::mo_val);
5006 5007
                    val = bcx.build.PointerCast(val, llout_arg_ty);
                }
5008
                llargs += [val];
5009 5010
                b += 1;
            }
5011 5012 5013
            case (
                 // Arg will be provided when the thunk is invoked.
                 none) {
5014 5015
                let ValueRef passed_arg = llvm::LLVMGetParam(llthunk, a);
                if (ty::type_contains_params(cx.ccx.tcx, out_arg.ty)) {
5016
                    assert (out_arg.mode != ty::mo_val);
5017 5018
                    passed_arg =
                        bcx.build.PointerCast(passed_arg, llout_arg_ty);
5019
                }
5020
                llargs += [passed_arg];
5021 5022 5023
                a += 1u;
            }
        }
5024
        outgoing_arg_index += 1u;
5025 5026
    }
    // FIXME: turn this call + ret into a tail call.
5027

5028 5029
    auto lltargetfn =
        bcx.build.GEP(lltarget.val, [C_int(0), C_int(abi::fn_field_code)]);
5030 5031 5032
    // Cast the outgoing function to the appropriate type (see the comments in
    // trans_bind below for why this is necessary).

5033 5034 5035 5036 5037
    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)));
5038 5039
    lltargetfn = bcx.build.Load(lltargetfn);
    auto r = bcx.build.FastCall(lltargetfn, llargs);
5040
    bcx.build.RetVoid();
5041
    finish_fn(fcx, lltop);
5042 5043 5044
    ret llthunk;
}

5045
fn trans_bind(&@block_ctxt cx, &@ast::expr f,
5046
              &vec[option::t[@ast::expr]] args, &ast::ann ann) -> result {
5047 5048
    auto f_res = trans_lval(cx, f);
    if (f_res.is_mem) {
5049
        cx.fcx.lcx.ccx.sess.unimpl("re-binding existing function");
5050
    } else {
5051
        let vec[@ast::expr] bound = [];
5052
        for (option::t[@ast::expr] argopt in args) {
5053
            alt (argopt) {
5054 5055
                case (none) { }
                case (some(?e)) { vec::push[@ast::expr](bound, e); }
5056 5057
            }
        }
5058
        // Figure out which tydescs we need to pass, if any.
5059

5060
        let ty::t outgoing_fty;
B
Brian Anderson 已提交
5061
        let vec[ValueRef] lltydescs;
5062
        alt (f_res.generic) {
5063
            case (none) {
5064
                outgoing_fty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, f);
5065
                lltydescs = [];
5066
            }
5067
            case (some(?ginfo)) {
5068
                lazily_emit_all_generic_info_tydesc_glues(cx, ginfo);
5069 5070 5071 5072
                outgoing_fty = ginfo.item_type;
                lltydescs = ginfo.tydescs;
            }
        }
5073 5074
        auto ty_param_count = vec::len[ValueRef](lltydescs);
        if (vec::len[@ast::expr](bound) == 0u && ty_param_count == 0u) {
5075
            // Trivial 'binding': just return the static pair-ptr.
5076

5077 5078 5079
            ret f_res.res;
        } else {
            auto bcx = f_res.res.bcx;
5080
            auto pair_t = node_type(cx.fcx.lcx.ccx, cx.sp, ann);
5081
            auto pair_v = alloca(bcx, pair_t);
5082
            // Translate the bound expressions.
5083

5084 5085
            let vec[ty::t] bound_tys = [];
            let vec[ValueRef] bound_vals = [];
5086
            auto i = 0u;
5087
            for (@ast::expr e in bound) {
5088 5089
                auto arg = trans_expr(bcx, e);
                bcx = arg.bcx;
5090 5091
                vec::push[ValueRef](bound_vals, arg.val);
                vec::push[ty::t](bound_tys,
5092
                                 ty::expr_ty(cx.fcx.lcx.ccx.tcx, e));
5093
                i += 1u;
5094 5095
            }
            // Synthesize a closure type.
5096

5097 5098
            let ty::t bindings_ty =
                ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, bound_tys);
5099
            // NB: keep this in sync with T_closure_ptr; we're making
5100
            // a ty::t structure that has the same "shape" as the LLVM type
5101 5102
            // it constructs.

5103
            let ty::t tydesc_ty = ty::mk_type(cx.fcx.lcx.ccx.tcx);
5104
            let vec[ty::t] captured_tys =
5105
                vec::init_elt[ty::t](tydesc_ty, ty_param_count);
5106
            let vec[ty::t] closure_tys =
5107 5108 5109 5110
                [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);
5111
            auto r = trans_malloc_boxed(bcx, closure_ty);
5112 5113
            auto box = r.val;
            bcx = r.bcx;
5114
            auto rc =
5115
                bcx.build.GEP(box,
5116 5117 5118
                              [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)]);
5119 5120
            bcx.build.Store(C_int(1), rc);
            // Store bindings tydesc.
5121

5122 5123
            auto bound_tydesc =
                bcx.build.GEP(closure,
5124
                              [C_int(0), C_int(abi::closure_elt_tydesc)]);
5125 5126 5127
            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);
5128
            lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
5129 5130
            bcx = bindings_tydesc.bcx;
            bcx.build.Store(bindings_tydesc.val, bound_tydesc);
5131 5132 5133 5134 5135 5136 5137
            // 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.

5138 5139 5140 5141 5142 5143 5144
            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));
5145
            // Store thunk-target.
5146

5147
            auto bound_target =
5148
                bcx.build.GEP(closure,
5149
                              [C_int(0), C_int(abi::closure_elt_target)]);
5150
            auto src = bcx.build.Load(f_res.res.val);
5151
            bound_target = bcx.build.PointerCast(bound_target, llclosurety);
5152
            bcx.build.Store(src, bound_target);
5153
            // Copy expr values into boxed bindings.
5154

5155
            i = 0u;
5156 5157
            auto bindings =
                bcx.build.GEP(closure,
5158
                              [C_int(0), C_int(abi::closure_elt_bindings)]);
5159
            for (ValueRef v in bound_vals) {
5160 5161
                auto bound =
                    bcx.build.GEP(bindings, [C_int(0), C_int(i as int)]);
5162
                bcx = copy_val(bcx, INIT, bound, v, bound_tys.(i)).bcx;
5163 5164 5165 5166
                i += 1u;
            }
            // If necessary, copy tydescs describing type parameters into the
            // appropriate slot in the closure.
5167

5168
            alt (f_res.generic) {
5169
                case (none) {/* nothing to do */ }
5170
                case (some(?ginfo)) {
5171
                    lazily_emit_all_generic_info_tydesc_glues(cx, ginfo);
5172 5173
                    auto ty_params_slot =
                        bcx.build.GEP(closure,
5174
                                      [C_int(0),
5175
                                       C_int(abi::closure_elt_ty_params)]);
5176 5177
                    auto i = 0;
                    for (ValueRef td in ginfo.tydescs) {
5178 5179 5180
                        auto ty_param_slot =
                            bcx.build.GEP(ty_params_slot,
                                          [C_int(0), C_int(i)]);
5181 5182 5183
                        bcx.build.Store(td, ty_param_slot);
                        i += 1;
                    }
5184
                    outgoing_fty = ginfo.item_type;
5185
                }
5186
            }
5187
            // Make thunk and store thunk-ptr in outer pair's code slot.
5188

5189 5190
            auto pair_code =
                bcx.build.GEP(pair_v, [C_int(0), C_int(abi::fn_field_code)]);
5191
            let ty::t pair_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
5192
            let ValueRef llthunk =
5193
                trans_bind_thunk(cx.fcx.lcx, cx.sp, pair_ty, outgoing_fty,
5194
                                 args, closure_ty, bound_tys, ty_param_count);
5195 5196
            bcx.build.Store(llthunk, pair_code);
            // Store box ptr in outer pair's box slot.
5197

5198 5199 5200 5201 5202 5203
            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);
5204
            find_scope_cx(cx).cleanups +=
5205
                [clean(bind drop_slot(_, pair_v, pair_ty))];
5206 5207
            ret res(bcx, pair_v);
        }
5208 5209 5210
    }
}

5211
fn trans_arg_expr(&@block_ctxt cx, &ty::arg arg, TypeRef lldestty0,
5212
                  &@ast::expr e) -> result {
5213 5214
    auto val;
    auto bcx = cx;
5215
    auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
5216
    if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, e_ty)) {
5217 5218 5219
        auto re = trans_expr(bcx, e);
        val = re.val;
        bcx = re.bcx;
5220
    } else if (arg.mode != ty::mo_val) {
5221
        let lval_result lv;
5222
        if (ty::is_lval(e)) {
5223 5224 5225 5226 5227
            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);
5228
            } else { lv = lval_mem(r.bcx, r.val); }
5229 5230 5231 5232 5233 5234 5235
        }
        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.
5236

5237 5238
            val = do_spill(lv.res.bcx, lv.res.val);
        }
5239 5240
    } 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; }
5241 5242 5243 5244 5245
    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).
5246

5247
        val = llvm::LLVMGetUndef(lldestty0);
5248
    } else if (ty::type_contains_params(cx.fcx.lcx.ccx.tcx, arg.ty)) {
5249
        auto lldestty = lldestty0;
5250 5251 5252
        if (arg.mode == ty::mo_val
            && ty::type_is_structural(cx.fcx.lcx.ccx.tcx, e_ty)) {
            lldestty = T_ptr(lldestty);
5253 5254 5255
        }
        val = bcx.build.PointerCast(val, lldestty);
    }
5256 5257 5258 5259 5260
    if (arg.mode == ty::mo_val
        && ty::type_is_structural(cx.fcx.lcx.ccx.tcx, e_ty)) {
        // Until here we've been treating structures by pointer;
        // we are now passing it as an arg, so need to load it.
        val = bcx.build.Load(val);
5261 5262 5263 5264
    }
    ret res(bcx, val);
}

5265

5266 5267 5268 5269 5270 5271
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args
5272 5273 5274 5275
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) {
5276
    let vec[ty::arg] args = ty::ty_fn_args(cx.fcx.lcx.ccx.tcx, fn_ty);
5277 5278
    let vec[ValueRef] llargs = [];
    let vec[ValueRef] lltydescs = [];
5279 5280
    let @block_ctxt bcx = cx;
    // Arg 0: Output pointer.
5281

5282
    auto retty = ty::ty_fn_ret(cx.fcx.lcx.ccx.tcx, fn_ty);
5283 5284 5285
    auto llretslot_res = alloc_ty(bcx, retty);
    bcx = llretslot_res.bcx;
    auto llretslot = llretslot_res.val;
5286
    alt (gen) {
5287
        case (some(?g)) {
5288
            lazily_emit_all_generic_info_tydesc_glues(cx, g);
5289
            lltydescs = g.tydescs;
5290 5291
            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);
5292
        }
5293
        case (_) { }
5294
    }
5295
    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, retty)) {
5296 5297 5298
        llargs +=
            [bcx.build.PointerCast(llretslot,
                                   T_typaram_ptr(cx.fcx.lcx.ccx.tn))];
5299
    } else if (ty::type_contains_params(cx.fcx.lcx.ccx.tcx, retty)) {
5300 5301 5302 5303 5304
        // 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.
5305

5306
        llargs +=
5307
            [cx.build.PointerCast(llretslot,
5308 5309 5310
                                  T_ptr(type_of(bcx.fcx.lcx.ccx, bcx.sp,
                                                retty)))];
    } else { llargs += [llretslot]; }
5311
    // Arg 1: task pointer.
5312

5313
    llargs += [bcx.fcx.lltaskptr];
5314
    // Arg 2: Env (closure-bindings / self-obj)
5315

5316
    alt (llobj) {
5317
        case (some(?ob)) {
5318 5319 5320
            // Every object is always found in memory,
            // and not-yet-loaded (as part of an lval x.y
            // doted method-call).
5321

5322
            llargs += [bcx.build.Load(ob)];
5323
        }
5324
        case (_) { llargs += [llenv]; }
5325 5326 5327
    }
    // Args >3: ty_params ...

5328
    llargs += lltydescs;
5329
    // ... then possibly an lliterbody argument.
5330

5331
    alt (lliterbody) {
5332 5333
        case (none) { }
        case (some(?lli)) { llargs += [lli]; }
5334
    }
5335
    // ... then explicit args.
5336 5337 5338 5339 5340

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

5341
    auto arg_tys = type_of_explicit_args(cx.fcx.lcx.ccx, cx.sp, args);
5342
    auto i = 0u;
5343
    for (@ast::expr e in es) {
5344 5345
        auto r = trans_arg_expr(bcx, args.(i), arg_tys.(i), e);
        bcx = r.bcx;
5346
        llargs += [r.val];
5347 5348 5349 5350 5351
        i += 1u;
    }
    ret tup(bcx, llargs, llretslot);
}

5352 5353
fn trans_call(&@block_ctxt cx, &@ast::expr f, &option::t[ValueRef] lliterbody,
              &vec[@ast::expr] args, &ast::ann ann) -> result {
5354 5355 5356 5357
    // 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.

5358
    auto f_res = trans_lval(cx, f);
5359
    auto faddr = f_res.res.val;
5360
    auto llenv = C_null(T_opaque_closure_ptr(cx.fcx.lcx.ccx.tn));
5361
    alt (f_res.llobj) {
5362
        case (some(_)) {
5363
            // It's a vtbl entry.
5364

5365 5366
            faddr = f_res.res.bcx.build.Load(faddr);
        }
5367
        case (none) {
5368
            // It's a closure.
5369

5370
            auto bcx = f_res.res.bcx;
5371
            auto pair = faddr;
5372 5373
            faddr =
                bcx.build.GEP(pair, [C_int(0), C_int(abi::fn_field_code)]);
5374
            faddr = bcx.build.Load(faddr);
5375 5376
            auto llclosure =
                bcx.build.GEP(pair, [C_int(0), C_int(abi::fn_field_box)]);
5377
            llenv = bcx.build.Load(llclosure);
5378
        }
5379
    }
5380
    let ty::t fn_ty;
5381
    alt (f_res.method_ty) {
5382
        case (some(?meth)) {
5383
            // self-call
5384

5385
            fn_ty = meth;
5386
        }
5387
        case (_) { fn_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, f); }
5388
    }
5389
    auto ret_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann);
5390 5391 5392
    auto args_res =
        trans_args(f_res.res.bcx, llenv, f_res.llobj, f_res.generic,
                   lliterbody, args, fn_ty);
5393 5394 5395 5396
    auto bcx = args_res._0;
    auto llargs = args_res._1;
    auto llretslot = args_res._2;
    /*
5397
    log "calling: " + val_str(cx.fcx.lcx.ccx.tn, faddr);
5398
    
5399
    for (ValueRef arg in llargs) {
5400
        log "arg: " + val_str(cx.fcx.lcx.ccx.tn, arg);
5401
    }
5402 5403 5404 5405
    */

    bcx.build.FastCall(faddr, llargs);
    auto retval = C_nil();
5406
    alt (lliterbody) {
5407
        case (none) {
5408
            if (!ty::type_is_nil(cx.fcx.lcx.ccx.tcx, ret_ty)) {
5409 5410 5411 5412
                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.
5413

5414
                find_scope_cx(cx).cleanups +=
5415
                    [clean(bind drop_ty(_, retval, ret_ty))];
5416 5417
            }
        }
5418
        case (some(_)) {
5419 5420 5421
            // 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.
5422

5423
        }
5424 5425 5426 5427
    }
    ret res(bcx, retval);
}

5428
fn trans_tup(&@block_ctxt cx, &vec[ast::elt] elts, &ast::ann ann) -> result {
5429
    auto bcx = cx;
5430
    auto t = node_ann_type(bcx.fcx.lcx.ccx, ann);
5431 5432 5433
    auto tup_res = alloc_ty(bcx, t);
    auto tup_val = tup_res.val;
    bcx = tup_res.bcx;
5434
    find_scope_cx(cx).cleanups += [clean(bind drop_ty(_, tup_val, t))];
G
Graydon Hoare 已提交
5435
    let int i = 0;
5436
    for (ast::elt e in elts) {
5437
        auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e.expr);
5438 5439
        auto src_res = trans_expr(bcx, e.expr);
        bcx = src_res.bcx;
5440
        auto dst_res = GEP_tup_like(bcx, t, tup_val, [0, i]);
5441
        bcx = dst_res.bcx;
5442
        bcx = copy_val(src_res.bcx, INIT, dst_res.val, src_res.val, e_ty).bcx;
G
Graydon Hoare 已提交
5443 5444
        i += 1;
    }
5445
    ret res(bcx, tup_val);
G
Graydon Hoare 已提交
5446 5447
}

5448 5449
fn trans_vec(&@block_ctxt cx, &vec[@ast::expr] args, &ast::ann ann) ->
   result {
5450
    auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
5451
    auto unit_ty = t;
5452
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
5453 5454
        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 已提交
5455
    }
5456 5457 5458
    auto bcx = cx;
    auto unit_sz = size_of(bcx, unit_ty);
    bcx = unit_sz.bcx;
5459 5460
    auto data_sz =
        bcx.build.Mul(C_int(vec::len[@ast::expr](args) as int), unit_sz.val);
G
Graydon Hoare 已提交
5461
    // FIXME: pass tydesc properly.
5462 5463 5464 5465 5466

    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)))]);
5467
    auto llty = type_of(bcx.fcx.lcx.ccx, bcx.sp, t);
5468
    vec_val = bcx.build.PointerCast(vec_val, llty);
5469 5470
    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)]);
5471
    auto pseudo_tup_ty =
5472
        ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx,
5473 5474
                       vec::init_elt[ty::t](unit_ty,
                                            vec::len[@ast::expr](args)));
G
Graydon Hoare 已提交
5475
    let int i = 0;
5476
    for (@ast::expr e in args) {
5477 5478
        auto src_res = trans_expr(bcx, e);
        bcx = src_res.bcx;
5479
        auto dst_res = GEP_tup_like(bcx, pseudo_tup_ty, body, [0, i]);
5480
        bcx = dst_res.bcx;
5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493
        // 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;
5494
        if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, unit_ty)) {
5495
            auto llunit_ty = type_of(cx.fcx.lcx.ccx, bcx.sp, unit_ty);
5496
            dst_val = bcx.build.PointerCast(dst_res.val, T_ptr(llunit_ty));
5497
        } else { dst_val = dst_res.val; }
5498
        bcx = copy_val(bcx, INIT, dst_val, src_res.val, unit_ty).bcx;
G
Graydon Hoare 已提交
5499 5500
        i += 1;
    }
5501
    auto fill = bcx.build.GEP(vec_val, [C_int(0), C_int(abi::vec_elt_fill)]);
5502 5503
    bcx.build.Store(data_sz, fill);
    ret res(bcx, vec_val);
G
Graydon Hoare 已提交
5504 5505
}

5506

5507
// TODO: Move me to ivec::
5508
fn trans_ivec(@block_ctxt bcx, &vec[@ast::expr] args, &ast::ann ann) ->
5509
   result {
5510 5511 5512 5513 5514 5515 5516
    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 llunitty = type_of_or_i8(bcx, unit_ty);
5517 5518 5519 5520 5521 5522 5523

    auto ares = ivec::alloc(bcx, unit_ty);
    bcx = ares.bcx;
    auto llvecptr = ares.llptr;
    auto unit_sz = ares.llunitsz;
    auto llalen = ares.llalen;

5524 5525
    find_scope_cx(bcx).cleanups += [clean(bind drop_ty(_, llvecptr, typ))];

5526 5527
    auto lllen = bcx.build.Mul(C_uint(vec::len(args)), unit_sz);
    // Allocate the vector pieces and store length and allocated length.
5528

5529
    auto llfirsteltptr;
5530
    if (vec::len(args) > 0u && vec::len(args) <= abi::ivec_default_length) {
5531
        // Interior case.
5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544

        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)]);
5545 5546
    } else {
        // Heap case.
5547 5548 5549 5550

        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)];
5551 5552
        auto llstubty = T_ivec_heap(llunitty);
        auto llstubptr = bcx.build.PointerCast(llvecptr, T_ptr(llstubty));
5553
        bcx.build.Store(C_int(0), bcx.build.InBoundsGEP(llstubptr, stub_z));
5554
        auto llheapty = T_ivec_heap_part(llunitty);
5555 5556
        if (vec::len(args) == 0u) {
            // Null heap pointer indicates a zero-length vector.
5557

5558
            bcx.build.Store(llalen, bcx.build.InBoundsGEP(llstubptr, stub_a));
5559
            bcx.build.Store(C_null(T_ptr(llheapty)),
5560
                            bcx.build.InBoundsGEP(llstubptr, stub_p));
5561 5562
            llfirsteltptr = C_null(T_ptr(llunitty));
        } else {
5563 5564
            bcx.build.Store(lllen, bcx.build.InBoundsGEP(llstubptr, stub_a));

5565
            auto llheapsz = bcx.build.Add(llsize_of(llheapty), lllen);
5566
            auto rslt = trans_raw_malloc(bcx, T_ptr(llheapty), llheapsz);
5567 5568
            bcx = rslt.bcx;
            auto llheapptr = rslt.val;
5569 5570
            bcx.build.Store(llheapptr,
                            bcx.build.InBoundsGEP(llstubptr, stub_p));
5571
            auto heap_l = [C_int(0), C_uint(abi::ivec_heap_elt_len)];
5572
            bcx.build.Store(lllen, bcx.build.InBoundsGEP(llheapptr, heap_l));
5573 5574 5575 5576 5577
            llfirsteltptr =
                bcx.build.InBoundsGEP(llheapptr,
                                      [C_int(0),
                                       C_uint(abi::ivec_heap_elt_elems),
                                       C_int(0)]);
5578 5579 5580
        }
    }
    // Store the individual elements.
5581

5582 5583
    auto i = 0u;
    for (@ast::expr e in args) {
5584
        auto rslt = trans_expr(bcx, e);
5585 5586 5587 5588
        bcx = rslt.bcx;
        auto llsrc = rslt.val;
        auto lleltptr;
        if (ty::type_has_dynamic_size(bcx.fcx.lcx.ccx.tcx, unit_ty)) {
5589 5590 5591
            lleltptr =
                bcx.build.InBoundsGEP(llfirsteltptr,
                                      [bcx.build.Mul(C_uint(i), unit_sz)]);
5592
        } else {
5593
            lleltptr = bcx.build.InBoundsGEP(llfirsteltptr, [C_uint(i)]);
5594 5595 5596 5597 5598 5599 5600
        }
        bcx = copy_val(bcx, INIT, lleltptr, llsrc, unit_ty).bcx;
        i += 1u;
    }
    ret res(bcx, llvecptr);
}

5601 5602
fn trans_rec(&@block_ctxt cx, &vec[ast::field] fields,
             &option::t[@ast::expr] base, &ast::ann ann) -> result {
5603
    auto bcx = cx;
5604
    auto t = node_ann_type(bcx.fcx.lcx.ccx, ann);
5605 5606 5607
    auto rec_res = alloc_ty(bcx, t);
    auto rec_val = rec_res.val;
    bcx = rec_res.bcx;
5608
    find_scope_cx(cx).cleanups += [clean(bind drop_ty(_, rec_val, t))];
5609
    let int i = 0;
G
Graydon Hoare 已提交
5610 5611
    auto base_val = C_nil();
    alt (base) {
5612 5613
        case (none) { }
        case (some(?bexp)) {
G
Graydon Hoare 已提交
5614 5615 5616 5617 5618
            auto base_res = trans_expr(bcx, bexp);
            bcx = base_res.bcx;
            base_val = base_res.val;
        }
    }
5619
    let vec[ty::field] ty_fields = [];
5620 5621
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
        case (ty::ty_rec(?flds)) { ty_fields = flds; }
G
Graydon Hoare 已提交
5622
    }
5623
    for (ty::field tf in ty_fields) {
5624
        auto e_ty = tf.mt.ty;
5625
        auto dst_res = GEP_tup_like(bcx, t, rec_val, [0, i]);
5626
        bcx = dst_res.bcx;
G
Graydon Hoare 已提交
5627 5628
        auto expr_provided = false;
        auto src_res = res(bcx, C_nil());
5629
        for (ast::field f in fields) {
5630
            if (str::eq(f.node.ident, tf.ident)) {
G
Graydon Hoare 已提交
5631
                expr_provided = true;
5632
                src_res = trans_expr(bcx, f.node.expr);
G
Graydon Hoare 已提交
5633 5634 5635
            }
        }
        if (!expr_provided) {
5636
            src_res = GEP_tup_like(bcx, t, base_val, [0, i]);
5637 5638
            src_res =
                res(src_res.bcx, load_if_immediate(bcx, src_res.val, e_ty));
G
Graydon Hoare 已提交
5639 5640
        }
        bcx = src_res.bcx;
5641
        bcx = copy_val(bcx, INIT, dst_res.val, src_res.val, e_ty).bcx;
5642 5643
        i += 1;
    }
5644
    ret res(bcx, rec_val);
5645 5646
}

5647
fn trans_expr(&@block_ctxt cx, &@ast::expr e) -> result {
5648
    ret trans_expr_out(cx, e, return);
5649 5650
}

5651 5652
fn trans_expr_out(&@block_ctxt cx, &@ast::expr e, out_method output) ->
   result {
5653
    // FIXME Fill in cx.sp
5654

5655
    alt (e.node) {
5656
        case (ast::expr_lit(?lit, ?ann)) {
5657
            ret res(cx, trans_lit(cx.fcx.lcx.ccx, *lit, ann));
5658
        }
5659
        case (ast::expr_unary(?op, ?x, ?ann)) {
5660
            if (op != ast::deref) { ret trans_unary(cx, op, x, ann); }
5661
        }
5662
        case (ast::expr_binary(?op, ?x, ?y, _)) {
5663
            ret trans_binary(cx, op, x, y);
5664
        }
5665
        case (ast::expr_if(?cond, ?thn, ?els, ?ann)) {
5666 5667
            ret with_out_method(bind trans_if(cx, cond, thn, els, ann, _), cx,
                                ann, output);
5668
        }
T
Tim Chevalier 已提交
5669 5670 5671 5672
        case (ast::expr_if_check(?cond, ?thn, ?els, ?ann)) {
            ret with_out_method(bind trans_if(cx, cond, thn, els, ann, _), cx,
                                ann, output);
        }
5673
        case (ast::expr_for(?decl, ?seq, ?body, _)) {
G
Graydon Hoare 已提交
5674 5675
            ret trans_for(cx, decl, seq, body);
        }
5676
        case (ast::expr_for_each(?decl, ?seq, ?body, _)) {
5677 5678
            ret trans_for_each(cx, decl, seq, body);
        }
5679
        case (ast::expr_while(?cond, ?body, _)) {
5680
            ret trans_while(cx, cond, body);
5681
        }
5682
        case (ast::expr_do_while(?body, ?cond, _)) {
5683
            ret trans_do_while(cx, body, cond);
5684
        }
5685
        case (ast::expr_alt(?expr, ?arms, ?ann)) {
5686 5687
            ret with_out_method(bind trans_alt(cx, expr, arms, ann, _), cx,
                                ann, output);
P
Patrick Walton 已提交
5688
        }
5689 5690
        case (ast::expr_fn(?f, ?ann)) {
            auto ccx = cx.fcx.lcx.ccx;
5691 5692 5693 5694 5695 5696 5697
            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)
                    }
                };
5698 5699 5700 5701 5702 5703
            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));
        }
5704
        case (ast::expr_block(?blk, ?ann)) {
5705 5706
            auto sub_cx = new_scope_block_ctxt(cx, "block-expr body");
            auto next_cx = new_sub_block_ctxt(cx, "next");
5707 5708 5709
            auto sub =
                with_out_method(bind trans_block(sub_cx, blk, _), cx, ann,
                                output);
5710 5711 5712
            cx.build.Br(sub_cx.llbb);
            sub.bcx.build.Br(next_cx.llbb);
            ret res(next_cx, sub.val);
5713
        }
5714
        case (ast::expr_move(?dst, ?src, _)) {
5715 5716
            auto lhs_res = trans_lval(cx, dst);
            assert (lhs_res.is_mem);
5717
            // FIXME Fill in lhs_res.res.bcx.sp
5718

M
Michael Sullivan 已提交
5719
            auto rhs_res = trans_lval(lhs_res.res.bcx, src);
5720
            auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, src);
5721
            // FIXME: calculate copy init-ness in typestate.
5722 5723 5724 5725

            auto move_res =
                move_val(rhs_res.res.bcx, DROP_EXISTING, lhs_res.res.val,
                         rhs_res.res.val, t);
5726
            ret res(move_res.bcx, C_nil());
5727
        }
5728
        case (ast::expr_assign(?dst, ?src, _)) {
5729
            auto lhs_res = trans_lval(cx, dst);
5730
            assert (lhs_res.is_mem);
5731
            // FIXME Fill in lhs_res.res.bcx.sp
5732

5733
            auto rhs_res = trans_expr(lhs_res.res.bcx, src);
5734
            auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, src);
G
Graydon Hoare 已提交
5735
            // FIXME: calculate copy init-ness in typestate.
5736 5737 5738 5739

            auto copy_res =
                copy_val(rhs_res.bcx, DROP_EXISTING, lhs_res.res.val,
                         rhs_res.val, t);
5740
            ret res(copy_res.bcx, C_nil());
5741
        }
M
Michael Sullivan 已提交
5742 5743 5744 5745 5746 5747 5748 5749 5750
        case (ast::expr_swap(?dst, ?src, _)) {
            auto lhs_res = trans_lval(cx, dst);
            assert (lhs_res.is_mem);
            // FIXME Fill in lhs_res.res.bcx.sp

            auto rhs_res = trans_lval(lhs_res.res.bcx, src);
            auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, src);
            auto tmp_res = alloc_ty(rhs_res.res.bcx, t);
            // Swap through a temporary.
5751 5752 5753 5754 5755 5756 5757 5758

            auto move1_res =
                memmove_ty(tmp_res.bcx, tmp_res.val, lhs_res.res.val, t);
            auto move2_res =
                memmove_ty(move1_res.bcx, lhs_res.res.val, rhs_res.res.val,
                           t);
            auto move3_res =
                memmove_ty(move2_res.bcx, rhs_res.res.val, tmp_res.val, t);
M
Michael Sullivan 已提交
5759 5760
            ret res(move3_res.bcx, C_nil());
        }
5761 5762
        case (ast::expr_assign_op(?op, ?dst, ?src, _)) {
            auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, src);
5763
            auto lhs_res = trans_lval(cx, dst);
5764
            assert (lhs_res.is_mem);
5765
            // FIXME Fill in lhs_res.res.bcx.sp
5766

5767
            auto rhs_res = trans_expr(lhs_res.res.bcx, src);
5768
            if (ty::type_is_sequence(cx.fcx.lcx.ccx.tcx, t)) {
5769
                alt (op) {
5770
                    case (ast::add) {
5771
                        if (ty::sequence_is_interior(cx.fcx.lcx.ccx.tcx, t)) {
5772 5773 5774
                            ret ivec::trans_append(rhs_res.bcx, t,
                                                   lhs_res.res.val,
                                                   rhs_res.val);
5775
                        }
5776
                        ret trans_vec_append(rhs_res.bcx, t, lhs_res.res.val,
5777 5778 5779 5780 5781
                                             rhs_res.val);
                    }
                    case (_) { }
                }
            }
5782 5783 5784
            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);
5785
            // FIXME: calculate copy init-ness in typestate.
5786 5787 5788

            auto copy_res =
                copy_val(v.bcx, DROP_EXISTING, lhs_res.res.val, v.val, t);
5789
            ret res(copy_res.bcx, C_nil());
5790
        }
5791
        case (ast::expr_bind(?f, ?args, ?ann)) {
5792 5793
            ret trans_bind(cx, f, args, ann);
        }
5794
        case (ast::expr_call(?f, ?args, ?ann)) {
5795
            ret trans_call(cx, f, none[ValueRef], args, ann);
5796
        }
5797
        case (ast::expr_cast(?e, _, ?ann)) { ret trans_cast(cx, e, ann); }
5798
        case (ast::expr_vec(?args, _, ast::sk_rc, ?ann)) {
G
Graydon Hoare 已提交
5799 5800
            ret trans_vec(cx, args, ann);
        }
5801 5802 5803
        case (ast::expr_vec(?args, _, ast::sk_unique, ?ann)) {
            ret trans_ivec(cx, args, ann);
        }
5804
        case (ast::expr_tup(?args, ?ann)) { ret trans_tup(cx, args, ann); }
5805
        case (ast::expr_rec(?args, ?base, ?ann)) {
5806
            ret trans_rec(cx, args, base, ann);
5807
        }
5808
        case (ast::expr_ext(_, _, _, ?expanded, _)) {
5809
            ret trans_expr(cx, expanded);
5810
        }
J
Josh Matthews 已提交
5811 5812 5813
        case (ast::expr_fail(_, ?str)) {
            auto failmsg;
            alt (str) {
5814 5815
                case (some(?msg)) { failmsg = msg; }
                case (_) { failmsg = "explicit failure"; }
J
Josh Matthews 已提交
5816 5817
            }
            ret trans_fail(cx, some(e.span), failmsg);
5818
        }
5819
        case (ast::expr_log(?lvl, ?a, _)) { ret trans_log(lvl, cx, a); }
5820
        case (ast::expr_assert(?a, _)) {
5821
            ret trans_check_expr(cx, a, "Assertion");
5822
        }
5823
        case (ast::expr_check(?a, _)) {
5824
            ret trans_check_expr(cx, a, "Predicate");
5825
        }
5826 5827 5828 5829 5830 5831 5832
        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); }
5833
        case (ast::expr_send(?lhs, ?rhs, ?ann)) {
B
Brian Anderson 已提交
5834 5835
            ret trans_send(cx, lhs, rhs, ann);
        }
5836
        case (ast::expr_recv(?lhs, ?rhs, ?ann)) {
B
Brian Anderson 已提交
5837 5838
            ret trans_recv(cx, lhs, rhs, ann);
        }
5839
        case (ast::expr_spawn(?dom, ?name, ?func, ?args, ?ann)) {
5840
            ret trans_spawn(cx, dom, name, func, args, ann);
5841
        }
L
Lindsey Kuper 已提交
5842
        case (ast::expr_anon_obj(?anon_obj, ?tps, ?odid, ?ann)) {
L
Lindsey Kuper 已提交
5843
            ret trans_anon_obj(cx, e.span, anon_obj, tps, odid.ctor, ann);
L
Lindsey Kuper 已提交
5844
        }
5845
        case (_) {
5846
            // The expression is an lvalue. Fall through.
T
Tim Chevalier 已提交
5847 5848
            assert (ty::is_lval(e)); // make sure it really is and that we 
                               // didn't forget to add a case for a new expr!
5849
        }
5850
    }
5851 5852 5853
    // lval cases fall through to trans_lval and then
    // possibly load the result (if it's non-structural).

5854
    auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
5855
    auto sub = trans_lval(cx, e);
5856
    ret res(sub.res.bcx, load_if_immediate(sub.res.bcx, sub.res.val, t));
5857 5858
}

5859
fn with_out_method(fn(&out_method) -> result  work, @block_ctxt cx,
5860 5861 5862 5863 5864 5865
                   &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);
5866
        if (ty::type_is_nil(ccx.tcx, tp)) { ret work(return); }
5867 5868
        auto res_alloca = alloc_ty(cx, tp);
        cx = zero_alloca(res_alloca.bcx, res_alloca.val, tp).bcx;
5869 5870
        fn drop_hoisted_ty(&@block_ctxt cx, ValueRef target, ty::t t) ->
           result {
5871 5872 5873 5874 5875 5876
            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 已提交
5877
        done = res(done.bcx, load_if_immediate(done.bcx, res_alloca.val, tp));
5878 5879 5880 5881
        ret done;
    }
}

5882

5883
// We pass structural values around the compiler "by pointer" and
5884 5885 5886 5887
// 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.
5888
fn type_is_immediate(&@crate_ctxt ccx, &ty::t t) -> bool {
5889 5890
    ret ty::type_is_scalar(ccx.tcx, t) || ty::type_is_boxed(ccx.tcx, t) ||
            ty::type_is_native(ccx.tcx, t);
5891 5892
}

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

5896 5897 5898 5899
    auto llptr = alloca(cx, val_ty(v));
    cx.build.Store(v, llptr);
    ret llptr;
}
5900

5901
fn spill_if_immediate(&@block_ctxt cx, ValueRef v, &ty::t t) -> ValueRef {
5902
    if (type_is_immediate(cx.fcx.lcx.ccx, t)) { ret do_spill(cx, v); }
5903 5904 5905
    ret v;
}

5906
fn load_if_immediate(&@block_ctxt cx, ValueRef v, &ty::t t) -> ValueRef {
5907
    if (type_is_immediate(cx.fcx.lcx.ccx, t)) { ret cx.build.Load(v); }
5908
    ret v;
5909 5910
}

5911
fn trans_log(int lvl, &@block_ctxt cx, &@ast::expr e) -> result {
5912
    auto lcx = cx.fcx.lcx;
5913
    auto modname = str::connect(lcx.module_path, "::");
5914 5915 5916 5917
    auto global;
    if (lcx.ccx.module_data.contains_key(modname)) {
        global = lcx.ccx.module_data.get(modname);
    } else {
5918 5919 5920 5921 5922
        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));
5923 5924
        llvm::LLVMSetGlobalConstant(global, False);
        llvm::LLVMSetInitializer(global, C_null(T_int()));
5925 5926
        llvm::LLVMSetLinkage(global,
                             lib::llvm::LLVMInternalLinkage as llvm::Linkage);
5927 5928
        lcx.ccx.module_data.insert(modname, global);
    }
5929
    auto log_cx = new_scope_block_ctxt(cx, "log");
5930 5931
    auto after_cx = new_sub_block_ctxt(cx, "after");
    auto load = cx.build.Load(global);
5932
    auto test = cx.build.ICmp(lib::llvm::LLVMIntSGE, load, C_int(lvl));
5933 5934
    cx.build.CondBr(test, log_cx.llbb, after_cx.llbb);
    auto sub = trans_expr(log_cx, e);
5935
    auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
5936
    auto log_bcx = sub.bcx;
5937
    if (ty::type_is_fp(cx.fcx.lcx.ccx.tcx, e_ty)) {
5938 5939
        let TypeRef tr;
        let bool is32bit = false;
5940 5941
        alt (ty::struct(cx.fcx.lcx.ccx.tcx, e_ty)) {
            case (ty::ty_machine(util::common::ty_f32)) {
5942 5943 5944
                tr = T_f32();
                is32bit = true;
            }
5945 5946
            case (ty::ty_machine(util::common::ty_f64)) { tr = T_f64(); }
            case (_) { tr = T_float(); }
5947 5948
        }
        if (is32bit) {
5949
            log_bcx.build.Call(log_bcx.fcx.lcx.ccx.upcalls.log_float,
5950
                               [log_bcx.fcx.lltaskptr, C_int(lvl), sub.val]);
5951
        } else {
5952
            // FIXME: Eliminate this level of indirection.
5953

5954
            auto tmp = alloca(log_bcx, tr);
5955
            sub.bcx.build.Store(sub.val, tmp);
5956
            log_bcx.build.Call(log_bcx.fcx.lcx.ccx.upcalls.log_double,
5957
                               [log_bcx.fcx.lltaskptr, C_int(lvl), tmp]);
5958
        }
5959
    } else if (ty::type_is_integral(cx.fcx.lcx.ccx.tcx, e_ty) ||
5960
                   ty::type_is_bool(cx.fcx.lcx.ccx.tcx, e_ty)) {
5961
        // FIXME: Handle signedness properly.
5962 5963 5964

        auto llintval =
            int_cast(log_bcx, T_int(), val_ty(sub.val), sub.val, false);
5965
        log_bcx.build.Call(log_bcx.fcx.lcx.ccx.upcalls.log_int,
5966
                           [log_bcx.fcx.lltaskptr, C_int(lvl), llintval]);
5967
    } else {
5968 5969
        alt (ty::struct(cx.fcx.lcx.ccx.tcx, e_ty)) {
            case (ty::ty_str) {
5970
                log_bcx.build.Call(log_bcx.fcx.lcx.ccx.upcalls.log_str,
5971
                                   [log_bcx.fcx.lltaskptr, C_int(lvl),
5972
                                    sub.val]);
5973 5974
            }
            case (_) {
5975
                // FIXME: Support these types.
5976

5977
                cx.fcx.lcx.ccx.sess.span_fatal(e.span,
5978 5979 5980 5981
                                             "log called on unsupported type "
                                                 +
                                                 ty_to_str(cx.fcx.lcx.ccx.tcx,
                                                           e_ty));
5982
            }
5983 5984
        }
    }
5985 5986
    log_bcx = trans_block_cleanups(log_bcx, log_cx);
    log_bcx.build.Br(after_cx.llbb);
5987
    ret res(after_cx, C_nil());
5988 5989
}

5990
fn trans_check_expr(&@block_ctxt cx, &@ast::expr e, &str s) -> result {
5991
    auto cond_res = trans_expr(cx, e);
5992
    auto expr_str = s + " " + expr_to_str(e) + " failed";
5993
    auto fail_cx = new_sub_block_ctxt(cx, "fail");
5994
    auto fail_res = trans_fail(fail_cx, some[common::span](e.span), expr_str);
5995
    auto next_cx = new_sub_block_ctxt(cx, "next");
5996
    cond_res.bcx.build.CondBr(cond_res.val, next_cx.llbb, fail_cx.llbb);
5997 5998 5999
    ret res(next_cx, C_nil());
}

6000
fn trans_fail(&@block_ctxt cx, &option::t[common::span] sp_opt, &str fail_str)
6001
   -> result {
6002
    auto V_fail_str = C_cstr(cx.fcx.lcx.ccx, fail_str);
6003 6004
    auto V_filename;
    auto V_line;
6005
    alt (sp_opt) {
6006
        case (some(?sp)) {
6007
            auto loc = cx.fcx.lcx.ccx.sess.lookup_pos(sp.lo);
6008
            V_filename = C_cstr(cx.fcx.lcx.ccx, loc.filename);
6009 6010
            V_line = loc.line as int;
        }
6011
        case (none) {
6012
            V_filename = C_cstr(cx.fcx.lcx.ccx, "<runtime>");
6013 6014 6015
            V_line = 0;
        }
    }
6016 6017
    V_fail_str = cx.build.PointerCast(V_fail_str, T_ptr(T_i8()));
    V_filename = cx.build.PointerCast(V_filename, T_ptr(T_i8()));
6018
    auto args = [cx.fcx.lltaskptr, V_fail_str, V_filename, C_int(V_line)];
6019 6020 6021
    cx.build.Call(cx.fcx.lcx.ccx.upcalls._fail, args);
    cx.build.Unreachable();
    ret res(cx, C_nil());
B
Brian Anderson 已提交
6022 6023
}

6024
fn trans_put(&@block_ctxt cx, &option::t[@ast::expr] e) -> result {
6025 6026
    auto llcallee = C_nil();
    auto llenv = C_nil();
6027
    alt ({ cx.fcx.lliterbody }) {
6028
        case (some(?lli)) {
6029
            auto slot = alloca(cx, val_ty(lli));
6030
            cx.build.Store(lli, slot);
6031 6032
            llcallee =
                cx.build.GEP(slot, [C_int(0), C_int(abi::fn_field_code)]);
6033
            llcallee = cx.build.Load(llcallee);
6034
            llenv = cx.build.GEP(slot, [C_int(0), C_int(abi::fn_field_box)]);
6035 6036 6037 6038
            llenv = cx.build.Load(llenv);
        }
    }
    auto bcx = cx;
6039
    auto dummy_retslot = alloca(bcx, T_nil());
6040
    let vec[ValueRef] llargs = [dummy_retslot, cx.fcx.lltaskptr, llenv];
6041
    alt (e) {
6042 6043
        case (none) { }
        case (some(?x)) {
6044
            auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, x);
6045
            auto arg = rec(mode=ty::mo_alias(false), ty=e_ty);
6046 6047
            auto arg_tys =
                type_of_explicit_args(cx.fcx.lcx.ccx, x.span, [arg]);
6048
            auto r = trans_arg_expr(bcx, arg, arg_tys.(0), x);
6049
            bcx = r.bcx;
6050
            llargs += [r.val];
6051 6052 6053
        }
    }
    ret res(bcx, bcx.build.FastCall(llcallee, llargs));
6054 6055
}

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

6060 6061 6062
    auto cleanup_cx = cx;
    while (true) {
        bcx = trans_block_cleanups(bcx, cleanup_cx);
6063
        alt ({ cleanup_cx.kind }) {
6064 6065 6066 6067 6068
            case (LOOP_SCOPE_BLOCK(?_cont, ?_break)) {
                if (to_end) {
                    bcx.build.Br(_break.llbb);
                } else {
                    alt (_cont) {
6069
                        case (option::some(?_cont)) {
6070 6071
                            bcx.build.Br(_cont.llbb);
                        }
6072
                        case (_) { bcx.build.Br(cleanup_cx.llbb); }
6073 6074
                    }
                }
6075 6076
                ret res(new_sub_block_ctxt(bcx, "break_cont.unreachable"),
                        C_nil());
6077 6078
            }
            case (_) {
6079
                alt ({ cleanup_cx.parent }) {
6080
                    case (parent_some(?cx)) { cleanup_cx = cx; }
6081
                    case (parent_none) {
6082
                        cx.fcx.lcx.ccx.sess.span_fatal(sp,
6083 6084 6085 6086
                                                     if (to_end) {
                                                         "Break"
                                                     } else { "Cont" } +
                                                         " outside a loop");
6087
                    }
6088 6089 6090 6091
                }
            }
        }
    }
6092
    // If we get here without returning, it's a bug
6093

6094
    cx.fcx.lcx.ccx.sess.bug("in trans::trans_break_cont()");
6095 6096
}

6097 6098
fn trans_break(&span sp, &@block_ctxt cx) -> result {
    ret trans_break_cont(sp, cx, true);
6099 6100
}

6101 6102
fn trans_cont(&span sp, &@block_ctxt cx) -> result {
    ret trans_break_cont(sp, cx, false);
6103 6104
}

6105
fn trans_ret(&@block_ctxt cx, &option::t[@ast::expr] e) -> result {
6106 6107
    auto bcx = cx;
    auto val = C_nil();
6108
    alt (e) {
6109
        case (some(?x)) {
6110
            auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, x);
6111 6112 6113
            auto r = trans_expr(cx, x);
            bcx = r.bcx;
            val = r.val;
6114
            bcx = copy_val(bcx, INIT, cx.fcx.llretptr, val, t).bcx;
6115
        }
6116
        case (_) {
6117 6118
            auto t = llvm::LLVMGetElementType(val_ty(cx.fcx.llretptr));
            auto null = lib::llvm::llvm::LLVMConstNull(t);
6119 6120
            bcx.build.Store(null, cx.fcx.llretptr);
        }
6121
    }
6122
    // run all cleanups and back out.
6123

6124
    let bool more_cleanups = true;
6125
    auto cleanup_cx = cx;
6126
    while (more_cleanups) {
6127
        bcx = trans_block_cleanups(bcx, cleanup_cx);
6128 6129 6130
        alt ({ cleanup_cx.parent }) {
            case (parent_some(?b)) { cleanup_cx = b; }
            case (parent_none) { more_cleanups = false; }
6131 6132
        }
    }
6133
    bcx.build.RetVoid();
6134
    ret res(new_sub_block_ctxt(bcx, "ret.unreachable"), C_nil());
6135 6136
}

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

6140
    assert (ast::is_call_expr(e));
6141 6142
    // FIXME: Turn this into a real tail call once
    // calling convention issues are settled
6143

6144 6145 6146
    ret trans_ret(cx, some(e));
}

6147
fn trans_port(&@block_ctxt cx, &ast::ann ann) -> result {
6148
    auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
B
Brian Anderson 已提交
6149
    auto unit_ty;
6150
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
6151 6152
        case (ty::ty_port(?t)) { unit_ty = t; }
        case (_) { cx.fcx.lcx.ccx.sess.bug("non-port type in trans_port"); }
B
Brian Anderson 已提交
6153
    }
6154
    auto llunit_ty = type_of(cx.fcx.lcx.ccx, cx.sp, unit_ty);
B
Brian Anderson 已提交
6155 6156 6157
    auto bcx = cx;
    auto unit_sz = size_of(bcx, unit_ty);
    bcx = unit_sz.bcx;
6158 6159 6160
    auto port_raw_val =
        bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.new_port,
                       [bcx.fcx.lltaskptr, unit_sz.val]);
6161
    auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, t);
6162
    auto port_val = bcx.build.PointerCast(port_raw_val, llty);
B
Brian Anderson 已提交
6163
    auto dropref = clean(bind drop_ty(_, port_val, t));
6164
    find_scope_cx(bcx).cleanups += [dropref];
B
Brian Anderson 已提交
6165 6166 6167
    ret res(bcx, port_val);
}

6168
fn trans_chan(&@block_ctxt cx, &@ast::expr e, &ast::ann ann) -> result {
B
Brian Anderson 已提交
6169 6170 6171
    auto bcx = cx;
    auto prt = trans_expr(bcx, e);
    bcx = prt.bcx;
6172
    auto prt_val = bcx.build.PointerCast(prt.val, T_opaque_port_ptr());
6173 6174 6175
    auto chan_raw_val =
        bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.new_chan,
                       [bcx.fcx.lltaskptr, prt_val]);
6176
    auto chan_ty = node_ann_type(bcx.fcx.lcx.ccx, ann);
6177
    auto chan_llty = type_of(bcx.fcx.lcx.ccx, e.span, chan_ty);
6178
    auto chan_val = bcx.build.PointerCast(chan_raw_val, chan_llty);
B
Brian Anderson 已提交
6179
    auto dropref = clean(bind drop_ty(_, chan_val, chan_ty));
6180
    find_scope_cx(bcx).cleanups += [dropref];
B
Brian Anderson 已提交
6181 6182 6183
    ret res(bcx, chan_val);
}

6184 6185 6186
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 {
6187
    auto bcx = cx;
6188 6189
    // Make the task name

6190 6191 6192 6193 6194 6195 6196 6197
    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 }
        };
6198
    // Generate code
6199 6200 6201 6202 6203 6204 6205 6206 6207
    //
    // 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)
    //
6208
    // 3. Fill the tuple with the arguments we evaluated.
6209
    // 
6210 6211 6212 6213 6214 6215
    // 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.
6216 6217
    //
    // 5. Oh yeah, we have to create the task before we start it...
6218

6219 6220 6221 6222 6223 6224 6225
    // But first, we'll create a task.

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

6226 6227
    // Translate the arguments, remembering their types and where the values
    // ended up.
6228

6229
    let vec[ty::t] arg_tys = [];
6230
    let vec[ValueRef] arg_vals = [];
6231
    for (@ast::expr e in args) {
6232
        auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
6233
        auto arg = trans_expr(bcx, e);
6234

6235
        arg = deep_copy(arg.bcx, arg.val, e_ty, new_task);
6236

6237
        bcx = arg.bcx;
6238

6239
        vec::push[ValueRef](arg_vals, arg.val);
6240
        vec::push[ty::t](arg_tys, e_ty);
6241
    }
6242
    // Make the tuple.
6243

6244 6245 6246
    auto args_ty = ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, arg_tys);
    // Allocate and fill the tuple.

6247
    auto llargs = alloc_ty(bcx, args_ty);
6248
    auto i = 0u;
6249
    for (ValueRef v in arg_vals) {
6250 6251
        // log_err #fmt("ty(llargs) = %s", 
        //              val_str(bcx.fcx.lcx.ccx.tn, llargs.val));
6252

6253 6254 6255 6256 6257 6258
        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);
6259
        i += 1u;
6260
    }
6261 6262

    // Generate the wrapper function
6263
    auto wrapper = mk_spawn_wrapper(bcx, func, args_ty);
6264 6265
    bcx = wrapper.bcx;
    auto llfnptr_i = bcx.build.PointerCast(wrapper.val, T_int());
6266

6267 6268
    // And start the task
    auto llargs_i = bcx.build.PointerCast(llargs.val, T_int());
6269
    auto args_size = size_of(bcx, args_ty).val;
6270
    bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.start_task,
6271 6272
                   [bcx.fcx.lltaskptr, new_task, llfnptr_i, llargs_i,
                    args_size]);
E
Eric Holk 已提交
6273 6274 6275
    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];
6276
    ret res(bcx, new_task);
6277 6278
}

6279 6280
fn mk_spawn_wrapper(&@block_ctxt cx, &@ast::expr func, &ty::t args_ty) ->
   result {
6281 6282 6283 6284
    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,
6285
                   [rec(mode=ty::mo_alias(false), ty=args_ty)], ty::idx_nil,
6286 6287
                   0u);
    // TODO: construct a name based on tname
6288

6289
    let str wrap_name =
6290
        mangle_internal_name_by_path_and_seq(cx.fcx.lcx.ccx, cx.fcx.lcx.path,
6291
                                             "spawn_wrapper");
6292
    auto llfndecl = decl_cdecl_fn(llmod, wrap_name, wrapper_fn_type);
6293 6294 6295 6296
    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

6297
    let ValueRef arg = llvm::LLVMGetParam(fcx.llfn, 3u);
6298
    let vec[ValueRef] child_args =
6299
        [llvm::LLVMGetParam(fcx.llfn, 0u), llvm::LLVMGetParam(fcx.llfn, 1u),
6300 6301
         llvm::LLVMGetParam(fcx.llfn, 2u)];
    // unpack the arguments
6302 6303 6304

    alt (ty::struct(fcx.lcx.ccx.tcx, args_ty)) {
        case (ty::ty_tup(?elements)) {
6305
            auto i = 0;
6306
            for (ty::mt m in elements) {
6307 6308 6309 6310 6311 6312 6313 6314
                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
6315

6316 6317
    auto fnptr = trans_lval(fbcx, func).res;
    fbcx = fnptr.bcx;
6318
    auto llfnptr = fbcx.build.GEP(fnptr.val, [C_int(0), C_int(0)]);
6319
    auto llfn = fbcx.build.Load(llfnptr);
6320
    fbcx.build.FastCall(llfn, child_args);
6321 6322 6323
    fbcx.build.RetVoid();
    finish_fn(fcx, fbcx.llbb);
    // TODO: make sure we clean up everything we need to.
6324

6325 6326 6327
    ret res(cx, llfndecl);
}

6328 6329 6330 6331
// Does a deep copy of a value. This is needed for passing arguments to child
// tasks, and for sending things through channels. There are probably some
// uniqueness optimizations and things we can do here for tasks in the same
// domain.
6332 6333 6334 6335 6336 6337 6338
fn deep_copy(&@block_ctxt bcx, ValueRef v, ty::t t, ValueRef target_task) 
    -> result 
{
    // TODO: make sure all paths add any reference counting that they need to.

    // TODO: Teach deep copy to understand everything else it needs to.

6339 6340 6341 6342
    auto tcx = bcx.fcx.lcx.ccx.tcx;
    if(ty::type_is_scalar(tcx, t)) {
        ret res(bcx, v);
    }
6343 6344 6345 6346
    else if(ty::type_is_chan(tcx, t)) {
        // If this is a channel, we need to clone it.
        /*
        log_err "Generating clone call for channel argument.";
6347
      
6348 6349 6350
        log_err #fmt("ty(clone_chan) = %s", 
                     val_str(bcx.fcx.lcx.ccx.tn,
                             bcx.fcx.lcx.ccx.upcalls.clone_chan));
6351
      
6352 6353 6354
        log_err #fmt("ty(lltaskptr) = %s", 
                     val_str(bcx.fcx.lcx.ccx.tn, 
                             bcx.fcx.lltaskptr));
6355
      
6356 6357 6358
        log_err #fmt("ty(target_task) = %s", 
                     val_str(bcx.fcx.lcx.ccx.tn, 
                             target_task));
6359
      
6360 6361 6362 6363 6364 6365
        log_err #fmt("ty(chan) = %s", 
                     val_str(bcx.fcx.lcx.ccx.tn, 
                             v));
        */

        auto chan_ptr = bcx.build.PointerCast(v, T_opaque_chan_ptr());
6366
      
6367 6368 6369 6370 6371 6372 6373 6374 6375 6376
        auto chan_raw_val = 
            bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.clone_chan,
                           [bcx.fcx.lltaskptr, target_task, chan_ptr]);

        // Cast back to the type the context was expecting.
        auto chan_val = bcx.build.PointerCast(chan_raw_val, 
                                              val_ty(v));

        ret res(bcx, chan_val);
    } 
6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393
    else if(ty::type_is_structural(tcx, t)) {
        fn inner_deep_copy(&@block_ctxt bcx, ValueRef v, ty::t t) -> result {
            auto tcx = bcx.fcx.lcx.ccx.tcx;
    
            log_err "Unimplemented type for deep_copy.";
            fail;
        }

        ret iter_structural_ty(bcx, v, t, inner_deep_copy);
    }
    else {
        bcx.fcx.lcx.ccx.sess.bug("unexpected type in " +
                                "trans::deep_copy: " +
                                ty_to_str(tcx, t));
    }
}

6394 6395
fn trans_send(&@block_ctxt cx, &@ast::expr lhs, &@ast::expr rhs,
              &ast::ann ann) -> result {
6396 6397 6398 6399 6400
    auto bcx = cx;
    auto chn = trans_expr(bcx, lhs);
    bcx = chn.bcx;
    auto data = trans_expr(bcx, rhs);
    bcx = data.bcx;
6401
    auto chan_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
6402
    auto unit_ty;
6403
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, chan_ty)) {
6404 6405
        case (ty::ty_chan(?t)) { unit_ty = t; }
        case (_) { bcx.fcx.lcx.ccx.sess.bug("non-chan type in trans_send"); }
6406
    }
6407 6408
    auto data_alloc = alloc_ty(bcx, unit_ty);
    bcx = data_alloc.bcx;
6409
    auto data_tmp = copy_val(bcx, INIT, data_alloc.val, data.val, unit_ty);
6410
    bcx = data_tmp.bcx;
6411
    find_scope_cx(bcx).cleanups +=
6412
        [clean(bind drop_ty(_, data_alloc.val, unit_ty))];
6413 6414 6415
    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,
6416
                   [bcx.fcx.lltaskptr, llchanval, lldataptr]);
6417
    ret res(bcx, chn.val);
B
Brian Anderson 已提交
6418 6419
}

6420 6421
fn trans_recv(&@block_ctxt cx, &@ast::expr lhs, &@ast::expr rhs,
              &ast::ann ann) -> result {
6422
    auto bcx = cx;
6423
    auto data = trans_lval(bcx, rhs);
6424
    assert (data.is_mem);
B
Brian Anderson 已提交
6425
    bcx = data.res.bcx;
6426
    auto unit_ty = node_ann_type(bcx.fcx.lcx.ccx, ann);
6427 6428
    // FIXME: calculate copy init-ness in typestate.

6429
    ret recv_val(bcx, data.res.val, lhs, unit_ty, DROP_EXISTING);
6430
}
6431

6432
fn recv_val(&@block_ctxt cx, ValueRef to, &@ast::expr from, &ty::t unit_ty,
6433
            copy_action action) -> result {
6434
    auto bcx = cx;
6435
    auto prt = trans_expr(bcx, from);
6436
    bcx = prt.bcx;
6437
    auto lldataptr = bcx.build.PointerCast(to, T_ptr(T_ptr(T_i8())));
6438 6439
    auto llportptr = bcx.build.PointerCast(prt.val, T_opaque_port_ptr());
    bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.recv,
6440
                   [bcx.fcx.lltaskptr, lldataptr, llportptr]);
6441 6442
    auto data_load = load_if_immediate(bcx, to, unit_ty);
    auto cp = copy_val(bcx, action, to, data_load, unit_ty);
6443
    bcx = cp.bcx;
6444
    // TODO: Any cleanup need to be done here?
6445

6446
    ret res(bcx, to);
B
Brian Anderson 已提交
6447 6448
}

L
Lindsey Kuper 已提交
6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480

/*

  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 已提交
6481

6482 6483 6484 6485 6486
// trans_anon_obj: create and return a pointer to an object.  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 and returning the object
// itself.
6487
fn trans_anon_obj(@block_ctxt bcx, &span sp, &ast::anon_obj anon_obj,
6488
                  &vec[ast::ty_param] ty_params, ast::def_id oid,
L
Lindsey Kuper 已提交
6489
                  &ast::ann ann) -> result {
6490 6491 6492 6493 6494 6495
    // Right now, we're assuming that anon objs don't take ty params, even
    // though the AST supports it.  It's nonsensical to write an expression
    // like "obj[T](){ ... with ... }", since T is never instantiated;
    // nevertheless, such an expression will parse.  FIXME for the future:
    // support typarams (issue #n).

6496
    assert (vec::len(ty_params) == 0u);
6497
    auto ccx = bcx.fcx.lcx.ccx;
L
Lindsey Kuper 已提交
6498 6499
    // If with_obj (the object being extended) exists, translate it, producing
    // a result.
6500

L
Lindsey Kuper 已提交
6501 6502
    let option::t[result] with_obj_val = none[result];
    alt (anon_obj.with_obj) {
6503 6504
        case (none) { }
        case (some(?e)) {
6505 6506 6507
            // 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.
6508

6509
            with_obj_val = some[result](trans_expr(bcx, e));
L
Lindsey Kuper 已提交
6510 6511
        }
    }
L
Lindsey Kuper 已提交
6512 6513 6514 6515
    // 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.

6516
    auto self_ty = ty::ann_to_type(ccx.tcx, ann);
L
Lindsey Kuper 已提交
6517
    auto llself_ty = type_of(ccx, sp, self_ty);
6518 6519 6520
    // Allocate the object that we're going to return.  It's a two-word pair
    // containing a vtable pointer and a body pointer.

6521
    auto pair = alloca(bcx, llself_ty);
L
Lindsey Kuper 已提交
6522 6523 6524
    // 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'.
6525

6526 6527 6528 6529
    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)]);
6530 6531
    // Make a vtable for the outer object.  create_vtbl() wants an ast::_obj
    // and all we have is an ast::anon_obj, so we need to roll our own.
6532

6533 6534 6535 6536 6537
    let vec[ast::obj_field] addtl_fields = [];
    alt (anon_obj.fields) {
        case (none) { }
        case (some(?fields)) { addtl_fields = fields; }
    }
6538 6539 6540 6541 6542 6543
    let ast::_obj wrapper_obj =
        rec(fields=addtl_fields,
            methods=anon_obj.methods,
            dtor=none[@ast::method]);
    auto vtbl =
        create_vtbl(bcx.fcx.lcx, llself_ty, self_ty, wrapper_obj, ty_params);
L
Lindsey Kuper 已提交
6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556
    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);
6557
    alt (anon_obj.fields) {
6558
        case (none) {
6559 6560
            // If the object we're translating has no fields or type
            // parameters, there's not much to do.
L
Lindsey Kuper 已提交
6561

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

6564
            bcx.build.Store(C_null(llbox_ty), pair_box);
L
Lindsey Kuper 已提交
6565
        }
6566 6567 6568
        case (some(?fields)) {
            // For the moment let's pretend that there are no additional
            // fields.
6569

6570 6571
            bcx.fcx.lcx.ccx.sess.unimpl("anon objs don't support " +
                                            "adding fields yet");
6572 6573
            // FIXME (issue #417): drop these fields into the newly created
            // object.
6574

L
Lindsey Kuper 已提交
6575 6576 6577
        }
    }
    // Return the object we built.
6578

L
Lindsey Kuper 已提交
6579
    ret res(bcx, pair);
L
Lindsey Kuper 已提交
6580 6581
}

P
Paul Stansifer 已提交
6582
fn init_local(&@block_ctxt cx, &@ast::local local) -> result {
6583
    // Make a note to drop this slot on the way out.
6584

P
Paul Stansifer 已提交
6585 6586 6587
    assert (cx.fcx.lllocals.contains_key(local.node.id));
    auto llptr = cx.fcx.lllocals.get(local.node.id);
    auto ty = node_ann_type(cx.fcx.lcx.ccx, local.node.ann);
6588
    auto bcx = cx;
6589
    find_scope_cx(cx).cleanups += [clean(bind drop_slot(_, llptr, ty))];
P
Paul Stansifer 已提交
6590
    alt (local.node.init) {
6591
        case (some(?init)) {
6592
            alt (init.op) {
6593
                case (ast::init_assign) {
6594 6595 6596
                    // 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.
6597 6598 6599 6600

                    ty =
                        node_ann_type(cx.fcx.lcx.ccx,
                                      ty::expr_ann(init.expr));
6601
                    auto sub = trans_expr(bcx, init.expr);
6602
                    bcx = copy_val(sub.bcx, INIT, llptr, sub.val, ty).bcx;
6603
                }
6604 6605
                case (ast::init_move) {
                    auto sub = trans_lval(bcx, init.expr);
6606 6607 6608
                    bcx =
                        move_val(sub.res.bcx, INIT, llptr, sub.res.val,
                                 ty).bcx;
6609
                }
6610
                case (ast::init_recv) {
6611 6612 6613
                    bcx = recv_val(bcx, llptr, init.expr, ty, INIT).bcx;
                }
            }
6614
        }
6615
        case (_) { bcx = zero_alloca(bcx, llptr, ty).bcx; }
6616 6617 6618 6619
    }
    ret res(bcx, llptr);
}

6620
fn zero_alloca(&@block_ctxt cx, ValueRef llptr, ty::t t) -> result {
6621
    auto bcx = cx;
6622
    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
6623
        auto llsz = size_of(bcx, t);
6624
        auto llalign = align_of(llsz.bcx, t);
6625
        bcx = call_bzero(llalign.bcx, llptr, llsz.val, llalign.val).bcx;
6626
    } else {
6627
        auto llty = type_of(bcx.fcx.lcx.ccx, cx.sp, t);
6628
        auto null = lib::llvm::llvm::LLVMConstNull(llty);
6629 6630 6631
        bcx.build.Store(null, llptr);
    }
    ret res(bcx, llptr);
6632
}
6633

6634
fn trans_stmt(&@block_ctxt cx, &ast::stmt s) -> result {
6635
    // FIXME Fill in cx.sp
6636

6637
    auto bcx = cx;
6638
    alt (s.node) {
6639 6640
        case (ast::stmt_expr(?e, _)) { bcx = trans_expr(cx, e).bcx; }
        case (ast::stmt_decl(?d, _)) {
6641
            alt (d.node) {
6642
                case (ast::decl_local(?local)) {
6643
                    bcx = init_local(bcx, local).bcx;
6644
                }
6645
                case (ast::decl_item(?i)) { trans_item(cx.fcx.lcx, *i); }
6646 6647
            }
        }
6648
        case (_) { cx.fcx.lcx.ccx.sess.unimpl("stmt variant"); }
6649
    }
6650
    ret res(bcx, C_nil());
6651 6652
}

6653
fn new_builder(BasicBlockRef llbb) -> builder {
6654 6655
    let BuilderRef llbuild = llvm::LLVMCreateBuilder();
    llvm::LLVMPositionBuilderAtEnd(llbuild, llbb);
6656
    ret builder(llbuild, @mutable false);
6657 6658
}

6659

6660 6661
// You probably don't want to use this one. See the
// next three functions instead.
6662
fn new_block_ctxt(&@fn_ctxt cx, &block_parent parent, block_kind kind,
G
Graydon Hoare 已提交
6663
                  &str name) -> @block_ctxt {
6664
    let vec[cleanup] cleanups = [];
6665
    auto s = str::buf("");
6666 6667
    if (cx.lcx.ccx.sess.get_opts().save_temps ||
        cx.lcx.ccx.sess.get_opts().debuginfo) {
6668
        s = str::buf(cx.lcx.ccx.names.next(name));
6669
    }
6670
    let BasicBlockRef llbb = llvm::LLVMAppendBasicBlock(cx.llfn, s);
6671
    ret @rec(llbb=llbb,
6672
             build=new_builder(llbb),
6673
             parent=parent,
6674
             kind=kind,
6675
             mutable cleanups=cleanups,
6676
             sp=cx.sp,
6677 6678 6679
             fcx=cx);
}

6680

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

6686

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

6692
fn new_loop_scope_block_ctxt(&@block_ctxt bcx, &option::t[@block_ctxt] _cont,
G
Graydon Hoare 已提交
6693
                             &@block_ctxt _break, &str n) -> @block_ctxt {
6694 6695 6696 6697
    ret new_block_ctxt(bcx.fcx, parent_some(bcx),
                       LOOP_SCOPE_BLOCK(_cont, _break), n);
}

6698

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

6704
fn new_raw_block_ctxt(&@fn_ctxt fcx, BasicBlockRef llbb) -> @block_ctxt {
6705
    let vec[cleanup] cleanups = [];
6706 6707 6708 6709 6710 6711
    ret @rec(llbb=llbb,
             build=new_builder(llbb),
             parent=parent_none,
             kind=NON_SCOPE_BLOCK,
             mutable cleanups=cleanups,
             sp=fcx.sp,
6712
             fcx=fcx);
6713 6714
}

6715

6716 6717 6718 6719 6720 6721 6722
// 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.
6723 6724
fn trans_block_cleanups(&@block_ctxt cx, &@block_ctxt cleanup_cx) ->
   @block_ctxt {
6725
    auto bcx = cx;
6726
    if (cleanup_cx.kind == NON_SCOPE_BLOCK) {
6727
        assert (vec::len[cleanup](cleanup_cx.cleanups) == 0u);
6728
    }
6729
    auto i = vec::len[cleanup](cleanup_cx.cleanups);
6730 6731 6732
    while (i > 0u) {
        i -= 1u;
        auto c = cleanup_cx.cleanups.(i);
6733
        alt (c) { case (clean(?cfn)) { bcx = cfn(bcx).bcx; } }
6734
    }
6735 6736 6737
    ret bcx;
}

P
Paul Stansifer 已提交
6738
iter block_locals(&ast::block b) -> @ast::local {
6739 6740
    // FIXME: putting from inside an iter block doesn't work, so we can't
    // use the index here.
6741
    for (@ast::stmt s in b.node.stmts) {
6742
        alt (s.node) {
6743
            case (ast::stmt_decl(?d, _)) {
6744
                alt (d.node) {
6745 6746
                    case (ast::decl_local(?local)) { put local; }
                    case (_) {/* fall through */ }
6747 6748
                }
            }
6749
            case (_) {/* fall through */ }
6750 6751 6752 6753
        }
    }
}

6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776
fn llstaticallocas_block_ctxt(&@fn_ctxt fcx) -> @block_ctxt {
    let vec[cleanup] cleanups = [];
    ret @rec(llbb=fcx.llstaticallocas,
             build=new_builder(fcx.llstaticallocas),
             parent=parent_none,
             kind=SCOPE_BLOCK,
             mutable cleanups=cleanups,
             sp=fcx.sp,
             fcx=fcx);
}

fn llderivedtydescs_block_ctxt(&@fn_ctxt fcx) -> @block_ctxt {
    let vec[cleanup] cleanups = [];
    ret @rec(llbb=fcx.llderivedtydescs,
             build=new_builder(fcx.llderivedtydescs),
             parent=parent_none,
             kind=SCOPE_BLOCK,
             mutable cleanups=cleanups,
             sp=fcx.sp,
             fcx=fcx);
}

fn lldynamicallocas_block_ctxt(&@fn_ctxt fcx) -> @block_ctxt {
6777
    let vec[cleanup] cleanups = [];
6778 6779
    ret @rec(llbb=fcx.lldynamicallocas,
             build=new_builder(fcx.lldynamicallocas),
6780 6781 6782
             parent=parent_none,
             kind=SCOPE_BLOCK,
             mutable cleanups=cleanups,
6783
             sp=fcx.sp,
6784 6785 6786
             fcx=fcx);
}

6787 6788


6789
fn alloc_ty(&@block_ctxt cx, &ty::t t) -> result {
6790
    auto val = C_int(0);
6791
    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
6792
        // NB: we have to run this particular 'size_of' in a
6793
        // block_ctxt built on the llderivedtydescs block for the fn,
6794 6795 6796
        // so that the size dominates the array_alloca that
        // comes next.

6797 6798
        auto n = size_of(llderivedtydescs_block_ctxt(cx.fcx), t);
        cx.fcx.llderivedtydescs = n.bcx.llbb;
6799
        val = array_alloca(cx, T_i8(), n.val);
6800
    } else { val = alloca(cx, type_of(cx.fcx.lcx.ccx, cx.sp, t)); }
6801 6802 6803 6804 6805 6806
    // 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.
6807

6808
    ret res(cx, val);
6809 6810
}

P
Paul Stansifer 已提交
6811 6812
fn alloc_local(&@block_ctxt cx, &@ast::local local) -> result {
    auto t = node_ann_type(cx.fcx.lcx.ccx, local.node.ann);
6813
    auto r = alloc_ty(cx, t);
P
Paul Stansifer 已提交
6814
    r.bcx.fcx.lllocals.insert(local.node.id, r.val);
6815 6816 6817
    ret r;
}

6818
fn trans_block(&@block_ctxt cx, &ast::block b, &out_method output) -> result {
6819
    auto bcx = cx;
P
Paul Stansifer 已提交
6820
    for each (@ast::local local in block_locals(b)) {
6821
        // FIXME Update bcx.sp
6822
        bcx = alloc_local(bcx, local).bcx;
6823
    }
6824
    auto r = res(bcx, C_nil());
6825
    for (@ast::stmt s in b.node.stmts) {
6826 6827
        r = trans_stmt(bcx, *s);
        bcx = r.bcx;
6828

6829 6830
        // If we hit a terminator, control won't go any further so
        // we're in dead-code land. Stop here.
6831
        if (is_terminated(bcx)) { ret r; }
6832
    }
6833 6834
    fn accept_out_method(&@ast::expr expr) -> bool {
        ret alt (expr.node) {
6835 6836 6837 6838 6839
                case (ast::expr_if(_, _, _, _)) { true }
                case (ast::expr_alt(_, _, _)) { true }
                case (ast::expr_block(_, _)) { true }
                case (_) { false }
            };
6840
    }
6841
    alt (b.node.expr) {
6842
        case (some(?e)) {
6843 6844 6845
            auto pass = output != return && accept_out_method(e);
            if (pass) {
                r = trans_expr_out(bcx, e, output);
6846
            } else { r = trans_expr(bcx, e); }
6847
            bcx = r.bcx;
6848 6849
            auto ccx = cx.fcx.lcx.ccx;
            auto r_ty = ty::expr_ty(ccx.tcx, e);
6850
            if (is_terminated(bcx) || ty::type_is_bot(ccx.tcx, r_ty)) {
6851
                ret r;
6852 6853 6854 6855 6856 6857 6858
            } 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!
6859 6860 6861

                        auto res_copy =
                            copy_val(bcx, INIT, target, r.val, r_ty);
6862 6863
                        bcx = res_copy.bcx;
                        r = res(bcx, C_nil());
6864
                    }
6865
                    case (return) { }
6866
                }
6867 6868
            }
        }
6869
        case (none) { r = res(bcx, C_nil()); }
6870
    }
6871
    bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
6872
    ret res(bcx, r.val);
6873 6874
}

G
Graydon Hoare 已提交
6875
fn new_local_ctxt(&@crate_ctxt ccx) -> @local_ctxt {
6876 6877 6878
    let vec[str] pth = [];
    let vec[ast::ty_param] obj_typarams = [];
    let vec[ast::obj_field] obj_fields = [];
6879
    ret @rec(path=pth,
6880
             module_path=[ccx.crate_meta_name],
6881 6882 6883
             obj_typarams=obj_typarams,
             obj_fields=obj_fields,
             ccx=ccx);
6884 6885
}

6886

6887 6888
// Creates the standard quartet of basic blocks: static allocas, copy args,
// derived tydescs, and dynamic allocas.
6889
fn mk_standard_basic_blocks(ValueRef llfn) ->
6890 6891
   tup(BasicBlockRef, BasicBlockRef, BasicBlockRef, BasicBlockRef) {
    ret tup(llvm::LLVMAppendBasicBlock(llfn, str::buf("static_allocas")),
6892
            llvm::LLVMAppendBasicBlock(llfn, str::buf("copy_args")),
6893 6894
            llvm::LLVMAppendBasicBlock(llfn, str::buf("derived_tydescs")),
            llvm::LLVMAppendBasicBlock(llfn, str::buf("dynamic_allocas")));
6895 6896
}

6897

6898 6899 6900 6901 6902 6903
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args
6904
fn new_fn_ctxt(@local_ctxt cx, &span sp, ValueRef llfndecl) -> @fn_ctxt {
6905 6906 6907 6908 6909 6910 6911
    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]();
6912
    auto derived_tydescs =
6913
        map::mk_hashmap[ty::t, derived_tydesc_info](ty::hash_ty, ty::eq_ty);
6914
    auto llbbs = mk_standard_basic_blocks(llfndecl);
6915
    ret @rec(llfn=llfndecl,
6916
             lltaskptr=lltaskptr,
6917 6918
             llenv=llenv,
             llretptr=llretptr,
6919
             mutable llstaticallocas=llbbs._0,
6920
             mutable llcopyargs=llbbs._1,
6921
             mutable llderivedtydescs_first=llbbs._2,
6922
             mutable llderivedtydescs=llbbs._2,
6923
             mutable lldynamicallocas=llbbs._3,
L
Lindsey Kuper 已提交
6924
             mutable llself=none[val_self_pair],
6925
             mutable lliterbody=none[ValueRef],
6926
             llargs=llargs,
6927
             llobjfields=llobjfields,
6928
             lllocals=lllocals,
6929
             llupvars=llupvars,
6930
             mutable lltydescs=vec::empty[ValueRef](),
6931
             derived_tydescs=derived_tydescs,
6932
             sp=sp,
6933
             lcx=cx);
6934 6935
}

6936

6937 6938 6939 6940 6941 6942 6943
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args

L
Lindsey Kuper 已提交
6944 6945 6946 6947 6948 6949 6950
// 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
6951 6952
fn create_llargs_for_fn_args(&@fn_ctxt cx, ast::proto proto,
                             option::t[ty_self_pair] ty_self, ty::t ret_ty,
6953 6954
                             &vec[ast::arg] args,
                             &vec[ast::ty_param] ty_params) {
L
Lindsey Kuper 已提交
6955 6956 6957
    // 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.
6958

6959
    auto arg_n = 3u;
6960
    alt (ty_self) {
6961
        case (some(?tt)) {
6962
            cx.llself = some[val_self_pair](rec(v=cx.llenv, t=tt._1));
6963
        }
6964
        case (none) {
6965
            auto i = 0u;
6966 6967
            for (ast::ty_param tp in ty_params) {
                auto llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
6968
                assert (llarg as int != 0);
6969
                cx.lltydescs += [llarg];
6970
                arg_n += 1u;
6971
                i += 1u;
6972
            }
6973
        }
6974
    }
L
Lindsey Kuper 已提交
6975 6976 6977
    // 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.
6978

6979 6980
    if (proto == ast::proto_iter) {
        auto llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
6981
        assert (llarg as int != 0);
6982 6983 6984
        cx.lliterbody = some[ValueRef](llarg);
        arg_n += 1u;
    }
6985

L
Lindsey Kuper 已提交
6986 6987
    // Populate the llargs field of the function context with the ValueRefs
    // that we get from llvm::LLVMGetParam for each argument.
6988 6989
    for (ast::arg arg in args) {
        auto llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
6990
        assert (llarg as int != 0);
6991 6992 6993 6994 6995
        cx.llargs.insert(arg.id, llarg);
        arg_n += 1u;
    }
}

6996

6997 6998 6999
// 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.
7000
fn copy_any_self_to_alloca(@fn_ctxt fcx, option::t[ty_self_pair] ty_self) {
7001
    auto bcx = llstaticallocas_block_ctxt(fcx);
7002
    alt ({ fcx.llself }) {
L
Lindsey Kuper 已提交
7003
        case (some(?pair)) {
7004
            alt (ty_self) {
L
Lindsey Kuper 已提交
7005
                case (some[ty_self_pair](?tt)) {
7006
                    auto a = alloca(bcx, tt._0);
L
Lindsey Kuper 已提交
7007
                    bcx.build.Store(pair.v, a);
7008
                    fcx.llself = some[val_self_pair](rec(v=a, t=pair.t));
7009 7010 7011
                }
            }
        }
7012
        case (_) { }
7013
    }
7014 7015
}

7016
fn copy_args_to_allocas(@fn_ctxt fcx, vec[ast::arg] args,
7017
                        vec[ty::arg] arg_tys) {
7018 7019
    auto bcx = new_raw_block_ctxt(fcx, fcx.llcopyargs);
    let uint arg_n = 0u;
7020
    for (ast::arg aarg in args) {
7021
        if (aarg.mode == ast::val) {
7022
            auto arg_t = type_of_arg(bcx.fcx.lcx, fcx.sp, arg_tys.(arg_n));
7023
            auto a = alloca(bcx, arg_t);
7024
            auto argval = bcx.fcx.llargs.get(aarg.id);
7025
            bcx.build.Store(argval, a);
7026
            // Overwrite the llargs entry for this arg with its alloca.
7027

7028
            bcx.fcx.llargs.insert(aarg.id, a);
7029
        }
7030 7031 7032 7033
        arg_n += 1u;
    }
}

7034
fn add_cleanups_for_args(&@block_ctxt bcx, vec[ast::arg] args,
7035
                         vec[ty::arg] arg_tys) {
7036
    let uint arg_n = 0u;
7037
    for (ast::arg aarg in args) {
7038
        if (aarg.mode == ast::val) {
7039 7040
            auto argval = bcx.fcx.llargs.get(aarg.id);
            find_scope_cx(bcx).cleanups +=
7041
                [clean(bind drop_slot(_, argval, arg_tys.(arg_n).ty))];
7042 7043 7044 7045 7046
        }
        arg_n += 1u;
    }
}

G
Graydon Hoare 已提交
7047
fn is_terminated(&@block_ctxt cx) -> bool {
7048 7049
    auto inst = llvm::LLVMGetLastInstruction(cx.llbb);
    ret llvm::LLVMIsATerminatorInst(inst) as int != 0;
7050 7051
}

7052
fn arg_tys_of_fn(&@crate_ctxt ccx, ast::ann ann) -> vec[ty::arg] {
7053
    alt (ty::struct(ccx.tcx, ty::ann_to_type(ccx.tcx, ann))) {
7054
        case (ty::ty_fn(_, ?arg_tys, _, _, _)) { ret arg_tys; }
7055 7056 7057
    }
}

7058 7059
fn ret_ty_of_fn_ty(&@crate_ctxt ccx, ty::t t) -> ty::t {
    alt (ty::struct(ccx.tcx, t)) {
7060
        case (ty::ty_fn(_, _, ?ret_ty, _, _)) { ret ret_ty; }
7061
        case (_) {
7062 7063
            ccx.sess.bug("ret_ty_of_fn_ty() called on non-function type: " +
                             ty_to_str(ccx.tcx, t));
7064
        }
7065 7066 7067
    }
}

7068
fn ret_ty_of_fn(&@crate_ctxt ccx, ast::ann ann) -> ty::t {
7069
    ret ret_ty_of_fn_ty(ccx, ty::ann_to_type(ccx.tcx, ann));
7070 7071
}

L
Lindsey Kuper 已提交
7072
fn populate_fn_ctxt_from_llself(@fn_ctxt fcx, val_self_pair llself) {
7073
    auto bcx = llstaticallocas_block_ctxt(fcx);
7074
    let vec[ty::t] field_tys = [];
7075
    for (ast::obj_field f in bcx.fcx.lcx.obj_fields) {
7076
        field_tys += [node_ann_type(bcx.fcx.lcx.ccx, f.ann)];
7077
    }
7078 7079 7080
    // Synthesize a tuple type for the fields so that GEP_tup_like() can work
    // its magic.

7081
    auto fields_tup_ty = ty::mk_imm_tup(fcx.lcx.ccx.tcx, field_tys);
7082
    auto n_typarams = vec::len[ast::ty_param](bcx.fcx.lcx.obj_typarams);
7083
    let TypeRef llobj_box_ty = T_obj_ptr(bcx.fcx.lcx.ccx.tn, n_typarams);
7084
    auto box_cell =
7085
        bcx.build.GEP(llself.v, [C_int(0), C_int(abi::obj_field_box)]);
7086 7087
    auto box_ptr = bcx.build.Load(box_cell);
    box_ptr = bcx.build.PointerCast(box_ptr, llobj_box_ty);
7088 7089 7090 7091
    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)]);
7092 7093 7094
    // The object fields immediately follow the type parameters, so we skip
    // over them to get the pointer.

7095 7096
    auto et = llvm::LLVMGetElementType(val_ty(obj_typarams));
    auto obj_fields = bcx.build.Add(vp2i(bcx, obj_typarams), llsize_of(et));
7097 7098 7099
    // 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 *.
7100

7101
    if (!ty::type_has_dynamic_size(fcx.lcx.ccx.tcx, fields_tup_ty)) {
7102
        auto llfields_ty = type_of(fcx.lcx.ccx, fcx.sp, fields_tup_ty);
7103
        obj_fields = vi2p(bcx, obj_fields, T_ptr(llfields_ty));
7104
    } else { obj_fields = vi2p(bcx, obj_fields, T_ptr(T_i8())); }
7105
    let int i = 0;
7106
    for (ast::ty_param p in fcx.lcx.obj_typarams) {
7107 7108
        let ValueRef lltyparam =
            bcx.build.GEP(obj_typarams, [C_int(0), C_int(i)]);
7109
        lltyparam = bcx.build.Load(lltyparam);
7110
        fcx.lltydescs += [lltyparam];
7111 7112 7113
        i += 1;
    }
    i = 0;
7114
    for (ast::obj_field f in fcx.lcx.obj_fields) {
7115
        auto rslt = GEP_tup_like(bcx, fields_tup_ty, obj_fields, [0, i]);
7116
        bcx = llstaticallocas_block_ctxt(fcx);
7117
        auto llfield = rslt.val;
7118
        fcx.llobjfields.insert(f.id, llfield);
7119 7120
        i += 1;
    }
7121
    fcx.llstaticallocas = bcx.llbb;
7122 7123
}

7124

7125 7126
// Ties up the llstaticallocas -> llcopyargs -> llderivedtydescs ->
// lldynamicallocas -> lltop edges.
7127
fn finish_fn(&@fn_ctxt fcx, BasicBlockRef lltop) {
7128 7129 7130 7131
    new_builder(fcx.llstaticallocas).Br(fcx.llcopyargs);
    new_builder(fcx.llcopyargs).Br(fcx.llderivedtydescs_first);
    new_builder(fcx.llderivedtydescs).Br(fcx.lldynamicallocas);
    new_builder(fcx.lldynamicallocas).Br(lltop);
7132 7133
}

7134

7135 7136
// trans_fn: creates an LLVM function corresponding to a source language
// function.
7137
fn trans_fn(@local_ctxt cx, &span sp, &ast::_fn f, ValueRef llfndecl,
7138 7139
            option::t[ty_self_pair] ty_self, &vec[ast::ty_param] ty_params,
            &ast::ann ann) {
7140
    set_uwtable(llfndecl);
L
Lindsey Kuper 已提交
7141
    // Set up arguments to the function.
7142

7143 7144 7145 7146
    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);
7147
    copy_any_self_to_alloca(fcx, ty_self);
7148 7149 7150
    alt ({ fcx.llself }) {
        case (some(?llself)) { populate_fn_ctxt_from_llself(fcx, llself); }
        case (_) { }
7151
    }
7152
    auto arg_tys = arg_tys_of_fn(fcx.lcx.ccx, ann);
7153
    copy_args_to_allocas(fcx, f.decl.inputs, arg_tys);
L
Lindsey Kuper 已提交
7154 7155
    // Create the first basic block in the function and keep a handle on it to
    //  pass to finish_fn later.
7156

7157
    auto bcx = new_top_block_ctxt(fcx);
7158
    add_cleanups_for_args(bcx, f.decl.inputs, arg_tys);
7159
    auto lltop = bcx.llbb;
7160
    auto block_ty = node_ann_type(cx.ccx, f.body.node.a);
L
Lindsey Kuper 已提交
7161 7162 7163 7164
    // 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).
7165

7166 7167 7168 7169 7170
    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) };
7171
    if (!is_terminated(res.bcx)) {
7172 7173
        // FIXME: until LLVM has a unit type, we are moving around
        // C_nil values rather than their void type.
7174

7175
        res.bcx.build.RetVoid();
7176
    }
L
Lindsey Kuper 已提交
7177
    // Insert the mandatory first few basic blocks before lltop.
7178

7179
    finish_fn(fcx, lltop);
7180 7181
}

7182

L
Lindsey Kuper 已提交
7183 7184
// Create a vtable for an object being translated.  Returns a pointer into
// read-only memory.
7185 7186
fn create_vtbl(@local_ctxt cx, TypeRef llself_ty, ty::t self_ty,
               &ast::_obj ob, &vec[ast::ty_param] ty_params) -> ValueRef {
7187 7188
    auto dtor = C_null(T_ptr(T_i8()));
    alt (ob.dtor) {
7189
        case (some(?d)) {
7190
            auto dtor_1 = trans_dtor(cx, llself_ty, self_ty, ty_params, d);
7191
            dtor = llvm::LLVMConstBitCast(dtor_1, val_ty(dtor));
7192
        }
7193
        case (none) { }
7194
    }
7195
    let vec[ValueRef] methods = [dtor];
7196
    fn meth_lteq(&@ast::method a, &@ast::method b) -> bool {
7197
        ret str::lteq(a.node.ident, b.node.ident);
7198
    }
7199 7200
    auto meths =
        std::sort::merge_sort[@ast::method](bind meth_lteq(_, _), ob.methods);
7201
    for (@ast::method m in meths) {
7202
        auto llfnty = T_nil();
7203
        alt (ty::struct(cx.ccx.tcx, node_ann_type(cx.ccx, m.node.ann))) {
7204
            case (ty::ty_fn(?proto, ?inputs, ?output, _, _)) {
7205 7206 7207 7208
                llfnty =
                    type_of_fn_full(cx.ccx, m.span, proto,
                                    some[TypeRef](llself_ty), inputs, output,
                                    vec::len[ast::ty_param](ty_params));
7209 7210
            }
        }
7211 7212
        let @local_ctxt mcx =
            @rec(path=cx.path + ["method", m.node.ident] with *cx);
7213
        let str s = mangle_internal_name_by_path(mcx.ccx, mcx.path);
7214 7215
        let ValueRef llfn =
            decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty);
7216 7217 7218
        // Every method on an object gets its def_id inserted into the
        // crate-wide item_ids map, together with the ValueRef that points to
        // where that method's definition will be in the executable.
7219

7220 7221
        cx.ccx.item_ids.insert(m.node.id, llfn);
        cx.ccx.item_symbols.insert(m.node.id, s);
7222
        trans_fn(mcx, m.span, m.node.meth, llfn,
7223 7224
                 some[ty_self_pair](tup(llself_ty, self_ty)), ty_params,
                 m.node.ann);
7225
        methods += [llfn];
G
Graydon Hoare 已提交
7226
    }
7227
    auto vtbl = C_struct(methods);
7228 7229 7230
    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));
7231 7232
    llvm::LLVMSetInitializer(gvar, vtbl);
    llvm::LLVMSetGlobalConstant(gvar, True);
7233 7234
    llvm::LLVMSetLinkage(gvar,
                         lib::llvm::LLVMInternalLinkage as llvm::Linkage);
7235
    ret gvar;
G
Graydon Hoare 已提交
7236 7237
}

7238 7239
fn trans_dtor(@local_ctxt cx, TypeRef llself_ty, ty::t self_ty,
              &vec[ast::ty_param] ty_params, &@ast::method dtor) -> ValueRef {
7240
    auto llfnty = T_dtor(cx.ccx, dtor.span, llself_ty);
7241
    let str s = mangle_internal_name_by_path(cx.ccx, cx.path + ["drop"]);
7242 7243 7244
    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);
7245
    trans_fn(cx, dtor.span, dtor.node.meth, llfn,
7246 7247
             some[ty_self_pair](tup(llself_ty, self_ty)), ty_params,
             dtor.node.ann);
7248 7249 7250
    ret llfn;
}

7251

7252 7253
// trans_obj: creates an LLVM function that is the object constructor for the
// object being translated.
7254
fn trans_obj(@local_ctxt cx, &span sp, &ast::_obj ob, ast::def_id oid,
7255
             &vec[ast::ty_param] ty_params, &ast::ann ann) {
7256 7257 7258
    // To make a function, we have to create a function context and, inside
    // that, a number of block contexts for which code is generated.

7259 7260
    auto ccx = cx.ccx;
    auto llctor_decl = ccx.item_ids.get(oid);
7261 7262 7263 7264
    // 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 已提交
7265 7266
    // The fields of our object will become the arguments to the function
    // we're creating.
7267

7268
    let vec[ast::arg] fn_args = [];
7269
    for (ast::obj_field f in ob.fields) {
7270 7271
        fn_args +=
            [rec(mode=ast::alias(false), ty=f.ty, ident=f.ident, id=f.id)];
7272
    }
7273
    auto fcx = new_fn_ctxt(cx, sp, llctor_decl);
L
Lindsey Kuper 已提交
7274
    // Both regular arguments and type parameters are handled here.
7275

7276 7277
    create_llargs_for_fn_args(fcx, ast::proto_fn, none[ty_self_pair],
                              ret_ty_of_fn(ccx, ann), fn_args, ty_params);
7278
    let vec[ty::arg] arg_tys = arg_tys_of_fn(ccx, ann);
7279
    copy_args_to_allocas(fcx, fn_args, arg_tys);
L
Lindsey Kuper 已提交
7280
    //  Create the first block context in the function and keep a handle on it
7281
    //  to pass to finish_fn later.
7282

7283 7284
    auto bcx = new_top_block_ctxt(fcx);
    auto lltop = bcx.llbb;
L
Lindsey Kuper 已提交
7285 7286
    // 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.
7287

7288
    auto self_ty = ret_ty_of_fn(ccx, ann);
7289
    auto llself_ty = type_of(ccx, sp, self_ty);
L
Lindsey Kuper 已提交
7290 7291 7292 7293 7294
    // 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.)
7295

7296
    auto pair = bcx.fcx.llretptr;
L
Lindsey Kuper 已提交
7297 7298 7299 7300
    // 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'.

7301 7302 7303 7304
    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 已提交
7305 7306 7307 7308
    // 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.
7309

L
Lindsey Kuper 已提交
7310
    auto vtbl = create_vtbl(cx, llself_ty, self_ty, ob, ty_params);
7311
    bcx.build.Store(vtbl, pair_vtbl);
L
Lindsey Kuper 已提交
7312 7313 7314
    // 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.
7315

L
Lindsey Kuper 已提交
7316 7317 7318 7319 7320 7321 7322
    // 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.
7323

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

7329
        // Store null into pair, if no args or typarams.
7330 7331
        bcx.build.Store(C_null(llbox_ty), pair_box);
    } else {
L
Lindsey Kuper 已提交
7332 7333
        // Otherwise, we have to synthesize a big structural type for the
        // object body.
7334
        let vec[ty::t] obj_fields = [];
7335
        for (ty::arg a in arg_tys) { vec::push[ty::t](obj_fields, a.ty); }
L
Lindsey Kuper 已提交
7336

7337
        // Tuple type for fields: [field, ...]
7338 7339
        let ty::t fields_ty = ty::mk_imm_tup(ccx.tcx, obj_fields);

7340
        auto tydesc_ty = ty::mk_type(ccx.tcx);
7341
        let vec[ty::t] tps = [];
7342
        for (ast::ty_param tp in ty_params) {
7343
            vec::push[ty::t](tps, tydesc_ty);
7344
        }
7345 7346

        // Tuple type for typarams: [typaram, ...]
7347
        let ty::t typarams_ty = ty::mk_imm_tup(ccx.tcx, tps);
7348

7349
        // Tuple type for body: [tydesc_ty, [typaram, ...], [field, ...]]
7350 7351
        let ty::t body_ty =
            ty::mk_imm_tup(ccx.tcx, [tydesc_ty, typarams_ty, fields_ty]);
7352

7353 7354
        // Hand this type we've synthesized off to trans_malloc_boxed, which
        // allocates a box, including space for a refcount.
7355
        auto box = trans_malloc_boxed(bcx, body_ty);
7356
        bcx = box.bcx;
7357

7358 7359
        // mk_imm_box throws a refcount into the type we're synthesizing, so
        // that it looks like: [rc, [tydesc_ty, [typaram, ...], [field, ...]]]
7360
        let ty::t boxed_body_ty = ty::mk_imm_box(ccx.tcx, body_ty);
7361

7362
        // Grab onto the refcount and body parts of the box we allocated.
7363 7364 7365 7366 7367 7368 7369
        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]);
7370 7371
        bcx = body.bcx;
        bcx.build.Store(C_int(1), rc.val);
7372

7373 7374
        // Put together a tydesc for the body, so that the object can later be
        // freed by calling through its tydesc.
7375 7376 7377 7378 7379 7380

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

7382
        auto body_tydesc =
7383
            GEP_tup_like(bcx, body_ty, body.val,
7384
                         [0, abi::obj_body_elt_tydesc]);
7385
        bcx = body_tydesc.bcx;
7386 7387 7388
        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);
7389
        lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
7390 7391
        bcx = body_td.bcx;
        bcx.build.Store(body_td.val, body_tydesc.val);
7392

7393 7394 7395 7396 7397 7398 7399
        // 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.)

7400 7401 7402
        // Copy typarams into captured typarams.
        auto body_typarams =
            GEP_tup_like(bcx, body_ty, body.val,
7403
                         [0, abi::obj_body_elt_typarams]);
7404 7405
        bcx = body_typarams.bcx;
        let int i = 0;
7406
        for (ast::ty_param tp in ty_params) {
7407
            auto typaram = bcx.fcx.lltydescs.(i);
7408 7409
            auto capture =
                GEP_tup_like(bcx, typarams_ty, body_typarams.val, [0, i]);
7410
            bcx = capture.bcx;
7411
            bcx = copy_val(bcx, INIT, capture.val, typaram, tydesc_ty).bcx;
7412 7413
            i += 1;
        }
7414

7415
        // Copy args into body fields.
7416
        auto body_fields =
7417
            GEP_tup_like(bcx, body_ty, body.val,
7418
                         [0, abi::obj_body_elt_fields]);
7419
        bcx = body_fields.bcx;
7420
        i = 0;
7421
        for (ast::obj_field f in ob.fields) {
7422
            auto arg = bcx.fcx.llargs.get(f.id);
7423
            arg = load_if_immediate(bcx, arg, arg_tys.(i).ty);
7424 7425
            auto field =
                GEP_tup_like(bcx, fields_ty, body_fields.val, [0, i]);
7426
            bcx = field.bcx;
7427
            bcx = copy_val(bcx, INIT, field.val, arg, arg_tys.(i).ty).bcx;
7428 7429
            i += 1;
        }
7430

7431
        // Store box ptr in outer pair.
7432
        auto p = bcx.build.PointerCast(box.val, llbox_ty);
7433
        bcx.build.Store(p, pair_box);
7434
    }
7435
    bcx.build.RetVoid();
7436

7437
    // Insert the mandatory first few basic blocks before lltop.
7438
    finish_fn(fcx, lltop);
7439 7440
}

7441 7442 7443
fn trans_tag_variant(@local_ctxt cx, ast::def_id tag_id,
                     &ast::variant variant, int index,
                     &vec[ast::ty_param] ty_params) {
7444
    if (vec::len[ast::variant_arg](variant.node.args) == 0u) {
7445
        ret; // nullary constructors are just constants
7446

7447
    }
7448
    // Translate variant arguments to function arguments.
7449

7450
    let vec[ast::arg] fn_args = [];
7451
    auto i = 0u;
7452
    for (ast::variant_arg varg in variant.node.args) {
7453 7454 7455 7456 7457
        fn_args +=
            [rec(mode=ast::alias(false),
                 ty=varg.ty,
                 ident="arg" + uint::to_str(i, 10u),
                 id=varg.id)];
7458
    }
7459
    assert (cx.ccx.item_ids.contains_key(variant.node.id));
7460
    let ValueRef llfndecl = cx.ccx.item_ids.get(variant.node.id);
7461
    auto fcx = new_fn_ctxt(cx, variant.span, llfndecl);
7462 7463 7464
    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);
7465
    let vec[ty::t] ty_param_substs = [];
7466
    i = 0u;
7467
    for (ast::ty_param tp in ty_params) {
7468
        ty_param_substs += [ty::mk_param(cx.ccx.tcx, i)];
7469
        i += 1u;
7470
    }
7471
    auto arg_tys = arg_tys_of_fn(cx.ccx, variant.node.ann);
7472
    copy_args_to_allocas(fcx, fn_args, arg_tys);
7473 7474
    auto bcx = new_top_block_ctxt(fcx);
    auto lltop = bcx.llbb;
7475 7476
    // Cast the tag to a type we can GEP into.

7477 7478 7479
    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)]);
7480
    bcx.build.Store(C_int(index), lldiscrimptr);
7481
    auto llblobptr = bcx.build.GEP(lltagptr, [C_int(0), C_int(1)]);
7482
    i = 0u;
7483
    for (ast::variant_arg va in variant.node.args) {
7484 7485 7486
        auto rslt =
            GEP_tag(bcx, llblobptr, tag_id, variant.node.id, ty_param_substs,
                    i as int);
7487 7488
        bcx = rslt.bcx;
        auto lldestptr = rslt.val;
7489 7490 7491 7492
        // 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.

7493 7494
        auto llargptr =
            bcx.build.PointerCast(fcx.llargs.get(va.id), val_ty(lldestptr));
7495 7496
        auto arg_ty = arg_tys.(i).ty;
        auto llargval;
7497 7498
        if (ty::type_is_structural(cx.ccx.tcx, arg_ty) ||
                ty::type_has_dynamic_size(cx.ccx.tcx, arg_ty)) {
7499
            llargval = llargptr;
7500
        } else { llargval = bcx.build.Load(llargptr); }
7501
        rslt = copy_val(bcx, INIT, lldestptr, llargval, arg_ty);
7502
        bcx = rslt.bcx;
7503 7504 7505
        i += 1u;
    }
    bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
7506
    bcx.build.RetVoid();
7507
    finish_fn(fcx, lltop);
7508 7509
}

7510

7511 7512 7513
// 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?
7514
fn trans_const_expr(&@crate_ctxt cx, @ast::expr e) -> ValueRef {
7515
    alt (e.node) {
7516
        case (ast::expr_lit(?lit, ?ann)) { ret trans_lit(cx, *lit, ann); }
7517 7518 7519
        case (_) {
            cx.sess.span_unimpl(e.span, "consts that's not a plain literal");
        }
7520 7521 7522
    }
}

7523 7524
fn trans_const(&@crate_ctxt cx, @ast::expr e, &ast::def_id cid,
               &ast::ann ann) {
7525 7526
    auto t = node_ann_type(cx, ann);
    auto v = trans_const_expr(cx, e);
7527 7528
    // The scalars come back as 1st class LLVM vals
    // which we have to stick into global constants.
7529

7530
    auto g = cx.consts.get(cid);
7531 7532
    llvm::LLVMSetInitializer(g, v);
    llvm::LLVMSetGlobalConstant(g, True);
7533 7534
}

7535
fn trans_item(@local_ctxt cx, &ast::item item) {
7536
    alt (item.node) {
7537 7538 7539
        case (ast::item_fn(?f, ?tps)) {
            auto sub_cx = extend_path(cx, item.ident);
            auto llfndecl = cx.ccx.item_ids.get(item.id);
7540
            trans_fn(sub_cx, item.span, f, llfndecl, none[ty_self_pair], tps,
7541
                     item.ann);
7542
        }
7543
        case (ast::item_obj(?ob, ?tps, ?ctor_id)) {
7544 7545
            auto sub_cx =
                @rec(obj_typarams=tps, obj_fields=ob.fields
7546 7547
                     with *extend_path(cx, item.ident));
            trans_obj(sub_cx, item.span, ob, ctor_id, tps, item.ann);
7548
        }
7549
        case (ast::item_mod(?m)) {
7550
            auto sub_cx =
7551 7552
                @rec(path=cx.path + [item.ident],
                     module_path=cx.module_path + [item.ident] with *cx);
7553
            trans_mod(sub_cx, m);
7554
        }
7555 7556
        case (ast::item_tag(?variants, ?tps)) {
            auto sub_cx = extend_path(cx, item.ident);
7557
            auto i = 0;
7558
            for (ast::variant variant in variants) {
7559
                trans_tag_variant(sub_cx, item.id, variant, i, tps);
7560
                i += 1;
7561 7562
            }
        }
7563 7564
        case (ast::item_const(_, ?expr)) {
            trans_const(cx.ccx, expr, item.id, item.ann);
7565
        }
7566
        case (_) {/* fall through */ }
7567 7568 7569
    }
}

7570

7571 7572 7573 7574 7575
// Translate a module.  Doing this amounts to translating the items in the
// module; there ends up being no artifact (aside from linkage names) of
// separate modules in the compiled program.  That's because modules exist
// only as a convenience for humans working with the code, to organize names
// and control visibility.
7576
fn trans_mod(@local_ctxt cx, &ast::_mod m) {
7577
    for (@ast::item item in m.items) { trans_item(cx, *item); }
7578 7579
}

7580 7581
fn get_pair_fn_ty(TypeRef llpairty) -> TypeRef {
    // Bit of a kludge: pick the fn typeref out of the pair.
7582

7583
    ret struct_elt(llpairty, 0u);
7584 7585
}

7586 7587
fn decl_fn_and_pair(&@crate_ctxt ccx, &span sp, vec[str] path, str flav,
                    vec[ast::ty_param] ty_params, &ast::ann ann,
7588
                    ast::def_id id) {
7589
    auto llfty;
7590
    alt (ty::struct(ccx.tcx, node_ann_type(ccx, ann))) {
7591
        case (ty::ty_fn(?proto, ?inputs, ?output, _, _)) {
7592 7593 7594
            llfty =
                type_of_fn(ccx, sp, proto, inputs, output,
                           vec::len[ast::ty_param](ty_params));
7595 7596
        }
        case (_) {
7597
            ccx.sess.bug("decl_fn_and_pair(): fn item doesn't have fn type!");
7598 7599
        }
    }
7600 7601
    let bool is_main =
        str::eq(vec::top(path), "main") && !ccx.sess.get_opts().shared;
7602
    // Declare the function itself.
7603

7604 7605 7606 7607
    let str s =
        if (is_main) {
            "_rust_main"
        } else { mangle_internal_name_by_path(ccx, path) };
7608
    let ValueRef llfn = decl_internal_fastcall_fn(ccx.llmod, s, llfty);
7609
    // Declare the global constant pair that points to it.
7610

7611
    let str ps = mangle_exported_name(ccx, path, node_ann_type(ccx, ann));
7612
    register_fn_pair(ccx, ps, llfty, llfn, id);
7613
    if (is_main) {
7614
        if (ccx.main_fn != none[ValueRef]) {
7615
            ccx.sess.span_fatal(sp, "multiple 'main' functions");
7616
        }
7617 7618
        llvm::LLVMSetLinkage(llfn,
                             lib::llvm::LLVMExternalLinkage as llvm::Linkage);
7619 7620
        ccx.main_fn = some(llfn);
    }
7621 7622
}

7623 7624
fn create_fn_pair(&@crate_ctxt cx, str ps, TypeRef llfnty, ValueRef llfn,
                  bool external) -> ValueRef {
7625 7626
    auto gvar =
        llvm::LLVMAddGlobal(cx.llmod, T_fn_pair(cx.tn, llfnty), str::buf(ps));
7627
    auto pair = C_struct([llfn, C_null(T_opaque_closure_ptr(cx.tn))]);
7628 7629
    llvm::LLVMSetInitializer(gvar, pair);
    llvm::LLVMSetGlobalConstant(gvar, True);
7630
    if (!external) {
7631 7632
        llvm::LLVMSetLinkage(gvar,
                             lib::llvm::LLVMInternalLinkage as llvm::Linkage);
7633
    }
7634 7635
    ret gvar;
}
7636

7637 7638 7639
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.
7640 7641 7642

    auto gvar =
        create_fn_pair(cx, ps, llfnty, llfn, cx.sess.get_opts().shared);
7643
    cx.item_ids.insert(id, llfn);
P
Patrick Walton 已提交
7644
    cx.item_symbols.insert(id, ps);
7645 7646 7647
    cx.fn_pairs.insert(id, gvar);
}

7648

7649
// Returns the number of type parameters that the given native function has.
7650
fn native_fn_ty_param_count(&@crate_ctxt cx, &ast::def_id id) -> uint {
7651 7652 7653
    auto count;
    auto native_item = cx.native_items.get(id);
    alt (native_item.node) {
7654
        case (ast::native_item_ty(_, _)) {
7655
            cx.sess.bug("decl_native_fn_and_pair(): native fn isn't " +
7656
                            "actually a fn");
7657
        }
7658
        case (ast::native_item_fn(_, _, _, ?tps, _, _)) {
7659
            count = vec::len[ast::ty_param](tps);
7660 7661 7662 7663 7664
        }
    }
    ret count;
}

7665
fn native_fn_wrapper_type(&@crate_ctxt cx, &span sp, uint ty_param_count,
7666
                          ty::t x) -> TypeRef {
7667 7668
    alt (ty::struct(cx.tcx, x)) {
        case (ty::ty_native_fn(?abi, ?args, ?out)) {
7669
            ret type_of_fn(cx, sp, ast::proto_fn, args, out, ty_param_count);
7670 7671 7672 7673
        }
    }
}

7674 7675
fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, vec[str] path,
                           str name, &ast::ann ann, ast::def_id id) {
7676
    auto num_ty_param = native_fn_ty_param_count(ccx, id);
7677
    // Declare the wrapper.
7678

7679
    auto t = node_ann_type(ccx, ann);
7680
    auto wrapper_type = native_fn_wrapper_type(ccx, sp, num_ty_param, t);
7681
    let str s = mangle_internal_name_by_path(ccx, path);
7682 7683
    let ValueRef wrapper_fn =
        decl_internal_fastcall_fn(ccx.llmod, s, wrapper_type);
7684
    // Declare the global constant pair that points to it.
7685

7686
    let str ps = mangle_exported_name(ccx, path, node_ann_type(ccx, ann));
7687
    register_fn_pair(ccx, ps, wrapper_type, wrapper_fn, id);
7688
    // Build the wrapper.
7689

7690
    auto fcx = new_fn_ctxt(new_local_ctxt(ccx), sp, wrapper_fn);
7691
    auto bcx = new_top_block_ctxt(fcx);
7692
    auto lltop = bcx.llbb;
7693
    // Declare the function itself.
7694

7695
    auto item = ccx.native_items.get(id);
7696
    auto fn_type = node_ann_type(ccx, ann); // NB: has no type params
7697

7698
    auto abi = ty::ty_fn_abi(ccx.tcx, fn_type);
7699 7700 7701
    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);
7702 7703 7704 7705
    // 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.

7706 7707
    auto rty_is_nil =
        ty::type_is_nil(ccx.tcx, ty::ty_fn_ret(ccx.tcx, fn_type));
7708
    auto pass_task;
7709
    auto cast_to_i32;
7710
    alt (abi) {
7711
        case (ast::native_abi_rust) { pass_task = true; cast_to_i32 = true; }
7712
        case (ast::native_abi_rust_intrinsic) {
7713
            pass_task = true;
7714
            cast_to_i32 = false;
7715
        }
7716
        case (ast::native_abi_cdecl) {
7717
            pass_task = false;
7718
            cast_to_i32 = true;
7719
        }
7720
        case (ast::native_abi_llvm) {
7721
            pass_task = false;
7722 7723 7724 7725 7726 7727
            cast_to_i32 = false;
        }
    }
    auto lltaskptr;
    if (cast_to_i32) {
        lltaskptr = vp2i(bcx, fcx.lltaskptr);
7728
    } else { lltaskptr = fcx.lltaskptr; }
7729 7730
    let vec[ValueRef] call_args = [];
    if (pass_task) { call_args += [lltaskptr]; }
7731
    auto arg_n = 3u;
7732
    for each (uint i in uint::range(0u, num_ty_param)) {
7733
        auto llarg = llvm::LLVMGetParam(fcx.llfn, arg_n);
7734
        fcx.lltydescs += [llarg];
7735 7736
        assert (llarg as int != 0);
        if (cast_to_i32) {
7737
            call_args += [vp2i(bcx, llarg)];
7738
        } else { call_args += [llarg]; }
7739
        arg_n += 1u;
7740
    }
7741 7742
    fn convert_arg_to_i32(&@block_ctxt cx, ValueRef v, ty::t t, ty::mode mode)
       -> ValueRef {
7743 7744
        if (mode == ty::mo_val) {
            if (ty::type_is_integral(cx.fcx.lcx.ccx.tcx, t)) {
7745
                auto lldsttype = T_int();
7746
                auto llsrctype = type_of(cx.fcx.lcx.ccx, cx.sp, t);
7747
                if (llvm::LLVMGetIntTypeWidth(lldsttype) >
7748
                        llvm::LLVMGetIntTypeWidth(llsrctype)) {
7749
                    ret cx.build.ZExtOrBitCast(v, T_int());
7750
                }
7751
                ret cx.build.TruncOrBitCast(v, T_int());
7752
            }
7753
            if (ty::type_is_fp(cx.fcx.lcx.ccx.tcx, t)) {
7754
                ret cx.build.FPToSI(v, T_int());
7755 7756
            }
        }
7757
        ret vp2i(cx, v);
7758
    }
7759
    fn trans_simple_native_abi(&@block_ctxt bcx, str name,
7760
                               &mutable vec[ValueRef] call_args,
7761 7762
                               ty::t fn_type, uint first_arg_n) ->
       tup(ValueRef, ValueRef) {
7763
        let vec[TypeRef] call_arg_tys = [];
7764
        for (ValueRef arg in call_args) { call_arg_tys += [val_ty(arg)]; }
7765 7766
        auto llnativefnty =
            T_fn(call_arg_tys,
7767
                 type_of(bcx.fcx.lcx.ccx, bcx.sp,
7768
                         ty::ty_fn_ret(bcx.fcx.lcx.ccx.tcx, fn_type)));
7769 7770 7771
        auto llnativefn =
            get_extern_fn(bcx.fcx.lcx.ccx.externs, bcx.fcx.lcx.ccx.llmod,
                          name, lib::llvm::LLVMCCallConv, llnativefnty);
7772 7773 7774 7775
        auto r = bcx.build.Call(llnativefn, call_args);
        auto rptr = bcx.fcx.llretptr;
        ret tup(r, rptr);
    }
7776
    auto args = ty::ty_fn_args(ccx.tcx, fn_type);
7777
    // Build up the list of arguments.
7778

7779
    let vec[tup(ValueRef, ty::t)] drop_args = [];
7780
    auto i = arg_n;
7781 7782
    for (ty::arg arg in args) {
        auto llarg = llvm::LLVMGetParam(fcx.llfn, i);
7783 7784 7785
        assert (llarg as int != 0);
        if (cast_to_i32) {
            auto llarg_i32 = convert_arg_to_i32(bcx, llarg, arg.ty, arg.mode);
7786
            call_args += [llarg_i32];
7787 7788
        } else { call_args += [llarg]; }
        if (arg.mode == ty::mo_val) { drop_args += [tup(llarg, arg.ty)]; }
7789 7790
        i += 1u;
    }
7791 7792 7793
    auto r;
    auto rptr;
    alt (abi) {
7794
        case (ast::native_abi_llvm) {
7795 7796 7797 7798
            auto result =
                trans_simple_native_abi(bcx, name, call_args, fn_type, arg_n);
            r = result._0;
            rptr = result._1;
7799
        }
7800
        case (ast::native_abi_rust_intrinsic) {
7801
            auto external_name = "rust_intrinsic_" + name;
7802 7803 7804 7805 7806
            auto result =
                trans_simple_native_abi(bcx, external_name, call_args,
                                        fn_type, arg_n);
            r = result._0;
            rptr = result._1;
7807
        }
7808
        case (_) {
7809 7810
            r =
                trans_native_call(bcx.build, ccx.glues, lltaskptr,
7811 7812 7813
                                  ccx.externs, ccx.tn, ccx.llmod, name,
                                  pass_task, call_args);
            rptr = bcx.build.BitCast(fcx.llretptr, T_ptr(T_i32()));
G
Graydon Hoare 已提交
7814
        }
7815
    }
7816 7817 7818 7819
    // 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.

7820
    if (!rty_is_nil) { bcx.build.Store(r, rptr); }
7821
    for (tup(ValueRef, ty::t) d in drop_args) {
7822 7823
        bcx = drop_ty(bcx, d._0, d._1).bcx;
    }
7824
    bcx.build.RetVoid();
7825
    finish_fn(fcx, lltop);
7826 7827
}

7828
fn item_path(&@ast::item item) -> vec[str] { ret [item.ident]; }
7829

7830 7831
fn collect_native_item(@crate_ctxt ccx, &@ast::native_item i, &vec[str] pt,
                       &vt[vec[str]] v) {
7832
    alt (i.node) {
7833
        case (ast::native_item_fn(?name, _, _, _, ?fid, ?ann)) {
7834 7835
            ccx.native_items.insert(fid, i);
            if (!ccx.obj_methods.contains_key(fid)) {
7836
                decl_native_fn_and_pair(ccx, i.span, pt, name, ann, fid);
7837
            }
7838
        }
7839
        case (ast::native_item_ty(_, ?tid)) {
7840
            ccx.native_items.insert(tid, i);
7841 7842 7843
        }
    }
}
7844

7845 7846
fn collect_item_1(@crate_ctxt ccx, &@ast::item i, &vec[str] pt,
                  &vt[vec[str]] v) {
7847
    visit::visit_item(i, pt + item_path(i), v);
7848
    alt (i.node) {
7849 7850
        case (ast::item_const(_, _)) {
            auto typ = node_ann_type(ccx, i.ann);
7851 7852
            auto g =
                llvm::LLVMAddGlobal(ccx.llmod, type_of(ccx, i.span, typ),
7853
                                    str::buf(ccx.names.next(i.ident)));
7854 7855 7856
            llvm::LLVMSetLinkage(g,
                                 lib::llvm::LLVMInternalLinkage as
                                     llvm::Linkage);
7857 7858
            ccx.items.insert(i.id, i);
            ccx.consts.insert(i.id, g);
7859
        }
7860 7861 7862 7863
        case (ast::item_mod(?m)) { ccx.items.insert(i.id, i); }
        case (ast::item_native_mod(_)) { ccx.items.insert(i.id, i); }
        case (ast::item_ty(_, _)) { ccx.items.insert(i.id, i); }
        case (ast::item_tag(_, _)) { ccx.items.insert(i.id, i); }
7864
        case (_) { }
7865 7866 7867
    }
}

7868 7869
fn collect_item_2(&@crate_ctxt ccx, &@ast::item i, &vec[str] pt,
                  &vt[vec[str]] v) {
7870 7871
    auto new_pt = pt + item_path(i);
    visit::visit_item(i, new_pt, v);
7872
    alt (i.node) {
7873 7874 7875 7876
        case (ast::item_fn(?f, ?tps)) {
            ccx.items.insert(i.id, i);
            if (!ccx.obj_methods.contains_key(i.id)) {
                decl_fn_and_pair(ccx, i.span, new_pt, "fn", tps, i.ann, i.id);
7877
            }
7878
        }
7879 7880 7881 7882
        case (ast::item_obj(?ob, ?tps, ?ctor_id)) {
            ccx.items.insert(ctor_id, i);
            decl_fn_and_pair(ccx, i.span, new_pt, "obj_ctor", tps, i.ann,
                             ctor_id);
7883
            for (@ast::method m in ob.methods) {
7884
                ccx.obj_methods.insert(m.node.id, ());
7885
            }
7886
        }
7887
        case (_) { }
7888 7889 7890
    }
}

7891
fn collect_items(&@crate_ctxt ccx, @ast::crate crate) {
7892
    auto visitor0 = visit::default_visitor();
7893 7894 7895 7896 7897
    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);
7898 7899 7900 7901
    visit::visit_crate(*crate, [], visit::vtor(visitor1));
    visit::visit_crate(*crate, [], visit::vtor(visitor2));
}

7902 7903
fn collect_tag_ctor(@crate_ctxt ccx, &@ast::item i, &vec[str] pt,
                    &vt[vec[str]] v) {
7904 7905
    auto new_pt = pt + item_path(i);
    visit::visit_item(i, new_pt, v);
7906
    alt (i.node) {
7907
        case (ast::item_tag(?variants, ?tps)) {
7908
            for (ast::variant variant in variants) {
7909
                if (vec::len[ast::variant_arg](variant.node.args) != 0u) {
7910
                    decl_fn_and_pair(ccx, i.span,
7911 7912
                                     new_pt + [variant.node.name], "tag", tps,
                                     variant.node.ann, variant.node.id);
7913 7914 7915
                }
            }
        }
7916
        case (_) {/* fall through */ }
7917 7918 7919
    }
}

7920
fn collect_tag_ctors(&@crate_ctxt ccx, @ast::crate crate) {
7921 7922 7923
    auto visitor =
        @rec(visit_item=bind collect_tag_ctor(ccx, _, _, _)
             with *visit::default_visitor());
7924
    visit::visit_crate(*crate, [], visit::vtor(visitor));
7925 7926
}

7927

7928 7929 7930
// The constant translation pass.
fn trans_constant(@crate_ctxt ccx, &@ast::item it, &vec[str] pt,
                  &vt[vec[str]] v) {
7931 7932
    auto new_pt = pt + item_path(it);
    visit::visit_item(it, new_pt, v);
7933
    alt (it.node) {
7934
        case (ast::item_tag(?variants, _)) {
7935
            auto i = 0u;
7936
            auto n_variants = vec::len[ast::variant](variants);
7937 7938
            while (i < n_variants) {
                auto variant = variants.(i);
7939
                auto discrim_val = C_int(i as int);
7940
                auto p = new_pt + [it.ident, variant.node.name, "discrim"];
7941
                auto s = mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx));
7942 7943
                auto discrim_gvar =
                    llvm::LLVMAddGlobal(ccx.llmod, T_int(), str::buf(s));
7944 7945
                llvm::LLVMSetInitializer(discrim_gvar, discrim_val);
                llvm::LLVMSetGlobalConstant(discrim_gvar, True);
7946 7947
                ccx.discrims.insert(variant.node.id, discrim_gvar);
                ccx.discrim_symbols.insert(variant.node.id, s);
7948 7949 7950
                i += 1u;
            }
        }
7951
        case (ast::item_const(_, ?expr)) {
7952 7953
            // FIXME: The whole expr-translation system needs cloning to deal
            // with consts.
7954

7955
            auto v = C_int(1);
7956
            ccx.item_ids.insert(it.id, v);
7957
            auto s =
7958 7959 7960
                mangle_exported_name(ccx, new_pt + [it.ident],
                                     node_ann_type(ccx, it.ann));
            ccx.item_symbols.insert(it.id, s);
7961
        }
7962
        case (_) { }
7963 7964 7965
    }
}

7966
fn trans_constants(&@crate_ctxt ccx, @ast::crate crate) {
7967 7968 7969
    auto visitor =
        @rec(visit_item=bind trans_constant(ccx, _, _, _)
             with *visit::default_visitor());
7970
    visit::visit_crate(*crate, [], visit::vtor(visitor));
7971 7972
}

G
Graydon Hoare 已提交
7973
fn vp2i(&@block_ctxt cx, ValueRef v) -> ValueRef {
7974 7975 7976
    ret cx.build.PtrToInt(v, T_int());
}

G
Graydon Hoare 已提交
7977
fn vi2p(&@block_ctxt cx, ValueRef v, TypeRef t) -> ValueRef {
7978 7979 7980
    ret cx.build.IntToPtr(v, t);
}

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

7983
fn i2p(ValueRef v, TypeRef t) -> ValueRef {
7984
    ret llvm::LLVMConstIntToPtr(v, t);
7985 7986
}

G
Graydon Hoare 已提交
7987
fn create_typedefs(&@crate_ctxt cx) {
7988 7989
    llvm::LLVMAddTypeName(cx.llmod, str::buf("task"), T_task(cx.tn));
    llvm::LLVMAddTypeName(cx.llmod, str::buf("tydesc"), T_tydesc(cx.tn));
7990 7991
}

7992 7993 7994 7995 7996 7997 7998 7999 8000
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()];
8001
    let vec[TypeRef] T_trap_args = [];
8002 8003 8004 8005 8006 8007 8008 8009 8010 8011 8012 8013 8014 8015
    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()));
8016
    auto intrinsics = new_str_hash[ValueRef]();
8017 8018
    intrinsics.insert("llvm.memmove.p0i8.p0i8.i32", memmove32);
    intrinsics.insert("llvm.memmove.p0i8.p0i8.i64", memmove64);
8019 8020
    intrinsics.insert("llvm.memset.p0i8.i32", memset32);
    intrinsics.insert("llvm.memset.p0i8.i64", memset64);
8021 8022
    intrinsics.insert("llvm.trap", trap);
    ret intrinsics;
8023 8024
}

G
Graydon Hoare 已提交
8025
fn trace_str(&@block_ctxt cx, str s) {
8026
    cx.build.Call(cx.fcx.lcx.ccx.upcalls.trace_str,
8027
                  [cx.fcx.lltaskptr, C_cstr(cx.fcx.lcx.ccx, s)]);
8028 8029
}

G
Graydon Hoare 已提交
8030
fn trace_word(&@block_ctxt cx, ValueRef v) {
8031
    cx.build.Call(cx.fcx.lcx.ccx.upcalls.trace_word, [cx.fcx.lltaskptr, v]);
8032 8033
}

G
Graydon Hoare 已提交
8034
fn trace_ptr(&@block_ctxt cx, ValueRef v) {
8035 8036 8037
    trace_word(cx, cx.build.PtrToInt(v, T_int()));
}

G
Graydon Hoare 已提交
8038
fn trap(&@block_ctxt bcx) {
8039
    let vec[ValueRef] v = [];
8040
    bcx.build.Call(bcx.fcx.lcx.ccx.intrinsics.get("llvm.trap"), v);
8041
}
8042

8043
fn decl_no_op_type_glue(ModuleRef llmod, type_names tn) -> ValueRef {
8044
    auto ty = T_fn([T_taskptr(tn), T_ptr(T_i8())], T_void());
8045
    ret decl_fastcall_fn(llmod, abi::no_op_type_glue_name(), ty);
8046 8047 8048
}

fn make_no_op_type_glue(ValueRef fun) {
8049
    auto bb_name = str::buf("_rust_no_op_type_glue_bb");
8050
    auto llbb = llvm::LLVMAppendBasicBlock(fun, bb_name);
8051
    new_builder(llbb).RetVoid();
8052 8053
}

G
Graydon Hoare 已提交
8054
fn vec_fill(&@block_ctxt bcx, ValueRef v) -> ValueRef {
8055 8056
    ret bcx.build.Load(bcx.build.GEP(v,
                                     [C_int(0), C_int(abi::vec_elt_fill)]));
8057 8058
}

G
Graydon Hoare 已提交
8059
fn vec_p0(&@block_ctxt bcx, ValueRef v) -> ValueRef {
8060
    auto p = bcx.build.GEP(v, [C_int(0), C_int(abi::vec_elt_data)]);
8061 8062 8063
    ret bcx.build.PointerCast(p, T_ptr(T_i8()));
}

G
Graydon Hoare 已提交
8064
fn make_glues(ModuleRef llmod, &type_names tn) -> @glue_fns {
8065
    ret @rec(no_op_type_glue=decl_no_op_type_glue(llmod, tn));
8066 8067
}

8068
fn make_common_glue(&session::session sess, &str output) {
8069
    // FIXME: part of this is repetitive and is probably a good idea
8070
    // to autogen it.
8071

8072
    auto llmod =
8073
        llvm::LLVMModuleCreateWithNameInContext(str::buf("rust_out"),
8074
                                                llvm::LLVMGetGlobalContext());
8075 8076
    llvm::LLVMSetDataLayout(llmod, str::buf(x86::get_data_layout()));
    llvm::LLVMSetTarget(llmod, str::buf(x86::get_target_triple()));
8077
    auto td = mk_target_data(x86::get_data_layout());
8078
    auto tn = mk_type_names();
8079
    auto intrinsics = declare_intrinsics(llmod);
8080
    llvm::LLVMSetModuleInlineAsm(llmod, str::buf(x86::get_module_asm()));
8081
    auto glues = make_glues(llmod, tn);
8082
    link::write::run_passes(sess, llmod, output);
8083 8084
}

G
Graydon Hoare 已提交
8085
fn create_module_map(&@crate_ctxt ccx) -> ValueRef {
8086
    auto elttype = T_struct([T_int(), T_int()]);
8087
    auto maptype = T_array(elttype, ccx.module_data.size() + 1u);
8088 8089
    auto map =
        llvm::LLVMAddGlobal(ccx.llmod, maptype, str::buf("_rust_mod_map"));
8090
    let vec[ValueRef] elts = [];
8091
    for each (@tup(str, ValueRef) item in ccx.module_data.items()) {
8092
        auto elt = C_struct([p2i(C_cstr(ccx, item._0)), p2i(item._1)]);
8093
        vec::push[ValueRef](elts, elt);
8094
    }
8095
    auto term = C_struct([C_int(0), C_int(0)]);
8096
    vec::push[ValueRef](elts, term);
8097
    llvm::LLVMSetInitializer(map, C_array(elttype, elts));
8098 8099 8100
    ret map;
}

8101

8102
// FIXME use hashed metadata instead of crate names once we have that
G
Graydon Hoare 已提交
8103
fn create_crate_map(&@crate_ctxt ccx) -> ValueRef {
8104
    let vec[ValueRef] subcrates = [];
8105 8106 8107
    auto i = 1;
    while (ccx.sess.has_external_crate(i)) {
        auto name = ccx.sess.get_external_crate(i).name;
8108 8109 8110
        auto cr =
            llvm::LLVMAddGlobal(ccx.llmod, T_int(),
                                str::buf("_rust_crate_map_" + name));
8111
        vec::push[ValueRef](subcrates, p2i(cr));
8112 8113
        i += 1;
    }
8114
    vec::push[ValueRef](subcrates, C_int(0));
8115 8116
    auto mapname;
    if (ccx.sess.get_opts().shared) {
8117
        mapname = ccx.crate_meta_name;
8118
    } else { mapname = "toplevel"; }
8119
    auto sym_name = "_rust_crate_map_" + mapname;
8120
    auto arrtype = T_array(T_int(), vec::len[ValueRef](subcrates));
8121
    auto maptype = T_struct([T_int(), arrtype]);
8122
    auto map = llvm::LLVMAddGlobal(ccx.llmod, maptype, str::buf(sym_name));
8123 8124 8125 8126 8127
    llvm::LLVMSetLinkage(map,
                         lib::llvm::LLVMExternalLinkage as llvm::Linkage);
    llvm::LLVMSetInitializer(map,
                             C_struct([p2i(create_module_map(ccx)),
                                       C_array(T_int(), subcrates)]));
8128 8129 8130
    ret map;
}

8131 8132
fn trans_crate(&session::session sess, &@ast::crate crate, &ty::ctxt tcx,
               &str output) -> ModuleRef {
8133
    auto llmod =
8134
        llvm::LLVMModuleCreateWithNameInContext(str::buf("rust_out"),
8135
                                                llvm::LLVMGetGlobalContext());
8136 8137
    llvm::LLVMSetDataLayout(llmod, str::buf(x86::get_data_layout()));
    llvm::LLVMSetTarget(llmod, str::buf(x86::get_target_triple()));
8138
    auto td = mk_target_data(x86::get_data_layout());
8139
    auto tn = mk_type_names();
8140
    auto intrinsics = declare_intrinsics(llmod);
8141
    auto glues = make_glues(llmod, tn);
8142 8143
    auto hasher = ty::hash_ty;
    auto eqer = ty::eq_ty;
8144 8145 8146 8147 8148 8149
    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);
8150
    auto sha = std::sha1::mk_sha1();
8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 8166 8167 8168 8169 8170 8171 8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187
    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));
8188
    auto cx = new_local_ctxt(ccx);
8189
    create_typedefs(ccx);
8190
    collect_items(ccx, crate);
8191 8192
    collect_tag_ctors(ccx, crate);
    trans_constants(ccx, crate);
8193
    trans_mod(cx, crate.node.module);
8194
    auto crate_map = create_crate_map(ccx);
8195
    emit_tydescs(ccx);
8196
    // Translate the metadata:
8197

8198
    middle::metadata::write_metadata(cx.ccx, crate);
8199 8200 8201 8202 8203 8204 8205 8206
    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);
    }
8207
    ret llmod;
8208 8209 8210 8211 8212 8213 8214 8215
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
8216
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
8217 8218
// End:
//