trans.rs 308.6 KB
Newer Older
1 2


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

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

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

80
type glue_fns = rec(ValueRef no_op_type_glue);
81

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

93

94 95 96 97 98 99 100 101
/*
 * A note on nomenclature of linking: "upcall", "extern" and "native".
 *
 * An "extern" is an LLVM symbol we wind up emitting an undefined external
 * reference to. This means "we don't have the thing in this compilation unit,
 * please make sure you link it in at runtime". This could be a reference to
 * C code found in a C library, or rust code found in a rust crate.
 *
102
 * A "native" is an extern that references C code. Called with cdecl.
103 104 105 106 107 108
 *
 * An upcall is a native call generated by the compiler (not corresponding to
 * any user-written call in the code) into librustrt, to perform some helper
 * task such as bringing a task to life, allocating memory, etc.
 *
 */
109 110 111 112 113 114 115
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);

116

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

        // 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.
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 162 163
        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);
164

165

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

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

171

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

266
tag block_kind {
267

268 269 270 271
    // 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.
272
    SCOPE_BLOCK;
273 274 275 276 277

    // 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?)
278
    LOOP_SCOPE_BLOCK(option::t[@block_ctxt], @block_ctxt);
279 280 281 282 283

    // 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.
284 285 286
    NON_SCOPE_BLOCK;
}

287

288 289 290 291 292
// 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.
293 294 295 296 297 298 299
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,
300

301 302 303
        // The llvm::builder object serving as an interface to LLVM's
        // LLVMBuild* functions.
        builder build,
304

305 306
        // The block pointing to this one in the function's digraph.
        block_parent parent,
307

308 309
        // The 'kind' of basic block this is.
        block_kind kind,
310

311 312 313 314
        // 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,
315

316 317 318 319 320 321
        // 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);
322

323

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

328
type result = rec(@block_ctxt bcx, ValueRef val);
329

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

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

336
fn ty_str(type_names tn, TypeRef t) -> str {
337
    ret lib::llvm::type_to_str(tn, t);
338 339
}

340 341 342
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)); }
343

344

345 346 347 348 349 350 351 352 353
// 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));
}

354 355

// LLVM type constructors.
356 357 358 359 360 361 362 363 364 365 366
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.
367

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

371 372 373
fn T_nil() -> TypeRef {
    // NB: See above in T_void().

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

377
fn T_i1() -> TypeRef { ret llvm::LLVMInt1Type(); }
378

379
fn T_i8() -> TypeRef { ret llvm::LLVMInt8Type(); }
380

381
fn T_i16() -> TypeRef { ret llvm::LLVMInt16Type(); }
382

383
fn T_i32() -> TypeRef { ret llvm::LLVMInt32Type(); }
384

385
fn T_i64() -> TypeRef { ret llvm::LLVMInt64Type(); }
386

387
fn T_f32() -> TypeRef { ret llvm::LLVMFloatType(); }
388

389 390 391
fn T_f64() -> TypeRef { ret llvm::LLVMDoubleType(); }

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

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

396 397 398
    ret T_i32();
}

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

402 403 404
    ret T_f64();
}

405
fn T_char() -> TypeRef { ret T_i32(); }
406

407 408
fn T_size_t() -> TypeRef {
    // FIXME: switch on target type.
409

410 411 412
    ret T_i32();
}

413
fn T_fn(vec[TypeRef] inputs, TypeRef output) -> TypeRef {
414 415
    ret llvm::LLVMFunctionType(output, vec::buf[TypeRef](inputs),
                               vec::len[TypeRef](inputs), False);
416 417
}

G
Graydon Hoare 已提交
418
fn T_fn_pair(&type_names tn, TypeRef tfn) -> TypeRef {
419
    ret T_struct([T_ptr(tfn), T_opaque_closure_ptr(tn)]);
420 421
}

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

G
Graydon Hoare 已提交
424
fn T_struct(&vec[TypeRef] elts) -> TypeRef {
425 426
    ret llvm::LLVMStructType(vec::buf[TypeRef](elts), vec::len[TypeRef](elts),
                             False);
427 428
}

429
fn T_opaque() -> TypeRef { ret llvm::LLVMOpaqueType(); }
430

G
Graydon Hoare 已提交
431
fn T_task(&type_names tn) -> TypeRef {
432
    auto s = "task";
433 434 435 436 437 438 439 440
    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
441 442 443 444

                  T_int(), // Domain pointer
                           // Crate cache pointer
                            T_int()]);
445 446
    tn.associate(s, t);
    ret t;
447 448
}

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

452
    let vec[TypeRef] tydesc_elts =
453
        vec::init_elt[TypeRef](T_nil(), abi::n_tydesc_fields as uint);
454
    llvm::LLVMGetStructElementTypes(T_tydesc(tn),
455
                                    vec::buf[TypeRef](tydesc_elts));
456
    auto t = llvm::LLVMGetElementType(tydesc_elts.(field));
457 458 459
    ret t;
}

G
Graydon Hoare 已提交
460
fn T_glue_fn(&type_names tn) -> TypeRef {
461
    auto s = "glue_fn";
462
    if (tn.name_has_type(s)) { ret tn.get_type(s); }
463
    auto t = T_tydesc_field(tn, abi::tydesc_field_drop_glue);
464 465 466 467
    tn.associate(s, t);
    ret t;
}

468
fn T_dtor(&@crate_ctxt ccx, &span sp, TypeRef llself_ty) -> TypeRef {
469
    ret type_of_fn_full(ccx, sp, ast::proto_fn, some[TypeRef](llself_ty),
470
                        vec::empty[ty::arg](), ty::mk_nil(ccx.tcx), 0u);
471 472
}

G
Graydon Hoare 已提交
473
fn T_cmp_glue_fn(&type_names tn) -> TypeRef {
474
    auto s = "cmp_glue_fn";
475
    if (tn.name_has_type(s)) { ret tn.get_type(s); }
476
    auto t = T_tydesc_field(tn, abi::tydesc_field_cmp_glue);
477 478
    tn.associate(s, t);
    ret t;
479 480
}

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

507 508
    llvm::LLVMRefineType(abs_tydesc, tydesc);
    auto t = llvm::LLVMResolveTypeHandle(th.llth);
509 510
    tn.associate(s, t);
    ret t;
511 512
}

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

515
fn T_vec(TypeRef t) -> TypeRef {
516 517 518
    ret T_struct([T_int(), // Refcount
                   T_int(), // Alloc
                   T_int(), // Fill
519 520 521 522

                  T_int(), // Pad
                           // Body elements
                            T_array(t, 0u)]);
523 524
}

525 526
fn T_opaque_vec_ptr() -> TypeRef { ret T_ptr(T_vec(T_int())); }

527

528 529 530
// Interior vector.
//
// TODO: Support user-defined vector sizes.
531
fn T_ivec(TypeRef t) -> TypeRef {
532 533 534 535
    ret T_struct([T_int(), // Length ("fill"; if zero, heapified)
                   T_int(), // Alloc
                   T_array(t, abi::ivec_default_length)]); // Body elements

536 537
}

538

539 540
// Note that the size of this one is in bytes.
fn T_opaque_ivec() -> TypeRef {
541 542 543 544
    ret T_struct([T_int(), // Length ("fill"; if zero, heapified)
                   T_int(), // Alloc
                   T_array(T_i8(), 0u)]); // Body elements

545 546
}

547
fn T_ivec_heap_part(TypeRef t) -> TypeRef {
548 549 550
    ret T_struct([T_int(), // Real length
                   T_array(t, 0u)]); // Body elements

551 552
}

553

554 555
// 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.
556
fn T_ivec_heap(TypeRef t) -> TypeRef {
557 558 559 560
    ret T_struct([T_int(), // Length (zero)
                   T_int(), // Alloc
                   T_ptr(T_ivec_heap_part(t))]); // Pointer

561 562 563
}

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

567 568
}

569
fn T_opaque_ivec_heap() -> TypeRef {
570 571 572
    ret T_struct([T_int(), // Length (zero)
                   T_int(), // Alloc
                   T_ptr(T_opaque_ivec_heap_part())]); // Pointer
573

574 575
}

576 577 578
fn T_str() -> TypeRef { ret T_vec(T_i8()); }

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

B
Brian Anderson 已提交
580
fn T_port(TypeRef t) -> TypeRef {
581
    ret T_struct([T_int()]); // Refcount
582

B
Brian Anderson 已提交
583 584 585
}

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

588 589
}

590 591 592
fn T_taskptr(&type_names tn) -> TypeRef { ret T_ptr(T_task(tn)); }


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

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

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

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

G
Graydon Hoare 已提交
614
fn T_opaque_closure_ptr(&type_names tn) -> TypeRef {
615
    auto s = "*closure";
616 617 618 619
    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);
620 621
    tn.associate(s, t);
    ret t;
622 623
}

G
Graydon Hoare 已提交
624
fn T_tag(&type_names tn, uint size) -> TypeRef {
625
    auto s = "tag_" + uint::to_str(size, 10u);
626
    if (tn.name_has_type(s)) { ret tn.get_type(s); }
627
    auto t = T_struct([T_int(), T_array(T_i8(), size)]);
628 629 630 631
    tn.associate(s, t);
    ret t;
}

G
Graydon Hoare 已提交
632
fn T_opaque_tag(&type_names tn) -> TypeRef {
633
    auto s = "opaque_tag";
634
    if (tn.name_has_type(s)) { ret tn.get_type(s); }
635
    auto t = T_struct([T_int(), T_i8()]);
636 637 638 639
    tn.associate(s, t);
    ret t;
}

G
Graydon Hoare 已提交
640
fn T_opaque_tag_ptr(&type_names tn) -> TypeRef {
641 642 643
    ret T_ptr(T_opaque_tag(tn));
}

G
Graydon Hoare 已提交
644
fn T_captured_tydescs(&type_names tn, uint n) -> TypeRef {
645
    ret T_struct(vec::init_elt[TypeRef](T_ptr(T_tydesc(tn)), n));
646 647
}

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

652
    fn T_obj(type_names tn, uint n_captured_tydescs) -> TypeRef {
653
        ret T_struct([T_ptr(T_tydesc(tn)),
654
                      T_captured_tydescs(tn, n_captured_tydescs)]);
655 656
    }
    ret T_ptr(T_box(T_obj(tn, n_captured_tydescs)));
657 658
}

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

661
fn T_opaque_port_ptr() -> TypeRef { ret T_ptr(T_i8()); }
662

663
fn T_opaque_chan_ptr() -> TypeRef { ret T_ptr(T_i8()); }
664

665

666 667 668 669
// 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.
670
fn type_of(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef {
671
    if (ty::type_has_dynamic_size(cx.tcx, t)) {
672 673 674
        cx.sess.span_err(sp,
                         "type_of() called on a type with dynamic size: " +
                             ty_to_str(cx.tcx, t));
675
    }
676
    ret type_of_inner(cx, sp, t);
677 678
}

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

700

701 702 703 704 705 706
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args
707 708 709
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 {
710
    let vec[TypeRef] atys = [];
711
    // Arg 0: Output pointer.
712

713
    if (ty::type_has_dynamic_size(cx.tcx, output)) {
714
        atys += [T_typaram_ptr(cx.tn)];
715
    } else { atys += [T_ptr(type_of_inner(cx, sp, output))]; }
716
    // Arg 1: task pointer.
717

718
    atys += [T_taskptr(cx.tn)];
719
    // Arg 2: Env (closure-bindings / self-obj)
720

721
    alt (obj_self) {
722 723
        case (some(?t)) { assert (t as int != 0); atys += [t]; }
        case (_) { atys += [T_opaque_closure_ptr(cx.tn)]; }
724
    }
725
    // Args >3: ty params, if not acquired via capture...
726

727 728 729
    if (obj_self == none[TypeRef]) {
        auto i = 0u;
        while (i < ty_param_count) {
730
            atys += [T_ptr(T_tydesc(cx.tn))];
731 732
            i += 1u;
        }
733
    }
734
    if (proto == ast::proto_iter) {
735 736 737
        // 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.
738

739
        atys +=
740
            [T_fn_pair(cx.tn,
741
                       type_of_fn_full(cx, sp, ast::proto_fn, none[TypeRef],
742
                                       [rec(mode=ty::mo_alias(false),
743 744
                                            ty=output)], ty::mk_nil(cx.tcx),
                                       0u))];
745
    }
746
    // ... then explicit args.
747

748
    atys += type_of_explicit_args(cx, sp, inputs);
749
    ret T_fn(atys, llvm::LLVMVoidType());
750 751
}

752 753 754
fn type_of_fn(&@crate_ctxt cx, &span sp, ast::proto proto,
              &vec[ty::arg] inputs, &ty::t output, uint ty_param_count) ->
   TypeRef {
755
    ret type_of_fn_full(cx, sp, proto, none[TypeRef], inputs, output,
756
                        ty_param_count);
757 758
}

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

776
fn type_of_inner(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef {
777 778
    // Check the cache.

779
    if (cx.lltypes.contains_key(t)) { ret cx.lltypes.get(t); }
780
    let TypeRef llty = 0 as TypeRef;
781 782 783
    alt (ty::struct(cx.tcx, t)) {
        case (ty::ty_native) { llty = T_ptr(T_i8()); }
        case (ty::ty_nil) { llty = T_nil(); }
784 785 786 787
        case (ty::ty_bot) {
            llty = T_nil(); /* ...I guess? */

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

890
fn type_of_arg(@local_ctxt cx, &span sp, &ty::arg arg) -> TypeRef {
891 892
    alt (ty::struct(cx.ccx.tcx, arg.ty)) {
        case (ty::ty_param(_)) {
893
            if (arg.mode != ty::mo_val) { ret T_typaram_ptr(cx.ccx.tn); }
894 895 896
        }
        case (_) {
            // fall through
897

898 899
        }
    }
900
    auto typ;
901
    if (arg.mode != ty::mo_val) {
902
        typ = T_ptr(type_of_inner(cx.ccx, sp, arg.ty));
903
    } else { typ = type_of_inner(cx.ccx, sp, arg.ty); }
904
    ret typ;
905 906
}

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

918 919
        }
    }
920
    ret type_of(lcx.ccx, sp, tpt._1);
921 922
}

923
fn type_of_or_i8(&@block_ctxt bcx, ty::t typ) -> TypeRef {
924
    if (ty::type_has_dynamic_size(bcx.fcx.lcx.ccx.tcx, typ)) { ret T_i8(); }
925 926 927
    ret type_of(bcx.fcx.lcx.ccx, bcx.sp, typ);
}

928

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

956

957 958
// LLVM constant constructors.
fn C_null(TypeRef t) -> ValueRef { ret llvm::LLVMConstNull(t); }
959

960
fn C_integral(TypeRef t, uint u, Bool sign_extend) -> ValueRef {
961
    // FIXME: We can't use LLVM::ULongLong with our existing minimal native
962
    // API, which only knows word-sized args.
963
    //
964
    // ret llvm::LLVMConstInt(T_int(), t as LLVM::ULongLong, False);
965
    //
966

967
    ret llvm::LLVMRustConstSmallInt(t, u, sign_extend);
968 969
}

G
Graydon Hoare 已提交
970
fn C_float(&str s) -> ValueRef {
971
    ret llvm::LLVMConstRealOfString(T_float(), str::buf(s));
972 973
}

G
Graydon Hoare 已提交
974
fn C_floating(&str s, TypeRef t) -> ValueRef {
975
    ret llvm::LLVMConstRealOfString(t, str::buf(s));
976 977
}

978 979
fn C_nil() -> ValueRef {
    // NB: See comment above in T_void().
980

981
    ret C_integral(T_i1(), 0u, False);
982 983
}

984 985
fn C_bool(bool b) -> ValueRef {
    if (b) {
986
        ret C_integral(T_bool(), 1u, False);
987
    } else { ret C_integral(T_bool(), 0u, False); }
988 989
}

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

992 993 994
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); }
995

996

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

1010

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

1029 1030
fn C_zero_byte_arr(uint size) -> ValueRef {
    auto i = 0u;
1031
    let vec[ValueRef] elts = [];
1032
    while (i < size) { elts += [C_u8(0u)]; i += 1u; }
1033
    ret llvm::LLVMConstArray(T_i8(), vec::buf[ValueRef](elts),
1034
                             vec::len[ValueRef](elts));
1035 1036
}

G
Graydon Hoare 已提交
1037
fn C_struct(&vec[ValueRef] elts) -> ValueRef {
1038
    ret llvm::LLVMConstStruct(vec::buf[ValueRef](elts),
1039
                              vec::len[ValueRef](elts), False);
1040 1041
}

G
Graydon Hoare 已提交
1042
fn C_array(TypeRef ty, &vec[ValueRef] elts) -> ValueRef {
1043
    ret llvm::LLVMConstArray(ty, vec::buf[ValueRef](elts),
1044
                             vec::len[ValueRef](elts));
1045 1046
}

G
Graydon Hoare 已提交
1047
fn decl_fn(ModuleRef llmod, &str name, uint cc, TypeRef llty) -> ValueRef {
1048
    let ValueRef llfn = llvm::LLVMAddFunction(llmod, str::buf(name), llty);
1049
    llvm::LLVMSetFunctionCallConv(llfn, cc);
1050 1051 1052
    ret llfn;
}

G
Graydon Hoare 已提交
1053
fn decl_cdecl_fn(ModuleRef llmod, &str name, TypeRef llty) -> ValueRef {
1054
    ret decl_fn(llmod, name, lib::llvm::LLVMCCallConv, llty);
1055 1056
}

G
Graydon Hoare 已提交
1057
fn decl_fastcall_fn(ModuleRef llmod, &str name, TypeRef llty) -> ValueRef {
1058
    ret decl_fn(llmod, name, lib::llvm::LLVMFastCallConv, llty);
1059 1060
}

1061

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

G
Graydon Hoare 已提交
1072
fn decl_glue(ModuleRef llmod, type_names tn, &str s) -> ValueRef {
1073
    ret decl_cdecl_fn(llmod, s, T_fn([T_taskptr(tn)], T_void()));
1074 1075
}

1076
fn get_extern_fn(&hashmap[str, ValueRef] externs, ModuleRef llmod, &str name,
1077
                 uint cc, TypeRef ty) -> ValueRef {
1078
    if (externs.contains_key(name)) { ret externs.get(name); }
1079
    auto f = decl_fn(llmod, name, cc, ty);
1080
    externs.insert(name, f);
1081 1082 1083
    ret f;
}

1084 1085 1086
fn get_extern_const(&hashmap[str, ValueRef] externs, ModuleRef llmod,
                    &str name, TypeRef ty) -> ValueRef {
    if (externs.contains_key(name)) { ret externs.get(name); }
1087
    auto c = llvm::LLVMAddGlobal(llmod, ty, str::buf(name));
1088 1089 1090 1091
    externs.insert(name, c);
    ret c;
}

1092 1093
fn get_simple_extern_fn(&hashmap[str, ValueRef] externs, ModuleRef llmod,
                        &str name, int n_args) -> ValueRef {
1094
    auto inputs = vec::init_elt[TypeRef](T_int(), n_args as uint);
1095 1096
    auto output = T_int();
    auto t = T_fn(inputs, output);
1097
    ret get_extern_fn(externs, llmod, name, lib::llvm::LLVMCCallConv, t);
1098 1099
}

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

G
Graydon Hoare 已提交
1111
fn trans_non_gc_free(&@block_ctxt cx, ValueRef v) -> result {
1112
    cx.build.Call(cx.fcx.lcx.ccx.upcalls.free,
1113 1114
                  [cx.fcx.lltaskptr, cx.build.PointerCast(v, T_ptr(T_i8())),
                   C_int(0)]);
1115
    ret res(cx, C_int(0));
1116 1117
}

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

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

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

G
Graydon Hoare 已提交
1139
fn align_to(&@block_ctxt cx, ValueRef off, ValueRef align) -> ValueRef {
1140 1141 1142 1143 1144
    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));
}

1145

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

1151
fn llsize_of(TypeRef t) -> ValueRef {
1152 1153
    ret llvm::LLVMConstIntCast(lib::llvm::llvm::LLVMSizeOf(t), T_int(),
                               False);
1154 1155
}

1156
fn llalign_of(TypeRef t) -> ValueRef {
1157 1158
    ret llvm::LLVMConstIntCast(lib::llvm::llvm::LLVMAlignOf(t), T_int(),
                               False);
1159 1160
}

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

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

G
Graydon Hoare 已提交
1175
fn alloca(&@block_ctxt cx, TypeRef t) -> ValueRef {
1176 1177 1178
    ret new_builder(cx.fcx.llallocas).Alloca(t);
}

G
Graydon Hoare 已提交
1179
fn array_alloca(&@block_ctxt cx, TypeRef t, ValueRef n) -> ValueRef {
1180 1181 1182 1183
    ret new_builder(cx.fcx.llallocas).ArrayAlloca(t, n);
}


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

1217

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

1238
    auto max_size = 0u;
1239 1240
    auto variants = ty::tag_variants(cx.tcx, tid);
    for (ty::variant_info variant in variants) {
1241
        auto tup_ty = simplify_type(cx, ty::mk_imm_tup(cx.tcx, variant.args));
1242 1243
        // Perform any type parameter substitutions.

1244
        tup_ty = ty::substitute_type_params(cx.tcx, subtys, tup_ty);
1245 1246
        // Here we possibly do a recursive call.

1247 1248
        auto this_size = llsize_of_real(cx, type_of(cx, sp, tup_ty));
        if (max_size < this_size) { max_size = this_size; }
1249 1250 1251 1252 1253
    }
    cx.tag_sizes.insert(t, max_size);
    ret max_size;
}

1254 1255
fn dynamic_size_of(&@block_ctxt cx, ty::t t) -> result {
    fn align_elements(&@block_ctxt cx, &vec[ty::t] elts) -> result {
1256 1257 1258 1259 1260 1261 1262 1263
        //
        // 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.
        //
1264

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

1300
            let ValueRef max_size = alloca(bcx, T_int());
1301
            bcx.build.Store(C_int(0), max_size);
1302 1303
            auto variants = ty::tag_variants(bcx.fcx.lcx.ccx.tcx, tid);
            for (ty::variant_info variant in variants) {
1304
                // Perform type substitution on the raw argument types.
1305

1306
                let vec[ty::t] raw_tys = variant.args;
1307
                let vec[ty::t] tys = [];
1308
                for (ty::t raw_ty in raw_tys) {
1309 1310 1311
                    auto t =
                        ty::substitute_type_params(cx.fcx.lcx.ccx.tcx, tps,
                                                   raw_ty);
1312
                    tys += [t];
1313
                }
1314 1315 1316 1317 1318 1319
                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);
            }
1320 1321 1322
            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);
1323
        }
1324 1325 1326 1327 1328 1329 1330 1331 1332
        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);
            auto llsz = bcx.build.Add(llsize_of(T_opaque_ivec()), llunitsz);
            ret res(bcx, llsz);
        }
1333 1334 1335
    }
}

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

1376

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

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

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

1415
        assert (len > 1u);
1416 1417 1418 1419
        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.
1420

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

1437
            ret rec(prefix=prefix, target=selected);
1438 1439 1440 1441
        } 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.
1442 1443

            auto inner = split_type(ccx, selected, ixs, n + 1u);
1444 1445 1446 1447 1448 1449 1450 1451
            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.

1452
    auto s = split_type(cx.fcx.lcx.ccx, t, ixs, 0u);
1453
    auto prefix_ty = ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, s.prefix);
1454 1455 1456 1457
    auto bcx = cx;
    auto sz = size_of(bcx, prefix_ty);
    bcx = sz.bcx;
    auto raw = bcx.build.PointerCast(base, T_ptr(T_i8()));
1458
    auto bumped = bcx.build.GEP(raw, [sz.val]);
1459
    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, s.target)) {
1460
        ret res(bcx, bumped);
1461
    }
1462
    auto typ = T_ptr(type_of(bcx.fcx.lcx.ccx, bcx.sp, s.target));
1463
    ret res(bcx, bcx.build.PointerCast(bumped, typ));
1464 1465
}

1466

1467 1468 1469 1470
// 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.
1471 1472 1473 1474
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);
1475 1476
    // Synthesize a tuple type so that GEP_tup_like() can work its magic.
    // Separately, store the type of the element we're interested in.
1477

1478
    auto arg_tys = variant.args;
1479
    auto elem_ty = ty::mk_nil(cx.fcx.lcx.ccx.tcx); // typestate infelicity
1480

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

1494
    let ValueRef llunionptr;
1495
    if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, tup_ty)) {
1496
        auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, tup_ty);
1497
        llunionptr = cx.build.TruncOrBitCast(llblobptr, T_ptr(llty));
1498
    } else { llunionptr = llblobptr; }
1499 1500
    // Do the GEP_tup_like().

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

1504
    auto val;
1505
    if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, elem_ty)) {
1506
        auto llelemty = type_of(rslt.bcx.fcx.lcx.ccx, cx.sp, elem_ty);
1507
        val = rslt.bcx.build.PointerCast(rslt.val, T_ptr(llelemty));
1508
    } else { val = rslt.val; }
1509 1510 1511
    ret res(rslt.bcx, val);
}

1512

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

1519
    auto tydesc = C_null(T_ptr(T_tydesc(cx.fcx.lcx.ccx.tn)));
1520 1521 1522
    auto rval =
        cx.build.Call(cx.fcx.lcx.ccx.upcalls.malloc,
                      [cx.fcx.lltaskptr, llsize, tydesc]);
1523
    ret res(cx, cx.build.PointerCast(rval, llptr_ty));
1524 1525
}

L
Lindsey Kuper 已提交
1526 1527 1528 1529

// 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.
1530
fn trans_malloc_boxed(&@block_ctxt cx, ty::t t) -> result {
1531 1532
    // Synthesize a fake box type structurally so we have something
    // to measure the size of.
L
Lindsey Kuper 已提交
1533 1534 1535 1536 1537

    // 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.
1538 1539 1540 1541 1542 1543

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

1549
    auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, box_ptr);
1550
    ret trans_raw_malloc(sz.bcx, llty, sz.val);
1551 1552 1553
}


1554 1555 1556 1557 1558
// 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.
1559 1560
fn field_of_tydesc(&@block_ctxt cx, &ty::t t, bool escapes, int field) ->
   result {
1561 1562
    auto ti = none[@tydesc_info];
    auto tydesc = get_tydesc(cx, t, escapes, ti);
1563
    ret res(tydesc.bcx,
1564
            tydesc.bcx.build.GEP(tydesc.val, [C_int(0), C_int(field)]));
1565
}
1566

1567

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

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

G
Graydon Hoare 已提交
1600
fn trans_stack_local_derived_tydesc(&@block_ctxt cx, ValueRef llsz,
1601 1602
                                    ValueRef llalign, ValueRef llroottydesc,
                                    ValueRef llparamtydescs) -> ValueRef {
1603
    auto llmyroottydesc = alloca(cx, T_tydesc(cx.fcx.lcx.ccx.tn));
1604
    // By convention, desc 0 is the root descriptor.
1605

1606
    llroottydesc = cx.build.Load(llroottydesc);
1607
    cx.build.Store(llroottydesc, llmyroottydesc);
1608
    // Store a pointer to the rest of the descriptors.
1609

1610
    auto llfirstparam = cx.build.GEP(llparamtydescs, [C_int(0), C_int(0)]);
1611
    cx.build.Store(llfirstparam,
1612
                   cx.build.GEP(llmyroottydesc, [C_int(0), C_int(0)]));
1613
    cx.build.Store(llsz, cx.build.GEP(llmyroottydesc, [C_int(0), C_int(1)]));
1614
    cx.build.Store(llalign,
1615
                   cx.build.GEP(llmyroottydesc, [C_int(0), C_int(2)]));
1616
    ret llmyroottydesc;
1617 1618
}

1619 1620
fn get_derived_tydesc(&@block_ctxt cx, &ty::t t, bool escapes,
                      &mutable option::t[@tydesc_info] static_ti) -> result {
1621
    alt (cx.fcx.derived_tydescs.find(t)) {
1622
        case (some(?info)) {
1623

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

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

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

1691
    alt (ty::type_param(cx.fcx.lcx.ccx.tcx, t)) {
1692
        case (some(?id)) { ret res(cx, cx.fcx.lltydescs.(id)); }
1693
        case (none) {/* fall through */ }
1694
    }
1695
    // Does it contain a type param? If so, generate a derived tydesc.
1696

1697
    if (ty::type_contains_params(cx.fcx.lcx.ccx.tcx, t)) {
1698
        ret get_derived_tydesc(cx, t, escapes, static_ti);
1699 1700
    }
    // Otherwise, generate a tydesc if necessary, and return it.
1701

1702
    let vec[uint] tps = [];
1703 1704 1705
    auto info = get_static_tydesc(cx, t, tps);
    static_ti = some[@tydesc_info](info);
    ret res(cx, info.tydesc);
1706 1707
}

1708 1709
fn get_static_tydesc(&@block_ctxt cx, &ty::t t, &vec[uint] ty_params) ->
   @tydesc_info {
1710
    alt (cx.fcx.lcx.ccx.tydescs.find(t)) {
1711
        case (some(?info)) { ret info; }
1712
        case (none) {
1713
            cx.fcx.lcx.ccx.stats.n_static_tydescs += 1u;
1714
            auto info = declare_tydesc(cx.fcx.lcx, cx.sp, t, ty_params);
1715
            cx.fcx.lcx.ccx.tydescs.insert(t, info);
1716 1717
            ret info;
        }
1718
    }
1719 1720
}

1721
fn set_no_inline(ValueRef f) {
1722 1723 1724
    llvm::LLVMAddFunctionAttr(f,
                              lib::llvm::LLVMNoInlineAttribute as
                                  lib::llvm::llvm::Attribute);
1725 1726
}

1727
fn set_uwtable(ValueRef f) {
1728 1729 1730
    llvm::LLVMAddFunctionAttr(f,
                              lib::llvm::LLVMUWTableAttribute as
                                  lib::llvm::llvm::Attribute);
1731 1732
}

1733
fn set_always_inline(ValueRef f) {
1734 1735 1736
    llvm::LLVMAddFunctionAttr(f,
                              lib::llvm::LLVMAlwaysInlineAttribute as
                                  lib::llvm::llvm::Attribute);
1737 1738 1739 1740 1741
}

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);
1742
    } else { set_always_inline(f); }
1743 1744 1745
}


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

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

1785
tag make_generic_glue_helper_fn {
1786
    mgghf_single(fn(&@block_ctxt, ValueRef, &ty::t) );
1787
    mgghf_cmp;
1788 1789
}

1790 1791
fn declare_generic_glue(&@local_ctxt cx, &ty::t t, TypeRef llfnty, &str name)
   -> ValueRef {
1792
    auto fn_nm;
1793
    if (cx.ccx.sess.get_opts().debuginfo) {
1794
        fn_nm = mangle_internal_name_by_type_only(cx.ccx, t, "glue_" + name);
1795
        fn_nm = sanitize(fn_nm);
1796
    } else { fn_nm = mangle_internal_name_by_seq(cx.ccx, "glue_" + name); }
1797
    auto llfn = decl_cdecl_fn(cx.ccx.llmod, fn_nm, llfnty);
1798
    set_glue_inlining(cx, llfn, t);
1799
    ret llfn;
1800
}
1801

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

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

1848 1849 1850 1851 1852
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;
1853 1854 1855 1856 1857 1858 1859 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
        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
1895 1896 1897 1898

        auto gvar = ti.tydesc;
        llvm::LLVMSetInitializer(gvar, tydesc);
        llvm::LLVMSetGlobalConstant(gvar, True);
1899 1900
        llvm::LLVMSetLinkage(gvar,
                             lib::llvm::LLVMInternalLinkage as llvm::Linkage);
1901 1902 1903
    }
}

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

1907
    auto bcx;
1908
    if (ty::type_is_boxed(cx.fcx.lcx.ccx.tcx, t)) {
1909
        bcx = incr_refcnt_of_boxed(cx, cx.build.Load(v)).bcx;
1910
    } else if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, t)) {
1911 1912
        bcx = iter_structural_ty(cx, v, t, bind take_ty(_, _, _)).bcx;
    } else { bcx = cx; }
1913
    bcx.build.RetVoid();
1914 1915
}

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

1932 1933
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.
1934

1935
    auto rslt;
1936 1937
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
        case (ty::ty_str) {
1938
            auto v = cx.build.Load(v0);
1939
            rslt = trans_non_gc_free(cx, v);
1940
        }
1941
        case (ty::ty_vec(_)) {
1942
            auto v = cx.build.Load(v0);
1943
            auto res = iter_sequence(cx, v, t, bind drop_ty(_, _, _));
1944
            // FIXME: switch gc/non-gc on layer of the type.
1945

1946
            rslt = trans_non_gc_free(res.bcx, v);
1947
        }
1948
        case (ty::ty_box(?body_mt)) {
1949
            auto v = cx.build.Load(v0);
1950 1951
            auto body =
                cx.build.GEP(v, [C_int(0), C_int(abi::box_rc_field_body)]);
1952 1953 1954 1955
            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.
1956

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

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

1991 1992 1993 1994 1995
            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.
1996

1997
            rslt = trans_non_gc_free(cx_, b);
1998
        }
1999
        case (ty::ty_fn(_, _, _, _, _)) {
2000
            auto box_cell =
2001
                cx.build.GEP(v0, [C_int(0), C_int(abi::fn_field_box)]);
2002 2003
            auto v = cx.build.Load(box_cell);
            // Call through the closure's own fields-drop glue first.
2004

2005
            auto body =
2006
                cx.build.GEP(v, [C_int(0), C_int(abi::box_rc_field_body)]);
2007 2008
            auto bindings =
                cx.build.GEP(body,
2009
                             [C_int(0), C_int(abi::closure_elt_bindings)]);
2010 2011
            auto tydescptr =
                cx.build.GEP(body,
2012
                             [C_int(0), C_int(abi::closure_elt_tydesc)]);
2013 2014 2015 2016 2017
            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.
2018

2019 2020 2021 2022 2023 2024 2025
            rslt = trans_non_gc_free(cx, v);
        }
        case (_) { rslt = res(cx, C_nil()); }
    }
    rslt.bcx.build.RetVoid();
}

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

    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)
        };
2049 2050 2051 2052 2053
    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());
}

2054 2055
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.
2056

2057 2058
    auto rslt;
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
2059 2060
        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); }
2061
        case (ty::ty_ivec(?tm)) {
2062 2063 2064 2065 2066 2067 2068 2069 2070
            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);
2071
        }
2072
        case (ty::ty_box(_)) { rslt = decr_refcnt_maybe_free(cx, v0, v0, t); }
2073 2074 2075 2076 2077 2078
        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);
        }
2079
        case (ty::ty_task) { rslt = decr_refcnt_maybe_free(cx, v0, v0, t); }
2080 2081
        case (ty::ty_obj(_)) {
            auto box_cell =
2082
                cx.build.GEP(v0, [C_int(0), C_int(abi::obj_field_box)]);
2083 2084
            rslt = decr_refcnt_maybe_free(cx, box_cell, v0, t);
        }
2085
        case (ty::ty_fn(_, _, _, _, _)) {
2086
            auto box_cell =
2087
                cx.build.GEP(v0, [C_int(0), C_int(abi::fn_field_box)]);
2088
            rslt = decr_refcnt_maybe_free(cx, box_cell, v0, t);
2089
        }
2090
        case (_) {
2091
            if (ty::type_has_pointers(cx.fcx.lcx.ccx.tcx, t) &&
2092 2093 2094
                    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()); }
2095 2096
        }
    }
2097
    rslt.bcx.build.RetVoid();
2098 2099
}

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

2133

2134
// Structural comparison: a rather involved form of glue.
G
Graydon Hoare 已提交
2135
fn maybe_name_value(&@crate_ctxt cx, ValueRef v, &str s) {
2136
    if (cx.sess.get_opts().save_temps) {
2137
        llvm::LLVMSetValueName(v, str::buf(s));
2138 2139 2140
    }
}

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

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

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

2237
                if (!ty::type_has_dynamic_size(last_cx.fcx.lcx.ccx.tcx, t)) {
2238 2239
                    auto llelemty =
                        T_ptr(type_of(last_cx.fcx.lcx.ccx, last_cx.sp, t));
2240 2241 2242 2243 2244 2245 2246 2247
                    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.

2248 2249 2250
            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);
2251
            // Second 'op' comparison: find out how this elt-pair decides.
2252

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

2283
        trans_fail(cx, none[common::span],
2284
                   "attempt to compare values of type " +
2285
                       ty_to_str(cx.fcx.lcx.ccx.tcx, t));
2286 2287 2288
    }
}

2289

2290
// Used only for creating scalar comparsion glue.
2291 2292
tag numerical_type { signed_int; unsigned_int; floating_point; }

2293

2294
// A helper function to create scalar comparison glue.
2295 2296
fn make_scalar_cmp_glue(&@block_ctxt cx, ValueRef lhs, ValueRef rhs, &ty::t t,
                        ValueRef llop) {
2297
    // assert ty::type_is_scalar(cx.fcx.lcx.ccx.tcx, t);
2298

2299 2300
    // In most cases, we need to know whether to do signed, unsigned, or float
    // comparison.
2301

2302
    auto f = bind make_numerical_cmp_glue(cx, lhs, rhs, _, llop);
2303

2304 2305 2306
    // 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)) {
2307
        case (ty::ty_nil) {
2308 2309 2310 2311 2312 2313 2314 2315
            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(_)) {
2316

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

            cx.fcx.lcx.ccx.sess.bug("non-scalar type passed to " +
                                        "make_scalar_cmp_glue");
2347
        }
2348 2349 2350
    }
}

2351

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

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

2411

2412 2413
// A helper function to create numerical comparison glue.
fn make_numerical_cmp_glue(&@block_ctxt cx, ValueRef lhs, ValueRef rhs,
2414
                           numerical_type nt, ValueRef llop) {
2415
    auto r = compare_numerical_values(cx, lhs, rhs, nt, llop);
2416 2417
    r.bcx.build.Store(r.val, r.bcx.fcx.llretptr);
    r.bcx.build.RetVoid();
2418 2419
}

2420 2421

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

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

2425
type val_pair_and_ty_fn =
2426 2427
    fn(&@block_ctxt, ValueRef, ValueRef, ty::t) -> result ;

2428

2429
// Iterates through the elements of a structural type.
2430 2431 2432
fn iter_structural_ty(&@block_ctxt cx, ValueRef v, &ty::t t, val_and_ty_fn f)
   -> result {
    fn adaptor_fn(val_and_ty_fn f, &@block_ctxt cx, ValueRef av, ValueRef bv,
2433
                  ty::t t) -> result {
2434 2435
        ret f(cx, av, t);
    }
2436
    ret iter_structural_ty_full(cx, v, v, t, bind adaptor_fn(f, _, _, _, _));
2437 2438
}

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

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

2479 2480 2481 2482 2483
        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.
2484

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

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

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

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

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

2624

2625 2626
// Iterates through a pointer range, until the src* hits the src_lim*.
fn iter_sequence_raw(@block_ctxt cx, ValueRef dst,
2627 2628

                         // elt*
2629
                         ValueRef src,
2630 2631

                         // elt*
2632
                         ValueRef src_lim,
2633 2634

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

2661
fn iter_sequence_inner(&@block_ctxt cx, ValueRef src,
2662 2663

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


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

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

2821 2822
fn call_tydesc_glue_full(&@block_ctxt cx, ValueRef v, ValueRef tydesc,
                         int field, &option::t[@tydesc_info] static_ti) {
2823
    lazily_emit_tydesc_glue(cx, field, static_ti);
2824
    auto llrawptr = cx.build.BitCast(v, T_ptr(T_i8()));
2825 2826 2827
    auto lltydescs =
        cx.build.GEP(tydesc,
                     [C_int(0), C_int(abi::tydesc_field_first_param)]);
2828
    lltydescs = cx.build.Load(lltydescs);
2829
    auto llfnptr = cx.build.GEP(tydesc, [C_int(0), C_int(field)]);
2830
    auto llfn = cx.build.Load(llfnptr);
2831 2832 2833
    cx.build.Call(llfn,
                  [C_null(T_ptr(T_nil())), cx.fcx.lltaskptr,
                   C_null(T_ptr(T_nil())), lltydescs, llrawptr]);
2834 2835
}

2836 2837
fn call_tydesc_glue(&@block_ctxt cx, ValueRef v, &ty::t t, int field) ->
   result {
2838
    let option::t[@tydesc_info] ti = none[@tydesc_info];
2839
    auto td = get_tydesc(cx, t, false, ti);
2840 2841
    call_tydesc_glue_full(td.bcx, spill_if_immediate(td.bcx, v, t), td.val,
                          field, ti);
2842
    ret res(td.bcx, C_nil());
2843 2844
}

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

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

2894
fn take_ty(&@block_ctxt cx, ValueRef v, ty::t t) -> result {
2895
    if (ty::type_has_pointers(cx.fcx.lcx.ccx.tcx, t)) {
2896
        ret call_tydesc_glue(cx, v, t, abi::tydesc_field_take_glue);
2897
    }
2898
    ret res(cx, C_nil());
2899 2900
}

2901
fn drop_slot(&@block_ctxt cx, ValueRef slot, &ty::t t) -> result {
2902
    auto llptr = load_if_immediate(cx, slot, t);
2903 2904
    auto re = drop_ty(cx, llptr, t);
    auto llty = val_ty(slot);
2905
    auto llelemty = lib::llvm::llvm::LLVMGetElementType(llty);
2906 2907
    re.bcx.build.Store(C_null(llelemty), slot);
    ret re;
2908 2909
}

2910
fn drop_ty(&@block_ctxt cx, ValueRef v, ty::t t) -> result {
2911
    if (ty::type_has_pointers(cx.fcx.lcx.ccx.tcx, t)) {
2912
        ret call_tydesc_glue(cx, v, t, abi::tydesc_field_drop_glue);
2913
    }
2914
    ret res(cx, C_nil());
2915 2916
}

2917
fn free_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_free_glue);
2920 2921 2922 2923
    }
    ret res(cx, C_nil());
}

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

2928
    auto i = cx.fcx.lcx.ccx.intrinsics;
2929 2930
    assert (i.contains_key("llvm.memmove.p0i8.p0i8.i32"));
    auto memmove = i.get("llvm.memmove.p0i8.p0i8.i32");
2931 2932
    auto src_ptr = cx.build.PointerCast(src, T_ptr(T_i8()));
    auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
2933 2934
    auto size = cx.build.IntCast(n_bytes, T_i32());
    auto align =
2935 2936 2937
        if (lib::llvm::llvm::LLVMIsConstant(align_bytes) == True) {
            cx.build.IntCast(align_bytes, T_i32())
        } else { cx.build.IntCast(C_int(0), T_i32()) };
2938
    auto volatile = C_bool(false);
2939 2940 2941
    ret res(cx,
            cx.build.Call(memmove,
                          [dst_ptr, src_ptr, size, align, volatile]));
2942 2943
}

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

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

2963 2964
fn memmove_ty(&@block_ctxt cx, ValueRef dst, ValueRef src, &ty::t t) ->
   result {
2965
    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
2966 2967
        auto llsz = size_of(cx, t);
        auto llalign = align_of(llsz.bcx, t);
2968
        ret call_memmove(llalign.bcx, dst, src, llsz.val, llalign.val);
2969
    } else { ret res(cx, cx.build.Store(cx.build.Load(src), dst)); }
2970 2971
}

2972
tag copy_action { INIT; DROP_EXISTING; }
2973

2974
// FIXME: This should copy the contents of the heap part for ivecs.
2975 2976
fn copy_val(&@block_ctxt cx, copy_action action, ValueRef dst, ValueRef src,
            &ty::t t) -> result {
2977

2978 2979
    if (ty::type_is_scalar(cx.fcx.lcx.ccx.tcx, t) ||
            ty::type_is_native(cx.fcx.lcx.ccx.tcx, t)) {
2980
        ret res(cx, cx.build.Store(src, dst));
2981
    } else if (ty::type_is_nil(cx.fcx.lcx.ccx.tcx, t) ||
2982
                   ty::type_is_bot(cx.fcx.lcx.ccx.tcx, t)) {
2983
        ret res(cx, C_nil());
2984
    } else if (ty::type_is_boxed(cx.fcx.lcx.ccx.tcx, t)) {
2985
        auto r = take_ty(cx, src, t);
2986
        if (action == DROP_EXISTING) {
2987
            r = drop_ty(r.bcx, r.bcx.build.Load(dst), t);
2988 2989
        }
        ret res(r.bcx, r.bcx.build.Store(src, dst));
2990
    } else if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, t) ||
2991
                   ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
2992
        auto r = take_ty(cx, src, t);
2993
        if (action == DROP_EXISTING) { r = drop_ty(r.bcx, dst, t); }
2994
        ret memmove_ty(r.bcx, dst, src, t);
2995
    }
2996
    cx.fcx.lcx.ccx.sess.bug("unexpected type in trans::copy_val: " +
2997
                                ty_to_str(cx.fcx.lcx.ccx.tcx, t));
2998 2999
}

3000

M
Michael Sullivan 已提交
3001 3002 3003 3004 3005
// 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.
3006
fn move_val(@block_ctxt cx, copy_action action, ValueRef dst, ValueRef src,
3007
            &ty::t t) -> result {
M
Michael Sullivan 已提交
3008 3009 3010 3011
    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) ||
3012
                   ty::type_is_bot(cx.fcx.lcx.ccx.tcx, t)) {
M
Michael Sullivan 已提交
3013 3014 3015 3016 3017 3018 3019 3020
        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) ||
3021 3022
                   ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
        if (action == DROP_EXISTING) { cx = drop_ty(cx, dst, t).bcx; }
3023
        auto r = memmove_ty(cx, dst, src, t);
M
Michael Sullivan 已提交
3024 3025 3026
        ret zero_alloca(r.bcx, src, t);
    }
    cx.fcx.lcx.ccx.sess.bug("unexpected type in trans::move_val: " +
3027
                                ty_to_str(cx.fcx.lcx.ccx.tcx, t));
M
Michael Sullivan 已提交
3028 3029
}

3030
fn trans_lit(&@crate_ctxt cx, &ast::lit lit, &ast::ann ann) -> ValueRef {
3031
    alt (lit.node) {
3032 3033
        case (ast::lit_int(?i)) { ret C_int(i); }
        case (ast::lit_uint(?u)) { ret C_int(u as int); }
3034
        case (ast::lit_mach_int(?tm, ?i)) {
3035 3036 3037
            // 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.
3038

3039
            auto t = T_int();
3040
            auto s = True;
3041
            alt (tm) {
3042 3043 3044 3045 3046 3047 3048 3049
                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(); }
3050
            }
3051
            ret C_integral(t, i as uint, s);
3052
        }
3053 3054
        case (ast::lit_float(?fs)) { ret C_float(fs); }
        case (ast::lit_mach_float(?tm, ?s)) {
3055
            auto t = T_float();
3056 3057 3058
            alt (tm) {
                case (common::ty_f32) { t = T_f32(); }
                case (common::ty_f64) { t = T_f64(); }
3059 3060 3061
            }
            ret C_floating(s, t);
        }
3062
        case (ast::lit_char(?c)) {
3063
            ret C_integral(T_char(), c as uint, False);
3064
        }
3065 3066 3067
        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); }
3068 3069 3070
    }
}

3071

3072
// Converts an annotation to a type
3073
fn node_ann_type(&@crate_ctxt cx, &ast::ann a) -> ty::t {
3074
    ret ty::ann_to_monotype(cx.tcx, a);
3075 3076
}

3077
fn node_type(&@crate_ctxt cx, &span sp, &ast::ann a) -> TypeRef {
3078
    ret type_of(cx, sp, node_ann_type(cx, a));
3079 3080
}

3081 3082
fn trans_unary(&@block_ctxt cx, ast::unop op, &@ast::expr e, &ast::ann a) ->
   result {
3083
    auto sub = trans_expr(cx, e);
3084
    auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
3085
    alt (op) {
3086
        case (ast::not) {
3087 3088 3089
            sub =
                autoderef(sub.bcx, sub.val,
                          ty::expr_ty(cx.fcx.lcx.ccx.tcx, e));
3090
            ret res(sub.bcx, sub.bcx.build.Not(sub.val));
3091
        }
3092
        case (ast::neg) {
3093 3094 3095 3096
            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) {
3097
                ret res(sub.bcx, sub.bcx.build.FNeg(sub.val));
3098
            } else { ret res(sub.bcx, sub.bcx.build.Neg(sub.val)); }
3099
        }
3100
        case (ast::box(_)) {
3101
            auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
3102
            auto e_val = sub.val;
3103
            auto box_ty = node_ann_type(sub.bcx.fcx.lcx.ccx, a);
3104 3105
            sub = trans_malloc_boxed(sub.bcx, e_ty);
            find_scope_cx(cx).cleanups +=
3106
                [clean(bind drop_ty(_, sub.val, box_ty))];
3107
            auto box = sub.val;
3108 3109 3110 3111 3112 3113 3114
            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)]);
3115
            sub.bcx.build.Store(C_int(1), rc);
3116 3117 3118
            // 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.
3119

3120
            if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, e_ty)) {
3121 3122
                auto llety =
                    T_ptr(type_of(sub.bcx.fcx.lcx.ccx, e.span, e_ty));
3123 3124
                body = sub.bcx.build.PointerCast(body, llety);
            }
3125
            sub = copy_val(sub.bcx, INIT, body, e_val, e_ty);
3126
            ret res(sub.bcx, box);
3127
        }
3128
        case (ast::deref) {
3129 3130 3131
            cx.fcx.lcx.ccx.sess.bug("deref expressions should have been " +
                                        "translated using trans_lval(), not "
                                        + "trans_unary()");
3132
        }
3133 3134 3135
    }
}

3136 3137
fn trans_compare(&@block_ctxt cx0, ast::binop op, &ty::t t0, ValueRef lhs0,
                 ValueRef rhs0) -> result {
3138
    // Autoderef both sides.
3139

3140
    auto cx = cx0;
3141 3142 3143 3144 3145 3146
    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;
3147
    auto t = autoderefed_ty(cx.fcx.lcx.ccx, t0);
3148 3149
    // Determine the operation we need.
    // FIXME: Use or-patterns when we have them.
3150

3151
    auto llop;
3152
    alt (op) {
3153 3154 3155 3156 3157 3158
        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); }
3159
    }
3160
    auto rslt = call_cmp_glue(cx, lhs, rhs, t, llop);
3161

3162 3163
    // Invert the result if necessary.
    // FIXME: Use or-patterns when we have them.
3164
    alt (op) {
3165 3166 3167
        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); }
3168 3169 3170
        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)); }
3171 3172 3173
    }
}

3174 3175
fn trans_vec_append(&@block_ctxt cx, &ty::t t, ValueRef lhs, ValueRef rhs) ->
   result {
3176
    auto elt_ty = ty::sequence_element_type(cx.fcx.lcx.ccx.tcx, t);
3177
    auto skip_null = C_bool(false);
3178 3179
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
        case (ty::ty_str) { skip_null = C_bool(true); }
3180 3181 3182
        case (_) { }
    }
    auto bcx = cx;
3183 3184
    auto ti = none[@tydesc_info];
    auto llvec_tydesc = get_tydesc(bcx, t, false, ti);
3185
    bcx = llvec_tydesc.bcx;
3186 3187 3188 3189
    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);
3190
    lazily_emit_tydesc_glue(cx, abi::tydesc_field_free_glue, ti);
3191
    bcx = llelt_tydesc.bcx;
3192 3193
    auto dst = bcx.build.PointerCast(lhs, T_ptr(T_opaque_vec_ptr()));
    auto src = bcx.build.PointerCast(rhs, T_opaque_vec_ptr());
3194 3195 3196 3197
    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]));
3198 3199
}

3200
mod ivec {
3201

3202 3203
    // Returns the length of an interior vector and a pointer to its first
    // element, in that order.
3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215
    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;
        }

3216 3217
        auto llunitty = type_of_or_i8(bcx, unit_ty);
        auto stack_len =
3218 3219 3220 3221 3222 3223
            {
                auto p = bcx.build.InBoundsGEP(v,
                                               [C_int(0),
                                                C_uint(abi::ivec_elt_len)]);
                bcx.build.Load(p)
            };
3224 3225
        auto stack_elem =
            bcx.build.InBoundsGEP(v,
3226 3227 3228 3229
                                  [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));
3230 3231 3232 3233 3234
        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)));
3235 3236 3237 3238 3239 3240
        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))
            };
3241 3242
        // Check whether the heap pointer is null. If it is, the vector length
        // is truly zero.
3243

3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260
        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.

3261 3262 3263 3264 3265 3266
        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)
            };
3267
        auto heap_elem =
3268 3269 3270 3271 3272
            {
                auto v = [C_int(0), C_uint(abi::ivec_heap_elt_elems),
                          C_int(0)];
                nonzero_len_cx.build.InBoundsGEP(heap_ptr,v)
            };
3273 3274 3275 3276 3277
        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 =
3278 3279 3280
            next_cx.build.Phi(T_int(), [stack_len, zero_len, heap_len],
                              [bcx.llbb, zero_len_cx.llbb,
                               nonzero_len_cx.llbb]);
3281 3282
        auto elem =
            next_cx.build.Phi(T_ptr(llunitty),
3283 3284 3285
                              [stack_elem, zero_elem, heap_elem],
                              [bcx.llbb, zero_len_cx.llbb,
                               nonzero_len_cx.llbb]);
3286
        ret tup(len, elem, next_cx);
3287 3288
    }

3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315
    // 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)];
3316 3317 3318
        auto stub_ptr =
            maybe_on_heap_cx.build.PointerCast(v,
                                               T_ptr(T_ivec_heap(llunitty)));
3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330
        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.
3331

3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348
        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 =
3349 3350 3351 3352 3353
            {
                auto v = [C_int(0), C_uint(abi::ivec_heap_elt_elems),
                          heap_len_unscaled];
                heap_no_resize_cx.build.InBoundsGEP(heap_ptr,v)
            };
3354 3355 3356 3357 3358
        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.

3359
        {
3360 3361
            auto p =
                heap_resize_cx.build.PointerCast(v, T_ptr(T_opaque_ivec()));
3362 3363 3364
            heap_resize_cx.build.Call(cx.fcx.lcx.ccx.upcalls.ivec_resize,
                                      [cx.fcx.lltaskptr, p, new_heap_len]);
        }
3365 3366 3367 3368 3369
        auto heap_ptr_resize =
            {
                auto m = heap_resize_cx.build.InBoundsGEP(stub_ptr, stub_p);
                heap_resize_cx.build.Load(m)
            };
3370
        auto heap_data_resize =
3371 3372 3373 3374 3375
            {
                auto v = [C_int(0), C_uint(abi::ivec_heap_elt_elems),
                          heap_len_unscaled];
                heap_resize_cx.build.InBoundsGEP(heap_ptr_resize, v)
            };
3376 3377
        heap_resize_cx.build.Br(next_cx.llbb);
        // We're on the stack. Check whether we need to spill to the heap.
3378

3379 3380 3381 3382 3383 3384 3385 3386 3387
        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,
3388
                                 stack_no_spill_cx.llbb, stack_spill_cx.llbb);
3389
        // Case (3): We're on the stack and don't need to spill.
3390

3391 3392 3393 3394 3395 3396 3397 3398 3399
        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.
3400

3401
        {
3402 3403
            auto p =
                stack_spill_cx.build.PointerCast(v, T_ptr(T_opaque_ivec()));
3404 3405 3406 3407 3408 3409
            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 =
3410 3411 3412 3413
            {
                auto p = stack_spill_cx.build.InBoundsGEP(spill_stub, stub_p);
                stack_spill_cx.build.Load(p)
            };
3414
        auto heap_len_ptr_spill =
3415 3416 3417 3418
            {
                auto v = [C_int(0), C_uint(abi::ivec_heap_elt_len)];
                stack_spill_cx.build.InBoundsGEP(heap_ptr_spill, v)
            };
3419
        auto heap_data_spill =
3420 3421 3422 3423 3424
            {
                auto v = [C_int(0), C_uint(abi::ivec_heap_elt_elems),
                          stack_len_unscaled];
                stack_spill_cx.build.InBoundsGEP(heap_ptr_spill, v)
            };
3425 3426
        stack_spill_cx.build.Br(next_cx.llbb);
        // Phi together the different data pointers to get the result.
3427

3428 3429 3430 3431 3432 3433 3434
        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);
3435
    }
3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448
    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;
        }

3449 3450 3451 3452 3453 3454 3455 3456 3457
        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");
            }
3458
        }
3459

3460
        // Gather the various type descriptors we'll need.
3461

3462 3463 3464 3465
        // FIXME (issue #511): This is needed to prevent a leak.
        auto no_tydesc_info = none;

        auto rslt = get_tydesc(cx, t, false, no_tydesc_info);
3466 3467
        auto vec_tydesc = rslt.val;
        auto bcx = rslt.bcx;
3468
        rslt = get_tydesc(bcx, unit_ty, false, no_tydesc_info);
3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481
        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.
3482

3483 3484 3485
        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.
3486

3487 3488 3489 3490
        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);
3491 3492
        auto copy_loop_header_cx =
            new_sub_block_ctxt(bcx, "copy_loop_header");
3493 3494 3495 3496
        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,
3497
                                           copy_dest_ptr, lhs_end);
3498 3499 3500 3501 3502 3503
        auto copy_loop_body_cx = new_sub_block_ctxt(bcx, "copy_loop_body");
        auto next_cx = new_sub_block_ctxt(bcx, "next");
        copy_loop_header_cx.build.CondBr(not_yet_at_end,
                                         copy_loop_body_cx.llbb,
                                         next_cx.llbb);
        auto copy_src_ptr = copy_loop_body_cx.build.Load(src_ptr);
3504 3505
        rslt =
            copy_val(copy_loop_body_cx, INIT, copy_dest_ptr, copy_src_ptr, t);
3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517
        auto post_copy_cx = rslt.bcx;
        // Increment both pointers.

        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);
        post_copy_cx.build.Br(copy_loop_header_cx.llbb);
        ret res(next_cx, C_nil());
    }
3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543

    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) {
            bcx = llallocas_block_ctxt(cx.fcx);
        } else {
            bcx = cx;
        }

        auto llunitsz;
        auto rslt = size_of(bcx, unit_ty);
        bcx = rslt.bcx;
        llunitsz = rslt.val;
        if (dynamic) { bcx.fcx.llallocas = bcx.llbb; }

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

        auto llptr;
3544
        auto llunitty = type_of_or_i8(bcx, unit_ty);
3545 3546 3547
        if (dynamic) {
            auto llarraysz = bcx.build.Add(llsize_of(T_opaque_ivec()),
                                           llalen);
3548
            auto llvecptr = array_alloca(bcx, T_i8(), llarraysz);
3549 3550 3551
            llptr = bcx.build.PointerCast(llvecptr, T_ptr(T_opaque_ivec()));
        } else {
            llptr = alloca(bcx, T_ivec(llunitty));
3552
        }
3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564

        auto bcx_result;
        if (dynamic) {
            bcx_result = cx;
        } else {
            bcx_result = bcx;
        }

        ret rec(bcx=bcx_result,
                llptr=llptr,
                llunitsz=llunitsz,
                llalen=llalen);
3565
    }
3566 3567 3568

    fn trans_add(&@block_ctxt cx, ty::t vec_ty, ValueRef lhs, ValueRef rhs)
            -> result {
3569 3570
        auto bcx = cx;
        auto unit_ty = ty::sequence_element_type(bcx.fcx.lcx.ccx.tcx, vec_ty);
3571 3572 3573 3574 3575 3576 3577

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

3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593
        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.

3594 3595
        auto len_is_zero =
            bcx.build.ICmp(lib::llvm::LLVMIntEQ, lllen, C_int(0));
3596 3597 3598 3599
        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.
3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616

        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));
3617
        zero_len_cx.build.Store(C_null(T_ptr(llheappartty)),
3618 3619
                                zero_len_cx.build.InBoundsGEP(stub_ptr_zero,
                                                              stub_p));
3620 3621 3622
        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.
3623 3624 3625

        auto on_stack =
            nonzero_len_cx.build.ICmp(lib::llvm::LLVMIntULE, lllen, llalen);
3626 3627 3628 3629
        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.
3630 3631 3632 3633 3634 3635 3636 3637 3638

        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)]);
3639 3640 3641 3642
        auto copy_cx = new_sub_block_ctxt(bcx, "copy");
        stack_cx.build.Br(copy_cx.llbb);
        // Case (3): Allocate on heap and copy there.

3643 3644 3645 3646 3647 3648 3649 3650
        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));
3651
        auto heap_sz = heap_cx.build.Add(llsize_of(llheappartty), lllen);
3652
        auto rslt = trans_raw_malloc(heap_cx, T_ptr(llheappartty), heap_sz);
3653 3654
        auto heap_part = rslt.val;
        heap_cx = rslt.bcx;
3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668
        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)]);
3669 3670 3671
        heap_cx.build.Br(copy_cx.llbb);
        // Emit the copy loop.

3672 3673 3674 3675
        auto first_dest_ptr =
            copy_cx.build.Phi(T_ptr(llunitty),
                              [dest_ptr_stack, dest_ptr_heap],
                              [stack_cx.llbb, heap_cx.llbb]);
3676
        auto lhs_len_unscaled = copy_cx.build.UDiv(lhs_len, unit_sz);
3677 3678
        auto lhs_end_ptr =
            copy_cx.build.InBoundsGEP(lhs_data, [lhs_len_unscaled]);
3679
        auto rhs_len_unscaled = copy_cx.build.UDiv(rhs_len, unit_sz);
3680 3681
        auto rhs_end_ptr =
            copy_cx.build.InBoundsGEP(rhs_data, [rhs_len_unscaled]);
3682 3683 3684 3685 3686 3687 3688 3689 3690
        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.
3691

3692
        auto lhs_ptr = lhs_copy_cx.build.Load(lhs_ptr_ptr);
3693 3694 3695
        auto not_at_end_lhs =
            lhs_copy_cx.build.ICmp(lib::llvm::LLVMIntNE, lhs_ptr,
                                   lhs_end_ptr);
3696 3697 3698 3699 3700 3701
        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);
3702 3703 3704
        rslt =
            copy_val(lhs_do_copy_cx, INIT, dest_ptr_lhs_copy, lhs_val,
                     unit_ty);
3705
        lhs_do_copy_cx = rslt.bcx;
3706 3707 3708 3709 3710 3711 3712 3713
        {
            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);
        }
3714 3715
        lhs_do_copy_cx.build.Br(lhs_copy_cx.llbb);
        // Copy in elements from the RHS.
3716

3717
        auto rhs_ptr = rhs_copy_cx.build.Load(rhs_ptr_ptr);
3718 3719 3720
        auto not_at_end_rhs =
            rhs_copy_cx.build.ICmp(lib::llvm::LLVMIntNE, rhs_ptr,
                                   rhs_end_ptr);
3721 3722 3723 3724 3725
        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);
3726 3727 3728
        rslt =
            copy_val(rhs_do_copy_cx, INIT, dest_ptr_rhs_copy, rhs_val,
                     unit_ty);
3729
        rhs_do_copy_cx = rslt.bcx;
3730 3731 3732 3733 3734 3735 3736 3737
        {
            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);
        }
3738 3739
        rhs_do_copy_cx.build.Br(rhs_copy_cx.llbb);
        // Finally done!
3740

3741 3742
        ret res(next_cx, llvecptr);
    }
3743 3744
}

3745 3746
fn trans_vec_add(&@block_ctxt cx, &ty::t t, ValueRef lhs, ValueRef rhs) ->
   result {
3747
    auto r = alloc_ty(cx, t);
3748
    auto tmp = r.val;
3749
    r = copy_val(r.bcx, INIT, tmp, lhs, t);
3750
    auto bcx = trans_vec_append(r.bcx, t, tmp, rhs).bcx;
3751
    tmp = load_if_immediate(bcx, tmp, t);
3752
    find_scope_cx(cx).cleanups += [clean(bind drop_ty(_, tmp, t))];
3753
    ret res(bcx, tmp);
3754 3755
}

3756
fn trans_eager_binop(&@block_ctxt cx, ast::binop op, &ty::t intype,
3757
                     ValueRef lhs, ValueRef rhs) -> result {
3758
    auto is_float = false;
3759
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, intype)) {
3760 3761
        case (ty::ty_float) { is_float = true; }
        case (_) { is_float = false; }
3762
    }
3763
    alt (op) {
3764 3765
        case (ast::add) {
            if (ty::type_is_sequence(cx.fcx.lcx.ccx.tcx, intype)) {
3766 3767 3768
                if (ty::sequence_is_interior(cx.fcx.lcx.ccx.tcx, intype)) {
                    ret ivec::trans_add(cx, intype, lhs, rhs);
                }
3769
                ret trans_vec_add(cx, intype, lhs, rhs);
3770
            }
3771 3772
            if (is_float) {
                ret res(cx, cx.build.FAdd(lhs, rhs));
3773
            } else { ret res(cx, cx.build.Add(lhs, rhs)); }
3774
        }
3775
        case (ast::sub) {
3776 3777
            if (is_float) {
                ret res(cx, cx.build.FSub(lhs, rhs));
3778
            } else { ret res(cx, cx.build.Sub(lhs, rhs)); }
3779
        }
3780
        case (ast::mul) {
3781 3782
            if (is_float) {
                ret res(cx, cx.build.FMul(lhs, rhs));
3783
            } else { ret res(cx, cx.build.Mul(lhs, rhs)); }
3784
        }
3785
        case (ast::div) {
3786
            if (is_float) { ret res(cx, cx.build.FDiv(lhs, rhs)); }
3787
            if (ty::type_is_signed(cx.fcx.lcx.ccx.tcx, intype)) {
3788
                ret res(cx, cx.build.SDiv(lhs, rhs));
3789
            } else { ret res(cx, cx.build.UDiv(lhs, rhs)); }
3790
        }
3791
        case (ast::rem) {
3792
            if (is_float) { ret res(cx, cx.build.FRem(lhs, rhs)); }
3793
            if (ty::type_is_signed(cx.fcx.lcx.ccx.tcx, intype)) {
3794
                ret res(cx, cx.build.SRem(lhs, rhs));
3795
            } else { ret res(cx, cx.build.URem(lhs, rhs)); }
3796
        }
3797 3798 3799 3800 3801 3802
        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)); }
3803
        case (_) { ret trans_compare(cx, op, intype, lhs, rhs); }
3804 3805 3806
    }
}

3807
fn autoderef(&@block_ctxt cx, ValueRef v, &ty::t t) -> result {
3808
    let ValueRef v1 = v;
3809
    let ty::t t1 = t;
3810
    while (true) {
3811 3812
        alt (ty::struct(cx.fcx.lcx.ccx.tcx, t1)) {
            case (ty::ty_box(?mt)) {
3813 3814 3815
                auto body =
                    cx.build.GEP(v1,
                                 [C_int(0), C_int(abi::box_rc_field_body)]);
3816
                t1 = mt.ty;
3817 3818 3819 3820
                // 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.
3821

3822
                if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, mt.ty)) {
3823
                    auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, mt.ty);
3824
                    v1 = cx.build.PointerCast(body, T_ptr(llty));
3825
                } else { v1 = body; }
3826
                v1 = load_if_immediate(cx, v1, t1);
3827
            }
3828
            case (_) { break; }
3829 3830
        }
    }
3831
    ret res(cx, v1);
3832 3833
}

3834 3835
fn autoderefed_ty(&@crate_ctxt ccx, &ty::t t) -> ty::t {
    let ty::t t1 = t;
3836
    while (true) {
3837
        alt (ty::struct(ccx.tcx, t1)) {
3838
            case (ty::ty_box(?mt)) { t1 = mt.ty; }
3839
            case (_) { break; }
3840 3841
        }
    }
3842
    ret t1;
3843 3844
}

3845 3846
fn trans_binary(&@block_ctxt cx, ast::binop op, &@ast::expr a, &@ast::expr b)
   -> result {
3847

3848 3849
    // First couple cases are lazy:
    alt (op) {
3850
        case (ast::and) {
3851 3852
            // Lazy-eval and

3853 3854 3855 3856
            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));
3857
            auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
3858
            auto rhs_res = trans_expr(rhs_cx, b);
3859 3860 3861
            rhs_res =
                autoderef(rhs_res.bcx, rhs_res.val,
                          ty::expr_ty(cx.fcx.lcx.ccx.tcx, b));
3862
            auto lhs_false_cx = new_scope_block_ctxt(cx, "lhs false");
3863
            auto lhs_false_res = res(lhs_false_cx, C_bool(false));
3864
            // The following line ensures that any cleanups for rhs
3865
            // are done within the block for rhs. This is necessary
3866 3867 3868
            // because and/or are lazy. So the rhs may never execute,
            // and the cleanups can't be pushed into later code.

3869 3870
            auto rhs_bcx = trans_block_cleanups(rhs_res.bcx, rhs_cx);
            lhs_res.bcx.build.CondBr(lhs_res.val, rhs_cx.llbb,
3871 3872
                                     lhs_false_cx.llbb);
            ret join_results(cx, T_bool(),
3873
                             [lhs_false_res, rec(bcx=rhs_bcx with rhs_res)]);
3874
        }
3875
        case (ast::or) {
3876 3877
            // Lazy-eval or

3878 3879 3880 3881
            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));
3882
            auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
3883
            auto rhs_res = trans_expr(rhs_cx, b);
3884 3885 3886
            rhs_res =
                autoderef(rhs_res.bcx, rhs_res.val,
                          ty::expr_ty(cx.fcx.lcx.ccx.tcx, b));
3887
            auto lhs_true_cx = new_scope_block_ctxt(cx, "lhs true");
3888
            auto lhs_true_res = res(lhs_true_cx, C_bool(true));
3889 3890
            // see the and case for an explanation

3891 3892
            auto rhs_bcx = trans_block_cleanups(rhs_res.bcx, rhs_cx);
            lhs_res.bcx.build.CondBr(lhs_res.val, lhs_true_cx.llbb,
3893
                                     rhs_cx.llbb);
3894
            ret join_results(cx, T_bool(),
3895
                             [lhs_true_res, rec(bcx=rhs_bcx with rhs_res)]);
3896
        }
3897
        case (_) {
3898
            // Remaining cases are eager:
3899

3900
            auto lhs = trans_expr(cx, a);
3901
            auto lhty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, a);
3902
            lhs = autoderef(lhs.bcx, lhs.val, lhty);
3903
            auto rhs = trans_expr(lhs.bcx, b);
3904
            auto rhty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, b);
3905
            rhs = autoderef(rhs.bcx, rhs.val, rhty);
3906
            ret trans_eager_binop(rhs.bcx, op,
3907 3908
                                  autoderefed_ty(cx.fcx.lcx.ccx, lhty),
                                  lhs.val, rhs.val);
3909
        }
3910 3911 3912
    }
}

3913 3914
fn join_results(&@block_ctxt parent_cx, TypeRef t, &vec[result] ins) ->
   result {
3915 3916 3917
    let vec[result] live = [];
    let vec[ValueRef] vals = [];
    let vec[BasicBlockRef] bbs = [];
3918
    for (result r in ins) {
3919
        if (!is_terminated(r.bcx)) {
3920 3921 3922
            live += [r];
            vals += [r.val];
            bbs += [r.bcx.llbb];
3923 3924
        }
    }
3925
    alt (vec::len[result](live)) {
3926 3927 3928 3929
        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.
3930

3931
            assert (vec::len[result](ins) >= 1u);
3932 3933
            ret ins.(0);
        }
3934
        case (_) {/* fall through */ }
3935 3936
    }
    // We have >1 incoming edges. Make a join block and br+phi them into it.
3937

3938
    auto join_cx = new_sub_block_ctxt(parent_cx, "join");
3939
    for (result r in live) { r.bcx.build.Br(join_cx.llbb); }
3940 3941 3942 3943
    auto phi = join_cx.build.Phi(t, vals, bbs);
    ret res(join_cx, phi);
}

3944 3945 3946
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) {
3947
        if (!is_terminated(r.bcx)) { r.bcx.build.Br(out.llbb); }
3948 3949 3950 3951
    }
    ret out;
}

3952
tag out_method { return; save_in(ValueRef); }
3953

3954 3955 3956
fn trans_if(&@block_ctxt cx, &@ast::expr cond, &ast::block thn,
            &option::t[@ast::expr] els, &ast::ann ann, &out_method output) ->
   result {
3957
    auto cond_res = trans_expr(cx, cond);
3958
    auto then_cx = new_scope_block_ctxt(cx, "then");
3959
    auto then_res = trans_block(then_cx, thn, output);
3960
    auto else_cx = new_scope_block_ctxt(cx, "else");
3961 3962
    auto else_res;
    auto expr_llty;
3963
    alt (els) {
3964
        case (some(?elexpr)) {
3965
            alt (elexpr.node) {
3966 3967 3968 3969 3970
                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.
3971 3972 3973 3974

                    let ast::block_ elseif_blk_ =
                        rec(stmts=[], expr=some[@ast::expr](elexpr), a=ann);
                    auto elseif_blk = rec(node=elseif_blk_, span=elexpr.span);
3975
                    else_res = trans_block(else_cx, elseif_blk, output);
3976
                }
3977
                case (ast::expr_block(?blk, _)) {
3978 3979 3980 3981
                    // 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
3982

3983
                    else_res = trans_block(else_cx, blk, output);
3984 3985
                }
            }
3986
            // FIXME: This isn't quite right, particularly re: dynamic types
3987 3988

            auto expr_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann);
3989
            if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, expr_ty)) {
3990
                expr_llty = T_typaram_ptr(cx.fcx.lcx.ccx.tn);
3991
            } else {
3992
                expr_llty = type_of(cx.fcx.lcx.ccx, elexpr.span, expr_ty);
3993
                if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, expr_ty)) {
3994 3995
                    expr_llty = T_ptr(expr_llty);
                }
3996
            }
3997
        }
3998
        case (_) { else_res = res(else_cx, C_nil()); expr_llty = T_nil(); }
3999
    }
4000
    cond_res.bcx.build.CondBr(cond_res.val, then_cx.llbb, else_cx.llbb);
4001
    ret res(join_branches(cx, [then_res, else_res]), C_nil());
4002 4003
}

4004
fn trans_for(&@block_ctxt cx, &@ast::local local, &@ast::expr seq,
4005
             &ast::block body) -> result {
P
Paul Stansifer 已提交
4006
    fn inner(&@block_ctxt cx, @ast::local local, ValueRef curr, ty::t t,
4007
             ast::block body, @block_ctxt outer_next_cx) -> result {
G
Graydon Hoare 已提交
4008
        auto next_cx = new_sub_block_ctxt(cx, "next");
4009
        auto scope_cx =
4010
            new_loop_scope_block_ctxt(cx, option::some[@block_ctxt](next_cx),
4011
                                      outer_next_cx, "for loop scope");
G
Graydon Hoare 已提交
4012 4013
        cx.build.Br(scope_cx.llbb);
        auto local_res = alloc_local(scope_cx, local);
4014
        auto bcx = copy_val(local_res.bcx, INIT, local_res.val, curr, t).bcx;
4015
        scope_cx.cleanups += [clean(bind drop_slot(_, local_res.val, t))];
4016
        bcx = trans_block(bcx, body, return).bcx;
G
Graydon Hoare 已提交
4017 4018 4019
        bcx.build.Br(next_cx.llbb);
        ret res(next_cx, C_nil());
    }
4020
    auto next_cx = new_sub_block_ctxt(cx, "next");
4021
    auto seq_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, seq);
G
Graydon Hoare 已提交
4022
    auto seq_res = trans_expr(cx, seq);
4023 4024
    auto it =
        iter_sequence(seq_res.bcx, seq_res.val, seq_ty,
P
Paul Stansifer 已提交
4025
                      bind inner(_, local, _, _, body, next_cx));
4026 4027
    it.bcx.build.Br(next_cx.llbb);
    ret res(next_cx, it.val);
G
Graydon Hoare 已提交
4028 4029
}

4030 4031 4032 4033 4034

// 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.
4035 4036
fn collect_upvars(&@block_ctxt cx, &ast::block bloc,
                  &ast::def_id initial_decl) -> vec[ast::def_id] {
4037 4038 4039 4040
    type env =
        @rec(mutable vec[ast::def_id] refs,
             hashmap[ast::def_id, ()] decls,
             resolve::def_map def_map);
4041

4042
    fn walk_expr(env e, &@ast::expr expr) {
M
Marijn Haverbeke 已提交
4043
        alt (expr.node) {
4044
            case (ast::expr_path(?path, ?ann)) {
P
Patrick Walton 已提交
4045
                alt (e.def_map.get(ann.id)) {
4046
                    case (ast::def_arg(?did)) {
4047
                        vec::push[ast::def_id](e.refs, did);
M
Marijn Haverbeke 已提交
4048
                    }
4049
                    case (ast::def_local(?did)) {
4050
                        vec::push[ast::def_id](e.refs, did);
M
Marijn Haverbeke 已提交
4051
                    }
4052
                    case (_) { }
M
Marijn Haverbeke 已提交
4053 4054
                }
            }
4055
            case (_) { }
4056 4057
        }
    }
4058 4059
    fn walk_local(env e, &@ast::local local) {
        e.decls.insert(local.node.id, ());
4060
    }
4061
    let vec[ast::def_id] refs = [];
4062
    let hashmap[ast::def_id, ()] decls = new_def_hash[()]();
4063
    decls.insert(initial_decl, ());
4064 4065 4066 4067 4068 4069 4070 4071
    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());
4072
    walk::walk_block(*visitor, bloc);
4073
    // Calculate (refs - decls). This is the set of captured upvars.
4074

4075
    let vec[ast::def_id] result = [];
4076 4077
    for (ast::def_id ref_id_ in e.refs) {
        auto ref_id = ref_id_;
4078
        if (!decls.contains_key(ref_id)) { result += [ref_id]; }
4079 4080 4081 4082
    }
    ret result;
}

4083
fn trans_for_each(&@block_ctxt cx, &@ast::local local, &@ast::expr seq,
4084
                  &ast::block body) -> result {
4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110
    /*
     * 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.

4111
    auto lcx = cx.fcx.lcx;
4112
    // FIXME: possibly support alias-mode here?
4113

4114 4115
    auto decl_ty = node_ann_type(lcx.ccx, local.node.ann);
    auto decl_id = local.node.id;
4116
    auto upvars = collect_upvars(cx, body, decl_id);
4117
    auto upvar_count = vec::len[ast::def_id](upvars);
4118 4119 4120
    auto llbindingsptr;
    if (upvar_count > 0u) {
        // Gather up the upvars.
4121

4122 4123
        let vec[ValueRef] llbindings = [];
        let vec[TypeRef] llbindingtys = [];
4124
        for (ast::def_id did in upvars) {
4125 4126
            auto llbinding;
            alt (cx.fcx.lllocals.find(did)) {
4127
                case (none) {
4128 4129 4130 4131 4132 4133
                    alt (cx.fcx.llupvars.find(did)) {
                        case (none[ValueRef]) {
                            llbinding = cx.fcx.llargs.get(did);
                        }
                        case (some[ValueRef](?llval)) { llbinding = llval; }
                    }
4134
                }
4135
                case (some(?llval)) { llbinding = llval; }
4136
            }
4137 4138
            llbindings += [llbinding];
            llbindingtys += [val_ty(llbinding)];
4139 4140
        }
        // Create an array of bindings and copy in aliases to the upvars.
4141

4142
        llbindingsptr = alloca(cx, T_struct(llbindingtys));
4143 4144
        auto i = 0u;
        while (i < upvar_count) {
4145 4146
            auto llbindingptr =
                cx.build.GEP(llbindingsptr, [C_int(0), C_int(i as int)]);
4147 4148 4149 4150 4151
            cx.build.Store(llbindings.(i), llbindingptr);
            i += 1u;
        }
    } else {
        // Null bindings.
4152

4153
        llbindingsptr = C_null(T_ptr(T_i8()));
4154
    }
4155
    // Create an environment and populate it with the bindings.
4156

4157
    auto tydesc_count = vec::len[ValueRef](cx.fcx.lltydescs);
4158 4159 4160
    auto llenvptrty =
        T_closure_ptr(lcx.ccx.tn, T_ptr(T_nil()), val_ty(llbindingsptr),
                      tydesc_count);
4161
    auto llenvptr = alloca(cx, llvm::LLVMGetElementType(llenvptrty));
4162 4163 4164
    auto llbindingsptrptr =
        cx.build.GEP(llenvptr,
                     [C_int(0), C_int(abi::box_rc_field_body), C_int(2)]);
4165
    cx.build.Store(llbindingsptr, llbindingsptrptr);
4166 4167
    // Copy in our type descriptors, in case the iterator body needs to refer
    // to them.
4168 4169 4170 4171 4172

    auto lltydescsptr =
        cx.build.GEP(llenvptr,
                     [C_int(0), C_int(abi::box_rc_field_body),
                      C_int(abi::closure_elt_ty_params)]);
4173 4174
    auto i = 0u;
    while (i < tydesc_count) {
4175 4176
        auto lltydescptr =
            cx.build.GEP(lltydescsptr, [C_int(0), C_int(i as int)]);
4177 4178 4179
        cx.build.Store(cx.fcx.lltydescs.(i), lltydescptr);
        i += 1u;
    }
4180 4181
    // Step 2: Declare foreach body function.

4182 4183
    let str s =
        mangle_internal_name_by_path_and_seq(lcx.ccx, lcx.path, "foreach");
4184 4185 4186 4187 4188 4189
    // 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.

4190
    auto iter_body_llty =
4191
        type_of_fn_full(lcx.ccx, cx.sp, ast::proto_fn, none[TypeRef],
4192
                        [rec(mode=ty::mo_alias(false), ty=decl_ty)],
4193
                        ty::mk_nil(lcx.ccx.tcx), 0u);
4194 4195
    let ValueRef lliterbody =
        decl_internal_fastcall_fn(lcx.ccx.llmod, s, iter_body_llty);
4196
    auto fcx = new_fn_ctxt(lcx, cx.sp, lliterbody);
4197
    auto copy_args_bcx = new_raw_block_ctxt(fcx, fcx.llcopyargs);
4198
    // Populate the upvars from the environment.
4199 4200 4201

    auto llremoteenvptr =
        copy_args_bcx.build.PointerCast(fcx.llenv, llenvptrty);
4202
    auto llremotebindingsptrptr =
4203
        copy_args_bcx.build.GEP(llremoteenvptr,
4204 4205
                                [C_int(0), C_int(abi::box_rc_field_body),
                                 C_int(abi::closure_elt_bindings)]);
4206 4207
    auto llremotebindingsptr =
        copy_args_bcx.build.Load(llremotebindingsptrptr);
4208
    i = 0u;
4209 4210
    while (i < upvar_count) {
        auto upvar_id = upvars.(i);
4211 4212
        auto llupvarptrptr =
            copy_args_bcx.build.GEP(llremotebindingsptr,
4213
                                    [C_int(0), C_int(i as int)]);
4214
        auto llupvarptr = copy_args_bcx.build.Load(llupvarptrptr);
4215 4216 4217
        fcx.llupvars.insert(upvar_id, llupvarptr);
        i += 1u;
    }
4218
    // Populate the type parameters from the environment.
4219

4220
    auto llremotetydescsptr =
4221
        copy_args_bcx.build.GEP(llremoteenvptr,
4222 4223
                                [C_int(0), C_int(abi::box_rc_field_body),
                                 C_int(abi::closure_elt_ty_params)]);
4224 4225
    i = 0u;
    while (i < tydesc_count) {
4226
        auto llremotetydescptr =
4227 4228
            copy_args_bcx.build.GEP(llremotetydescsptr,
                                    [C_int(0), C_int(i as int)]);
4229
        auto llremotetydesc = copy_args_bcx.build.Load(llremotetydescptr);
4230
        fcx.lltydescs += [llremotetydesc];
4231 4232
        i += 1u;
    }
4233
    // Add an upvar for the loop variable alias.
4234

4235
    fcx.llupvars.insert(decl_id, llvm::LLVMGetParam(fcx.llfn, 3u));
4236 4237
    auto bcx = new_top_block_ctxt(fcx);
    auto lltop = bcx.llbb;
4238
    auto r = trans_block(bcx, body, return);
4239
    finish_fn(fcx, lltop);
4240
    r.bcx.build.RetVoid();
4241

4242
    // Step 3: Call iter passing [lliterbody, llenv], plus other args.
4243
    alt (seq.node) {
4244
        case (ast::expr_call(?f, ?args, ?ann)) {
4245 4246 4247
            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)]);
4248
            cx.build.Store(lliterbody, code_cell);
4249 4250 4251 4252 4253
            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));
4254
            cx.build.Store(llenvblobptr, env_cell);
4255
            // log "lliterbody: " + val_str(lcx.ccx.tn, lliterbody);
4256 4257 4258

            r =
                trans_call(cx, f, some[ValueRef](cx.build.Load(pair)), args,
4259
                           ann);
4260
            ret res(r.bcx, C_nil());
4261 4262
        }
    }
4263 4264
}

4265 4266
fn trans_while(&@block_ctxt cx, &@ast::expr cond, &ast::block body) ->
   result {
4267
    auto cond_cx = new_scope_block_ctxt(cx, "while cond");
4268
    auto next_cx = new_sub_block_ctxt(cx, "next");
4269 4270 4271
    auto body_cx =
        new_loop_scope_block_ctxt(cx, option::none[@block_ctxt], next_cx,
                                  "while loop body");
4272
    auto body_res = trans_block(body_cx, body, return);
4273 4274
    auto cond_res = trans_expr(cond_cx, cond);
    body_res.bcx.build.Br(cond_cx.llbb);
4275 4276
    auto cond_bcx = trans_block_cleanups(cond_res.bcx, cond_cx);
    cond_bcx.build.CondBr(cond_res.val, body_cx.llbb, next_cx.llbb);
4277
    cx.build.Br(cond_cx.llbb);
4278 4279 4280
    ret res(next_cx, C_nil());
}

4281 4282
fn trans_do_while(&@block_ctxt cx, &ast::block body, &@ast::expr cond) ->
   result {
4283
    auto next_cx = new_sub_block_ctxt(cx, "next");
4284 4285 4286
    auto body_cx =
        new_loop_scope_block_ctxt(cx, option::none[@block_ctxt], next_cx,
                                  "do-while loop body");
4287
    auto body_res = trans_block(body_cx, body, return);
4288
    auto cond_res = trans_expr(body_res.bcx, cond);
4289
    cond_res.bcx.build.CondBr(cond_res.val, body_cx.llbb, next_cx.llbb);
4290
    cx.build.Br(body_cx.llbb);
4291 4292 4293
    ret res(next_cx, body_res.val);
}

P
Patrick Walton 已提交
4294

4295
// Pattern matching translation
4296
fn trans_pat_match(&@block_ctxt cx, &@ast::pat pat, ValueRef llval,
G
Graydon Hoare 已提交
4297
                   &@block_ctxt next_cx) -> result {
P
Patrick Walton 已提交
4298
    alt (pat.node) {
4299 4300 4301
        case (ast::pat_wild(_)) { ret res(cx, llval); }
        case (ast::pat_bind(_, _, _)) { ret res(cx, llval); }
        case (ast::pat_lit(?lt, ?ann)) {
4302
            auto lllit = trans_lit(cx.fcx.lcx.ccx, *lt, ann);
4303
            auto lltype = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann);
4304
            auto lleq = trans_compare(cx, ast::eq, lltype, llval, lllit);
4305 4306
            auto matched_cx = new_sub_block_ctxt(lleq.bcx, "matched_cx");
            lleq.bcx.build.CondBr(lleq.val, matched_cx.llbb, next_cx.llbb);
4307 4308
            ret res(matched_cx, llval);
        }
4309
        case (ast::pat_tag(?id, ?subpats, ?ann)) {
4310 4311 4312 4313
            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)]);
4314
            auto lldiscrim = cx.build.Load(lldiscrimptr);
4315 4316
            auto vdef =
                ast::variant_def_ids(cx.fcx.lcx.ccx.tcx.def_map.get(ann.id));
P
Patrick Walton 已提交
4317
            auto variant_tag = 0;
4318
            auto variants = ty::tag_variants(cx.fcx.lcx.ccx.tcx, vdef._0);
P
Patrick Walton 已提交
4319
            auto i = 0;
4320
            for (ty::variant_info v in variants) {
4321
                auto this_variant_id = v.id;
4322
                if (vdef._1._0 == this_variant_id._0 &&
4323
                        vdef._1._1 == this_variant_id._1) {
P
Patrick Walton 已提交
4324 4325 4326 4327 4328
                    variant_tag = i;
                }
                i += 1;
            }
            auto matched_cx = new_sub_block_ctxt(cx, "matched_cx");
4329 4330 4331
            auto lleq =
                cx.build.ICmp(lib::llvm::LLVMIntEQ, lldiscrim,
                              C_int(variant_tag));
P
Patrick Walton 已提交
4332
            cx.build.CondBr(lleq, matched_cx.llbb, next_cx.llbb);
4333
            auto ty_params = ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx, ann);
4334
            if (vec::len[@ast::pat](subpats) > 0u) {
4335 4336
                auto llblobptr =
                    matched_cx.build.GEP(lltagptr, [C_int(0), C_int(1)]);
P
Patrick Walton 已提交
4337
                auto i = 0;
4338
                for (@ast::pat subpat in subpats) {
4339 4340 4341
                    auto rslt =
                        GEP_tag(matched_cx, llblobptr, vdef._0, vdef._1,
                                ty_params, i);
4342 4343
                    auto llsubvalptr = rslt.val;
                    matched_cx = rslt.bcx;
4344 4345 4346 4347 4348 4349
                    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 已提交
4350
                    matched_cx = subpat_res.bcx;
4351
                    i += 1;
P
Patrick Walton 已提交
4352 4353 4354 4355 4356 4357 4358
                }
            }
            ret res(matched_cx, llval);
        }
    }
}

4359 4360
fn trans_pat_binding(&@block_ctxt cx, &@ast::pat pat, ValueRef llval,
                     bool bind_alias) -> result {
P
Patrick Walton 已提交
4361
    alt (pat.node) {
4362 4363 4364
        case (ast::pat_wild(_)) { ret res(cx, llval); }
        case (ast::pat_lit(_, _)) { ret res(cx, llval); }
        case (ast::pat_bind(?id, ?def_id, ?ann)) {
4365 4366 4367 4368 4369 4370 4371 4372
            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;
4373
                maybe_name_value(cx.fcx.lcx.ccx, dst, id);
4374
                bcx.fcx.lllocals.insert(def_id, dst);
4375
                bcx.cleanups += [clean(bind drop_slot(_, dst, t))];
4376
                ret copy_val(bcx, INIT, dst, llval, t);
4377
            }
P
Patrick Walton 已提交
4378
        }
4379
        case (ast::pat_tag(_, ?subpats, ?ann)) {
4380
            if (vec::len[@ast::pat](subpats) == 0u) { ret res(cx, llval); }
4381 4382
            // Get the appropriate variant for this tag.

4383 4384 4385 4386 4387
            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));
4388
            auto llblobptr = cx.build.GEP(lltagptr, [C_int(0), C_int(1)]);
4389
            auto ty_param_substs =
4390
                ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx, ann);
P
Patrick Walton 已提交
4391 4392
            auto this_cx = cx;
            auto i = 0;
4393
            for (@ast::pat subpat in subpats) {
4394 4395 4396
                auto rslt =
                    GEP_tag(this_cx, llblobptr, vdef._0, vdef._1,
                            ty_param_substs, i);
4397
                this_cx = rslt.bcx;
4398 4399
                auto subpat_res =
                    trans_pat_binding(this_cx, subpat, rslt.val, true);
P
Patrick Walton 已提交
4400
                this_cx = subpat_res.bcx;
4401
                i += 1;
P
Patrick Walton 已提交
4402 4403 4404 4405 4406 4407
            }
            ret res(this_cx, llval);
        }
    }
}

4408 4409
fn trans_alt(&@block_ctxt cx, &@ast::expr expr, &vec[ast::arm] arms,
             &ast::ann ann, &out_method output) -> result {
P
Patrick Walton 已提交
4410 4411
    auto expr_res = trans_expr(cx, expr);
    auto this_cx = expr_res.bcx;
4412
    let vec[result] arm_results = [];
4413
    for (ast::arm arm in arms) {
P
Patrick Walton 已提交
4414
        auto next_cx = new_sub_block_ctxt(expr_res.bcx, "next");
4415 4416
        auto match_res =
            trans_pat_match(this_cx, arm.pat, expr_res.val, next_cx);
P
Patrick Walton 已提交
4417 4418
        auto binding_cx = new_scope_block_ctxt(match_res.bcx, "binding");
        match_res.bcx.build.Br(binding_cx.llbb);
4419 4420
        auto binding_res =
            trans_pat_binding(binding_cx, arm.pat, expr_res.val, false);
4421
        auto block_res = trans_block(binding_res.bcx, arm.block, output);
4422
        arm_results += [block_res];
P
Patrick Walton 已提交
4423 4424
        this_cx = next_cx;
    }
4425
    auto default_cx = this_cx;
4426 4427 4428
    auto default_res =
        trans_fail(default_cx, some[common::span](expr.span),
                   "non-exhaustive match failure");
4429
    // FIXME: This isn't quite right, particularly re: dynamic types
4430

4431
    auto expr_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann);
4432
    auto expr_llty;
4433
    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, expr_ty)) {
4434
        expr_llty = T_typaram_ptr(cx.fcx.lcx.ccx.tn);
4435
    } else {
4436
        expr_llty = type_of(cx.fcx.lcx.ccx, expr.span, expr_ty);
4437
        if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, expr_ty)) {
4438 4439 4440
            expr_llty = T_ptr(expr_llty);
        }
    }
4441
    ret res(join_branches(cx, arm_results), C_nil());
P
Patrick Walton 已提交
4442 4443
}

4444 4445 4446 4447
type generic_info =
    rec(ty::t item_type,
        vec[option::t[@tydesc_info]] static_tis,
        vec[ValueRef] tydescs);
4448

4449 4450 4451 4452 4453 4454
type lval_result =
    rec(result res,
        bool is_mem,
        option::t[generic_info] generic,
        option::t[ValueRef] llobj,
        option::t[ty::t] method_ty);
4455

G
Graydon Hoare 已提交
4456
fn lval_mem(&@block_ctxt cx, ValueRef val) -> lval_result {
4457 4458
    ret rec(res=res(cx, val),
            is_mem=true,
4459
            generic=none[generic_info],
4460
            llobj=none[ValueRef],
4461
            method_ty=none[ty::t]);
4462 4463
}

G
Graydon Hoare 已提交
4464
fn lval_val(&@block_ctxt cx, ValueRef val) -> lval_result {
4465 4466
    ret rec(res=res(cx, val),
            is_mem=false,
4467
            generic=none[generic_info],
4468
            llobj=none[ValueRef],
4469
            method_ty=none[ty::t]);
4470
}
4471

4472 4473
fn trans_external_path(&@block_ctxt cx, &ast::def_id did,
                       &ty::ty_param_count_and_ty tpt) -> lval_result {
4474
    auto lcx = cx.fcx.lcx;
4475
    auto name = creader::get_symbol(lcx.ccx.sess, did);
4476 4477 4478
    auto v =
        get_extern_const(lcx.ccx.externs, lcx.ccx.llmod, name,
                         type_of_ty_param_count_and_ty(lcx, cx.sp, tpt));
4479 4480 4481
    ret lval_val(cx, v);
}

4482 4483
fn lval_generic_fn(&@block_ctxt cx, &ty::ty_param_count_and_ty tpt,
                   &ast::def_id fn_id, &ast::ann ann) -> lval_result {
4484
    auto lv;
4485
    if (cx.fcx.lcx.ccx.sess.get_targ_crate_num() == fn_id._0) {
4486
        // Internal reference.
4487

4488
        assert (cx.fcx.lcx.ccx.fn_pairs.contains_key(fn_id));
4489
        lv = lval_val(cx, cx.fcx.lcx.ccx.fn_pairs.get(fn_id));
4490 4491
    } else {
        // External reference.
4492

4493
        lv = trans_external_path(cx, fn_id, tpt);
4494
    }
4495 4496
    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);
4497
    if (vec::len[ty::t](tys) != 0u) {
4498
        auto bcx = lv.res.bcx;
4499 4500
        let vec[ValueRef] tydescs = [];
        let vec[option::t[@tydesc_info]] tis = [];
4501
        for (ty::t t in tys) {
4502
            // TODO: Doesn't always escape.
4503

4504 4505
            auto ti = none[@tydesc_info];
            auto td = get_tydesc(bcx, t, true, ti);
4506
            tis += [ti];
4507
            bcx = td.bcx;
4508
            vec::push[ValueRef](tydescs, td.val);
4509
        }
4510 4511 4512 4513
        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);
4514 4515 4516 4517
    }
    ret lv;
}

4518
fn lookup_discriminant(&@local_ctxt lcx, &ast::def_id tid, &ast::def_id vid)
4519
   -> ValueRef {
4520
    alt (lcx.ccx.discrims.find(vid)) {
4521
        case (none) {
4522
            // It's an external discriminant that we haven't seen yet.
4523

4524
            assert (lcx.ccx.sess.get_targ_crate_num() != vid._0);
4525
            auto sym = creader::get_symbol(lcx.ccx.sess, vid);
4526 4527 4528 4529 4530
            auto gvar =
                llvm::LLVMAddGlobal(lcx.ccx.llmod, T_int(), str::buf(sym));
            llvm::LLVMSetLinkage(gvar,
                                 lib::llvm::LLVMExternalLinkage as
                                     llvm::Linkage);
4531
            llvm::LLVMSetGlobalConstant(gvar, True);
4532
            lcx.ccx.discrims.insert(vid, gvar);
4533 4534
            ret gvar;
        }
4535
        case (some(?llval)) { ret llval; }
4536 4537 4538
    }
}

4539
fn trans_path(&@block_ctxt cx, &ast::path p, &ast::ann ann) -> lval_result {
P
Patrick Walton 已提交
4540
    alt (cx.fcx.lcx.ccx.tcx.def_map.get(ann.id)) {
4541
        case (ast::def_arg(?did)) {
4542
            alt (cx.fcx.llargs.find(did)) {
4543
                case (none) {
4544 4545
                    assert (cx.fcx.llupvars.contains_key(did));
                    ret lval_mem(cx, cx.fcx.llupvars.get(did));
G
Graydon Hoare 已提交
4546
                }
4547
                case (some(?llval)) { ret lval_mem(cx, llval); }
4548 4549
            }
        }
4550
        case (ast::def_local(?did)) {
4551
            alt (cx.fcx.lllocals.find(did)) {
4552
                case (none) {
4553 4554
                    assert (cx.fcx.llupvars.contains_key(did));
                    ret lval_mem(cx, cx.fcx.llupvars.get(did));
4555
                }
4556
                case (some(?llval)) { ret lval_mem(cx, llval); }
4557 4558
            }
        }
4559
        case (ast::def_binding(?did)) {
4560 4561 4562
            assert (cx.fcx.lllocals.contains_key(did));
            ret lval_mem(cx, cx.fcx.lllocals.get(did));
        }
4563
        case (ast::def_obj_field(?did)) {
4564 4565 4566
            assert (cx.fcx.llobjfields.contains_key(did));
            ret lval_mem(cx, cx.fcx.llobjfields.get(did));
        }
4567
        case (ast::def_fn(?did)) {
4568
            auto tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, did);
4569 4570
            ret lval_generic_fn(cx, tyt, did, ann);
        }
4571
        case (ast::def_obj(?did)) {
4572
            auto tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, did);
4573 4574
            ret lval_generic_fn(cx, tyt, did, ann);
        }
4575
        case (ast::def_variant(?tid, ?vid)) {
4576
            auto v_tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, vid);
4577
            alt (ty::struct(cx.fcx.lcx.ccx.tcx, v_tyt._1)) {
4578
                case (ty::ty_fn(_, _, _, _, _)) {
4579
                    // N-ary variant.
4580

4581
                    ret lval_generic_fn(cx, v_tyt, vid, ann);
4582
                }
4583 4584
                case (_) {
                    // Nullary variant.
4585

4586 4587 4588 4589 4590 4591 4592
                    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;
4593 4594
                    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, tag_ty))
                       {
4595 4596
                        lltagty = T_opaque_tag(cx.fcx.lcx.ccx.tn);
                    } else {
4597
                        lltagty = type_of(cx.fcx.lcx.ccx, p.span, tag_ty);
4598
                    }
4599 4600 4601 4602 4603 4604 4605
                    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);
4606
                    ret lval_val(alloc_result.bcx, lltagptr);
G
Graydon Hoare 已提交
4607 4608 4609
                }
            }
        }
4610
        case (ast::def_const(?did)) {
4611
            // TODO: externals
4612

4613 4614 4615
            assert (cx.fcx.lcx.ccx.consts.contains_key(did));
            ret lval_mem(cx, cx.fcx.lcx.ccx.consts.get(did));
        }
4616
        case (ast::def_native_fn(?did)) {
4617
            auto tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, did);
4618 4619 4620
            ret lval_generic_fn(cx, tyt, did, ann);
        }
        case (_) {
4621
            cx.fcx.lcx.ccx.sess.span_unimpl(cx.sp, "def variant in trans");
4622 4623 4624 4625
        }
    }
}

4626
fn trans_field(&@block_ctxt cx, &span sp, ValueRef v, &ty::t t0,
4627
               &ast::ident field, &ast::ann ann) -> lval_result {
4628
    auto r = autoderef(cx, v, t0);
4629
    auto t = autoderefed_ty(cx.fcx.lcx.ccx, t0);
4630 4631 4632
    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);
4633
            auto v = GEP_tup_like(r.bcx, t, r.val, [0, ix as int]);
4634
            ret lval_mem(v.bcx, v.val);
4635
        }
4636
        case (ty::ty_rec(?fields)) {
4637 4638
            let uint ix =
                ty::field_idx(cx.fcx.lcx.ccx.sess, sp, field, fields);
4639
            auto v = GEP_tup_like(r.bcx, t, r.val, [0, ix as int]);
4640
            ret lval_mem(v.bcx, v.val);
4641
        }
4642
        case (ty::ty_obj(?methods)) {
4643 4644 4645 4646 4647
            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)]);
4648
            vtbl = r.bcx.build.Load(vtbl);
4649
            // +1 because slot #0 contains the destructor
4650

4651
            auto v = r.bcx.build.GEP(vtbl, [C_int(0), C_int(ix + 1u as int)]);
4652
            auto lvo = lval_mem(r.bcx, v);
4653 4654 4655
            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)
4656
                    with lvo);
4657
        }
4658 4659 4660
        case (_) {
            cx.fcx.lcx.ccx.sess.unimpl("field variant in trans_field");
        }
4661 4662 4663
    }
}

4664 4665
fn trans_index(&@block_ctxt cx, &span sp, &@ast::expr base, &@ast::expr idx,
               &ast::ann ann) -> lval_result {
4666
    // Is this an interior vector?
4667

4668 4669
    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);
4670 4671
    auto is_interior =
        ty::sequence_is_interior(cx.fcx.lcx.ccx.tcx, base_ty_no_boxes);
G
Graydon Hoare 已提交
4672
    auto lv = trans_expr(cx, base);
4673
    lv = autoderef(lv.bcx, lv.val, base_ty);
G
Graydon Hoare 已提交
4674 4675
    auto ix = trans_expr(lv.bcx, idx);
    auto v = lv.val;
4676
    auto bcx = ix.bcx;
4677
    // Cast to an LLVM integer. Rust is less strict than LLVM in this regard.
4678

4679
    auto ix_val;
4680 4681
    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());
4682 4683 4684 4685
    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());
4686
    } else { ix_val = ix.val; }
4687
    auto unit_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
4688
    auto unit_sz = size_of(bcx, unit_ty);
4689
    bcx = unit_sz.bcx;
4690
    maybe_name_value(cx.fcx.lcx.ccx, unit_sz.val, "unit_sz");
4691
    auto scaled_ix = bcx.build.Mul(ix_val, unit_sz.val);
4692
    maybe_name_value(cx.fcx.lcx.ccx, scaled_ix, "scaled_ix");
4693 4694
    auto interior_len_and_data;
    if (is_interior) {
4695
        auto rslt = ivec::get_len_and_data(bcx, v, unit_ty);
4696 4697
        interior_len_and_data = some(tup(rslt._0, rslt._1));
        bcx = rslt._2;
4698
    } else { interior_len_and_data = none; }
4699 4700 4701 4702 4703 4704 4705 4706
    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);
        }
    }
4707
    auto bounds_check = bcx.build.ICmp(lib::llvm::LLVMIntULT, scaled_ix, lim);
4708 4709 4710
    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);
4711 4712
    // fail: bad bounds check.

4713 4714
    auto fail_res =
        trans_fail(fail_cx, some[common::span](sp), "bounds check");
4715 4716 4717 4718
    auto body;
    alt (interior_len_and_data) {
        case (some(?lad)) { body = lad._1; }
        case (none) {
4719 4720 4721 4722
            body =
                next_cx.build.GEP(v,
                                  [C_int(0), C_int(abi::vec_elt_data),
                                   C_int(0)]);
4723 4724
        }
    }
4725
    auto elt;
4726
    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, unit_ty)) {
4727 4728
        body = next_cx.build.PointerCast(body, T_ptr(T_i8()));
        elt = next_cx.build.GEP(body, [scaled_ix]);
4729
    } else {
4730
        elt = next_cx.build.GEP(body, [ix_val]);
4731
        // We're crossing a box boundary here, so we may need to pointer cast.
4732

4733
        auto llunitty = type_of(next_cx.fcx.lcx.ccx, sp, unit_ty);
4734
        elt = next_cx.build.PointerCast(elt, T_ptr(llunitty));
4735
    }
4736
    ret lval_mem(next_cx, elt);
4737 4738
}

4739

4740 4741 4742
// 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).
4743
fn trans_lval(&@block_ctxt cx, &@ast::expr e) -> lval_result {
4744
    alt (e.node) {
4745
        case (ast::expr_path(?p, ?ann)) { ret trans_path(cx, p, ann); }
4746
        case (ast::expr_field(?base, ?ident, ?ann)) {
4747
            auto r = trans_expr(cx, base);
4748
            auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, base);
4749
            ret trans_field(r.bcx, e.span, r.val, t, ident, ann);
4750
        }
4751
        case (ast::expr_index(?base, ?idx, ?ann)) {
4752 4753
            ret trans_index(cx, e.span, base, idx, ann);
        }
4754 4755
        case (ast::expr_unary(?unop, ?base, ?ann)) {
            assert (unop == ast::deref);
4756
            auto sub = trans_expr(cx, base);
4757 4758 4759
            auto val =
                sub.bcx.build.GEP(sub.val,
                                  [C_int(0), C_int(abi::box_rc_field_body)]);
4760 4761
            ret lval_mem(sub.bcx, val);
        }
4762
        case (ast::expr_self_method(?ident, ?ann)) {
4763
            alt ({ cx.fcx.llself }) {
L
Lindsey Kuper 已提交
4764
                case (some(?pair)) {
4765 4766
                    auto r = pair.v;
                    auto t = pair.t;
4767 4768 4769 4770 4771
                    ret trans_field(cx, e.span, r, t, ident, ann);
                }
                case (_) {
                    // Shouldn't happen.

4772 4773 4774
                    cx.fcx.lcx.ccx.sess.bug("trans_lval called on " +
                                                "expr_self_method in " +
                                                "a context without llself");
4775
                }
4776 4777
            }
        }
4778
        case (_) {
4779 4780 4781 4782 4783
            ret rec(res=trans_expr(cx, e),
                    is_mem=false,
                    generic=none,
                    llobj=none,
                    method_ty=none);
4784
        }
G
Graydon Hoare 已提交
4785 4786 4787
    }
}

G
Graydon Hoare 已提交
4788
fn int_cast(&@block_ctxt bcx, TypeRef lldsttype, TypeRef llsrctype,
4789
            ValueRef llsrc, bool signed) -> ValueRef {
4790 4791
    if (llvm::LLVMGetIntTypeWidth(lldsttype) >
            llvm::LLVMGetIntTypeWidth(llsrctype)) {
4792 4793
        if (signed) {
            // Widening signed cast.
4794

4795 4796 4797
            ret bcx.build.SExtOrBitCast(llsrc, lldsttype);
        }
        // Widening unsigned cast.
4798

4799 4800 4801 4802 4803
        ret bcx.build.ZExtOrBitCast(llsrc, lldsttype);
    }
    ret bcx.build.TruncOrBitCast(llsrc, lldsttype);
}

4804
fn trans_cast(&@block_ctxt cx, &@ast::expr e, &ast::ann ann) -> result {
4805 4806
    auto e_res = trans_expr(cx, e);
    auto llsrctype = val_ty(e_res.val);
4807
    auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
4808
    auto lldsttype = type_of(cx.fcx.lcx.ccx, e.span, t);
4809
    if (!ty::type_is_fp(cx.fcx.lcx.ccx.tcx, t)) {
4810

4811
        // TODO: native-to-native casts
4812
        if (ty::type_is_native(cx.fcx.lcx.ccx.tcx,
4813 4814 4815 4816
                               ty::expr_ty(cx.fcx.lcx.ccx.tcx, e))) {
            e_res =
                res(e_res.bcx,
                    e_res.bcx.build.PtrToInt(e_res.val, lldsttype));
4817
        } else if (ty::type_is_native(cx.fcx.lcx.ccx.tcx, t)) {
4818 4819 4820
            e_res =
                res(e_res.bcx,
                    e_res.bcx.build.IntToPtr(e_res.val, lldsttype));
4821
        } else {
4822 4823 4824 4825
            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)));
4826
        }
4827
    } else { cx.fcx.lcx.ccx.sess.unimpl("fp cast"); }
4828 4829 4830
    ret e_res;
}

4831 4832 4833
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,
4834
                    uint ty_param_count) -> ValueRef {
4835
    // Construct a thunk-call with signature incoming_fty, and that copies
4836
    // args forward into a call to outgoing_fty:
4837

4838 4839 4840 4841 4842 4843
    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);
4844
    auto fcx = new_fn_ctxt(cx, sp, llthunk);
4845
    auto bcx = new_top_block_ctxt(fcx);
4846
    auto lltop = bcx.llbb;
4847
    auto llclosure_ptr_ty =
4848
        type_of(cx.ccx, sp, ty::mk_imm_box(cx.ccx.tcx, closure_ty));
4849
    auto llclosure = bcx.build.PointerCast(fcx.llenv, llclosure_ptr_ty);
4850 4851 4852
    auto lltarget =
        GEP_tup_like(bcx, closure_ty, llclosure,
                     [0, abi::box_rc_field_body, abi::closure_elt_target]);
4853
    bcx = lltarget.bcx;
4854 4855
    auto lltargetclosure =
        bcx.build.GEP(lltarget.val, [C_int(0), C_int(abi::fn_field_box)]);
4856
    lltargetclosure = bcx.build.Load(lltargetclosure);
4857 4858
    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);
4859
    auto llretptr = fcx.llretptr;
4860
    if (ty::type_has_dynamic_size(cx.ccx.tcx, outgoing_ret_ty)) {
4861
        llretptr = bcx.build.PointerCast(llretptr, T_typaram_ptr(cx.ccx.tn));
4862
    }
4863
    let vec[ValueRef] llargs = [llretptr, fcx.lltaskptr, lltargetclosure];
4864
    // Copy in the type parameters.
4865

4866 4867 4868
    let uint i = 0u;
    while (i < ty_param_count) {
        auto lltyparam_ptr =
4869
            GEP_tup_like(bcx, closure_ty, llclosure,
4870 4871
                         [0, abi::box_rc_field_body,
                          abi::closure_elt_ty_params, i as int]);
4872
        bcx = lltyparam_ptr.bcx;
4873
        auto td = bcx.build.Load(lltyparam_ptr.val);
4874 4875
        llargs += [td];
        fcx.lltydescs += [td];
4876 4877
        i += 1u;
    }
4878
    let uint a = 3u; // retptr, task ptr, env come first
4879

4880
    let int b = 0;
4881
    let uint outgoing_arg_index = 0u;
4882
    let vec[TypeRef] llout_arg_tys =
4883
        type_of_explicit_args(cx.ccx, sp, outgoing_args);
4884
    for (option::t[@ast::expr] arg in args) {
4885 4886
        auto out_arg = outgoing_args.(outgoing_arg_index);
        auto llout_arg_ty = llout_arg_tys.(outgoing_arg_index);
4887
        alt (arg) {
4888 4889 4890 4891
            case (
                 // Arg provided at binding time; thunk copies it from
                 // closure.
                 some(?e)) {
4892
                auto e_ty = ty::expr_ty(cx.ccx.tcx, e);
4893 4894
                auto bound_arg =
                    GEP_tup_like(bcx, closure_ty, llclosure,
4895 4896
                                 [0, abi::box_rc_field_body,
                                  abi::closure_elt_bindings, b]);
4897
                bcx = bound_arg.bcx;
4898
                auto val = bound_arg.val;
4899
                if (out_arg.mode == ty::mo_val) {
4900 4901 4902 4903 4904 4905 4906
                    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);
                    }
4907
                } else if (ty::type_contains_params(cx.ccx.tcx, out_arg.ty)) {
4908
                    assert (out_arg.mode != ty::mo_val);
4909 4910
                    val = bcx.build.PointerCast(val, llout_arg_ty);
                }
4911
                llargs += [val];
4912 4913
                b += 1;
            }
4914 4915 4916
            case (
                 // Arg will be provided when the thunk is invoked.
                 none) {
4917 4918
                let ValueRef passed_arg = llvm::LLVMGetParam(llthunk, a);
                if (ty::type_contains_params(cx.ccx.tcx, out_arg.ty)) {
4919
                    assert (out_arg.mode != ty::mo_val);
4920 4921
                    passed_arg =
                        bcx.build.PointerCast(passed_arg, llout_arg_ty);
4922
                }
4923
                llargs += [passed_arg];
4924 4925 4926
                a += 1u;
            }
        }
4927
        outgoing_arg_index += 1u;
4928 4929
    }
    // FIXME: turn this call + ret into a tail call.
4930

4931 4932
    auto lltargetfn =
        bcx.build.GEP(lltarget.val, [C_int(0), C_int(abi::fn_field_code)]);
4933 4934 4935
    // Cast the outgoing function to the appropriate type (see the comments in
    // trans_bind below for why this is necessary).

4936 4937 4938 4939 4940
    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)));
4941 4942
    lltargetfn = bcx.build.Load(lltargetfn);
    auto r = bcx.build.FastCall(lltargetfn, llargs);
4943
    bcx.build.RetVoid();
4944
    finish_fn(fcx, lltop);
4945 4946 4947
    ret llthunk;
}

4948
fn trans_bind(&@block_ctxt cx, &@ast::expr f,
4949
              &vec[option::t[@ast::expr]] args, &ast::ann ann) -> result {
4950 4951
    auto f_res = trans_lval(cx, f);
    if (f_res.is_mem) {
4952
        cx.fcx.lcx.ccx.sess.unimpl("re-binding existing function");
4953
    } else {
4954
        let vec[@ast::expr] bound = [];
4955
        for (option::t[@ast::expr] argopt in args) {
4956
            alt (argopt) {
4957 4958
                case (none) { }
                case (some(?e)) { vec::push[@ast::expr](bound, e); }
4959 4960
            }
        }
4961
        // Figure out which tydescs we need to pass, if any.
4962

4963
        let ty::t outgoing_fty;
B
Brian Anderson 已提交
4964
        let vec[ValueRef] lltydescs;
4965
        alt (f_res.generic) {
4966
            case (none) {
4967
                outgoing_fty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, f);
4968
                lltydescs = [];
4969
            }
4970
            case (some(?ginfo)) {
4971
                lazily_emit_all_generic_info_tydesc_glues(cx, ginfo);
4972 4973 4974 4975
                outgoing_fty = ginfo.item_type;
                lltydescs = ginfo.tydescs;
            }
        }
4976 4977
        auto ty_param_count = vec::len[ValueRef](lltydescs);
        if (vec::len[@ast::expr](bound) == 0u && ty_param_count == 0u) {
4978
            // Trivial 'binding': just return the static pair-ptr.
4979

4980 4981 4982
            ret f_res.res;
        } else {
            auto bcx = f_res.res.bcx;
4983
            auto pair_t = node_type(cx.fcx.lcx.ccx, cx.sp, ann);
4984
            auto pair_v = alloca(bcx, pair_t);
4985
            // Translate the bound expressions.
4986

4987 4988
            let vec[ty::t] bound_tys = [];
            let vec[ValueRef] bound_vals = [];
4989
            auto i = 0u;
4990
            for (@ast::expr e in bound) {
4991 4992
                auto arg = trans_expr(bcx, e);
                bcx = arg.bcx;
4993 4994
                vec::push[ValueRef](bound_vals, arg.val);
                vec::push[ty::t](bound_tys,
4995
                                 ty::expr_ty(cx.fcx.lcx.ccx.tcx, e));
4996
                i += 1u;
4997 4998
            }
            // Synthesize a closure type.
4999

5000 5001
            let ty::t bindings_ty =
                ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, bound_tys);
5002
            // NB: keep this in sync with T_closure_ptr; we're making
5003
            // a ty::t structure that has the same "shape" as the LLVM type
5004 5005
            // it constructs.

5006
            let ty::t tydesc_ty = ty::mk_type(cx.fcx.lcx.ccx.tcx);
5007
            let vec[ty::t] captured_tys =
5008
                vec::init_elt[ty::t](tydesc_ty, ty_param_count);
5009
            let vec[ty::t] closure_tys =
5010 5011 5012 5013
                [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);
5014
            auto r = trans_malloc_boxed(bcx, closure_ty);
5015 5016
            auto box = r.val;
            bcx = r.bcx;
5017
            auto rc =
5018
                bcx.build.GEP(box,
5019 5020 5021
                              [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)]);
5022 5023
            bcx.build.Store(C_int(1), rc);
            // Store bindings tydesc.
5024

5025 5026
            auto bound_tydesc =
                bcx.build.GEP(closure,
5027
                              [C_int(0), C_int(abi::closure_elt_tydesc)]);
5028 5029 5030
            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);
5031
            lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
5032 5033
            bcx = bindings_tydesc.bcx;
            bcx.build.Store(bindings_tydesc.val, bound_tydesc);
5034 5035 5036 5037 5038 5039 5040
            // 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.

5041 5042 5043 5044 5045 5046 5047
            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));
5048
            // Store thunk-target.
5049

5050
            auto bound_target =
5051
                bcx.build.GEP(closure,
5052
                              [C_int(0), C_int(abi::closure_elt_target)]);
5053
            auto src = bcx.build.Load(f_res.res.val);
5054
            bound_target = bcx.build.PointerCast(bound_target, llclosurety);
5055
            bcx.build.Store(src, bound_target);
5056
            // Copy expr values into boxed bindings.
5057

5058
            i = 0u;
5059 5060
            auto bindings =
                bcx.build.GEP(closure,
5061
                              [C_int(0), C_int(abi::closure_elt_bindings)]);
5062
            for (ValueRef v in bound_vals) {
5063 5064
                auto bound =
                    bcx.build.GEP(bindings, [C_int(0), C_int(i as int)]);
5065
                bcx = copy_val(bcx, INIT, bound, v, bound_tys.(i)).bcx;
5066 5067 5068 5069
                i += 1u;
            }
            // If necessary, copy tydescs describing type parameters into the
            // appropriate slot in the closure.
5070

5071
            alt (f_res.generic) {
5072
                case (none) {/* nothing to do */ }
5073
                case (some(?ginfo)) {
5074
                    lazily_emit_all_generic_info_tydesc_glues(cx, ginfo);
5075 5076
                    auto ty_params_slot =
                        bcx.build.GEP(closure,
5077
                                      [C_int(0),
5078
                                       C_int(abi::closure_elt_ty_params)]);
5079 5080
                    auto i = 0;
                    for (ValueRef td in ginfo.tydescs) {
5081 5082 5083
                        auto ty_param_slot =
                            bcx.build.GEP(ty_params_slot,
                                          [C_int(0), C_int(i)]);
5084 5085 5086
                        bcx.build.Store(td, ty_param_slot);
                        i += 1;
                    }
5087
                    outgoing_fty = ginfo.item_type;
5088
                }
5089
            }
5090
            // Make thunk and store thunk-ptr in outer pair's code slot.
5091

5092 5093
            auto pair_code =
                bcx.build.GEP(pair_v, [C_int(0), C_int(abi::fn_field_code)]);
5094
            let ty::t pair_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
5095
            let ValueRef llthunk =
5096
                trans_bind_thunk(cx.fcx.lcx, cx.sp, pair_ty, outgoing_fty,
5097
                                 args, closure_ty, bound_tys, ty_param_count);
5098 5099
            bcx.build.Store(llthunk, pair_code);
            // Store box ptr in outer pair's box slot.
5100

5101 5102 5103 5104 5105 5106
            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);
5107
            find_scope_cx(cx).cleanups +=
5108
                [clean(bind drop_slot(_, pair_v, pair_ty))];
5109 5110
            ret res(bcx, pair_v);
        }
5111 5112 5113
    }
}

5114
fn trans_arg_expr(&@block_ctxt cx, &ty::arg arg, TypeRef lldestty0,
5115
                  &@ast::expr e) -> result {
5116 5117
    auto val;
    auto bcx = cx;
5118
    auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
5119
    if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, e_ty)) {
5120 5121 5122
        auto re = trans_expr(bcx, e);
        val = re.val;
        bcx = re.bcx;
5123
    } else if (arg.mode != ty::mo_val) {
5124
        let lval_result lv;
5125
        if (ty::is_lval(e)) {
5126 5127 5128 5129 5130
            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);
5131
            } else { lv = lval_mem(r.bcx, r.val); }
5132 5133 5134 5135 5136 5137 5138
        }
        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.
5139

5140 5141
            val = do_spill(lv.res.bcx, lv.res.val);
        }
5142 5143
    } 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; }
5144 5145 5146 5147 5148
    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).
5149

5150
        val = llvm::LLVMGetUndef(lldestty0);
5151
    } else if (ty::type_contains_params(cx.fcx.lcx.ccx.tcx, arg.ty)) {
5152
        auto lldestty = lldestty0;
5153
        if (arg.mode == ty::mo_val) {
5154

5155
            // FIXME: we'd prefer to use &&, but rustboot doesn't like it
5156
            if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, e_ty)) {
5157 5158 5159 5160 5161
                lldestty = T_ptr(lldestty);
            }
        }
        val = bcx.build.PointerCast(val, lldestty);
    }
5162
    if (arg.mode == ty::mo_val) {
5163

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

5169 5170 5171 5172 5173 5174
            val = bcx.build.Load(val);
        }
    }
    ret res(bcx, val);
}

5175

5176 5177 5178 5179 5180 5181
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args
5182 5183 5184 5185
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) {
5186
    let vec[ty::arg] args = ty::ty_fn_args(cx.fcx.lcx.ccx.tcx, fn_ty);
5187 5188
    let vec[ValueRef] llargs = [];
    let vec[ValueRef] lltydescs = [];
5189 5190
    let @block_ctxt bcx = cx;
    // Arg 0: Output pointer.
5191

5192
    auto retty = ty::ty_fn_ret(cx.fcx.lcx.ccx.tcx, fn_ty);
5193 5194 5195
    auto llretslot_res = alloc_ty(bcx, retty);
    bcx = llretslot_res.bcx;
    auto llretslot = llretslot_res.val;
5196
    alt (gen) {
5197
        case (some(?g)) {
5198
            lazily_emit_all_generic_info_tydesc_glues(cx, g);
5199
            lltydescs = g.tydescs;
5200 5201
            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);
5202
        }
5203
        case (_) { }
5204
    }
5205
    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, retty)) {
5206 5207 5208
        llargs +=
            [bcx.build.PointerCast(llretslot,
                                   T_typaram_ptr(cx.fcx.lcx.ccx.tn))];
5209
    } else if (ty::type_contains_params(cx.fcx.lcx.ccx.tcx, retty)) {
5210 5211 5212 5213 5214
        // 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.
5215

5216
        llargs +=
5217
            [cx.build.PointerCast(llretslot,
5218 5219 5220
                                  T_ptr(type_of(bcx.fcx.lcx.ccx, bcx.sp,
                                                retty)))];
    } else { llargs += [llretslot]; }
5221
    // Arg 1: task pointer.
5222

5223
    llargs += [bcx.fcx.lltaskptr];
5224
    // Arg 2: Env (closure-bindings / self-obj)
5225

5226
    alt (llobj) {
5227
        case (some(?ob)) {
5228 5229 5230
            // Every object is always found in memory,
            // and not-yet-loaded (as part of an lval x.y
            // doted method-call).
5231

5232
            llargs += [bcx.build.Load(ob)];
5233
        }
5234
        case (_) { llargs += [llenv]; }
5235 5236 5237
    }
    // Args >3: ty_params ...

5238
    llargs += lltydescs;
5239
    // ... then possibly an lliterbody argument.
5240

5241
    alt (lliterbody) {
5242 5243
        case (none) { }
        case (some(?lli)) { llargs += [lli]; }
5244
    }
5245
    // ... then explicit args.
5246 5247 5248 5249 5250

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

5251
    auto arg_tys = type_of_explicit_args(cx.fcx.lcx.ccx, cx.sp, args);
5252
    auto i = 0u;
5253
    for (@ast::expr e in es) {
5254 5255
        auto r = trans_arg_expr(bcx, args.(i), arg_tys.(i), e);
        bcx = r.bcx;
5256
        llargs += [r.val];
5257 5258 5259 5260 5261
        i += 1u;
    }
    ret tup(bcx, llargs, llretslot);
}

5262 5263
fn trans_call(&@block_ctxt cx, &@ast::expr f, &option::t[ValueRef] lliterbody,
              &vec[@ast::expr] args, &ast::ann ann) -> result {
5264 5265 5266 5267
    // 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.

5268
    auto f_res = trans_lval(cx, f);
5269
    auto faddr = f_res.res.val;
5270
    auto llenv = C_null(T_opaque_closure_ptr(cx.fcx.lcx.ccx.tn));
5271
    alt (f_res.llobj) {
5272
        case (some(_)) {
5273
            // It's a vtbl entry.
5274

5275 5276
            faddr = f_res.res.bcx.build.Load(faddr);
        }
5277
        case (none) {
5278
            // It's a closure.
5279

5280
            auto bcx = f_res.res.bcx;
5281
            auto pair = faddr;
5282 5283
            faddr =
                bcx.build.GEP(pair, [C_int(0), C_int(abi::fn_field_code)]);
5284
            faddr = bcx.build.Load(faddr);
5285 5286
            auto llclosure =
                bcx.build.GEP(pair, [C_int(0), C_int(abi::fn_field_box)]);
5287
            llenv = bcx.build.Load(llclosure);
5288
        }
5289
    }
5290
    let ty::t fn_ty;
5291
    alt (f_res.method_ty) {
5292
        case (some(?meth)) {
5293
            // self-call
5294

5295
            fn_ty = meth;
5296
        }
5297
        case (_) { fn_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, f); }
5298
    }
5299
    auto ret_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann);
5300 5301 5302
    auto args_res =
        trans_args(f_res.res.bcx, llenv, f_res.llobj, f_res.generic,
                   lliterbody, args, fn_ty);
5303 5304 5305 5306
    auto bcx = args_res._0;
    auto llargs = args_res._1;
    auto llretslot = args_res._2;
    /*
5307
    log "calling: " + val_str(cx.fcx.lcx.ccx.tn, faddr);
5308
    
5309
    for (ValueRef arg in llargs) {
5310
        log "arg: " + val_str(cx.fcx.lcx.ccx.tn, arg);
5311
    }
5312 5313 5314 5315
    */

    bcx.build.FastCall(faddr, llargs);
    auto retval = C_nil();
5316
    alt (lliterbody) {
5317
        case (none) {
5318
            if (!ty::type_is_nil(cx.fcx.lcx.ccx.tcx, ret_ty)) {
5319 5320 5321 5322
                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.
5323

5324
                find_scope_cx(cx).cleanups +=
5325
                    [clean(bind drop_ty(_, retval, ret_ty))];
5326 5327
            }
        }
5328
        case (some(_)) {
5329 5330 5331
            // 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.
5332

5333
        }
5334 5335 5336 5337
    }
    ret res(bcx, retval);
}

5338
fn trans_tup(&@block_ctxt cx, &vec[ast::elt] elts, &ast::ann ann) -> result {
5339
    auto bcx = cx;
5340
    auto t = node_ann_type(bcx.fcx.lcx.ccx, ann);
5341 5342 5343
    auto tup_res = alloc_ty(bcx, t);
    auto tup_val = tup_res.val;
    bcx = tup_res.bcx;
5344
    find_scope_cx(cx).cleanups += [clean(bind drop_ty(_, tup_val, t))];
G
Graydon Hoare 已提交
5345
    let int i = 0;
5346
    for (ast::elt e in elts) {
5347
        auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e.expr);
5348 5349
        auto src_res = trans_expr(bcx, e.expr);
        bcx = src_res.bcx;
5350
        auto dst_res = GEP_tup_like(bcx, t, tup_val, [0, i]);
5351
        bcx = dst_res.bcx;
5352
        bcx = copy_val(src_res.bcx, INIT, dst_res.val, src_res.val, e_ty).bcx;
G
Graydon Hoare 已提交
5353 5354
        i += 1;
    }
5355
    ret res(bcx, tup_val);
G
Graydon Hoare 已提交
5356 5357
}

5358 5359
fn trans_vec(&@block_ctxt cx, &vec[@ast::expr] args, &ast::ann ann) ->
   result {
5360
    auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
5361
    auto unit_ty = t;
5362
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
5363 5364
        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 已提交
5365
    }
5366 5367 5368
    auto bcx = cx;
    auto unit_sz = size_of(bcx, unit_ty);
    bcx = unit_sz.bcx;
5369 5370
    auto data_sz =
        bcx.build.Mul(C_int(vec::len[@ast::expr](args) as int), unit_sz.val);
G
Graydon Hoare 已提交
5371
    // FIXME: pass tydesc properly.
5372 5373 5374 5375 5376

    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)))]);
5377
    auto llty = type_of(bcx.fcx.lcx.ccx, bcx.sp, t);
5378
    vec_val = bcx.build.PointerCast(vec_val, llty);
5379 5380
    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)]);
5381
    auto pseudo_tup_ty =
5382
        ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx,
5383 5384
                       vec::init_elt[ty::t](unit_ty,
                                            vec::len[@ast::expr](args)));
G
Graydon Hoare 已提交
5385
    let int i = 0;
5386
    for (@ast::expr e in args) {
5387 5388
        auto src_res = trans_expr(bcx, e);
        bcx = src_res.bcx;
5389
        auto dst_res = GEP_tup_like(bcx, pseudo_tup_ty, body, [0, i]);
5390
        bcx = dst_res.bcx;
5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403
        // 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;
5404
        if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, unit_ty)) {
5405
            auto llunit_ty = type_of(cx.fcx.lcx.ccx, bcx.sp, unit_ty);
5406
            dst_val = bcx.build.PointerCast(dst_res.val, T_ptr(llunit_ty));
5407
        } else { dst_val = dst_res.val; }
5408
        bcx = copy_val(bcx, INIT, dst_val, src_res.val, unit_ty).bcx;
G
Graydon Hoare 已提交
5409 5410
        i += 1;
    }
5411
    auto fill = bcx.build.GEP(vec_val, [C_int(0), C_int(abi::vec_elt_fill)]);
5412 5413
    bcx.build.Store(data_sz, fill);
    ret res(bcx, vec_val);
G
Graydon Hoare 已提交
5414 5415
}

5416

5417
// TODO: Move me to ivec::
5418
fn trans_ivec(@block_ctxt bcx, &vec[@ast::expr] args, &ast::ann ann) ->
5419
   result {
5420 5421 5422 5423 5424 5425 5426
    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);
5427 5428 5429 5430 5431 5432 5433

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

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

5437
    auto llfirsteltptr;
5438
    if (vec::len(args) > 0u && vec::len(args) <= abi::ivec_default_length) {
5439
        // Interior case.
5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452

        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)]);
5453 5454
    } else {
        // Heap case.
5455 5456 5457 5458

        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)];
5459 5460
        auto llstubty = T_ivec_heap(llunitty);
        auto llstubptr = bcx.build.PointerCast(llvecptr, T_ptr(llstubty));
5461 5462
        bcx.build.Store(C_int(0), bcx.build.InBoundsGEP(llstubptr, stub_z));
        bcx.build.Store(lllen, bcx.build.InBoundsGEP(llstubptr, stub_a));
5463
        auto llheapty = T_ivec_heap_part(llunitty);
5464 5465
        if (vec::len(args) == 0u) {
            // Null heap pointer indicates a zero-length vector.
5466

5467
            bcx.build.Store(C_null(T_ptr(llheapty)),
5468
                            bcx.build.InBoundsGEP(llstubptr, stub_p));
5469 5470 5471
            llfirsteltptr = C_null(T_ptr(llunitty));
        } else {
            auto llheapsz = bcx.build.Add(llsize_of(llheapty), lllen);
5472
            auto rslt = trans_raw_malloc(bcx, T_ptr(llheapty), llheapsz);
5473 5474
            bcx = rslt.bcx;
            auto llheapptr = rslt.val;
5475 5476
            bcx.build.Store(llheapptr,
                            bcx.build.InBoundsGEP(llstubptr, stub_p));
5477
            auto heap_l = [C_int(0), C_uint(abi::ivec_heap_elt_len)];
5478
            bcx.build.Store(lllen, bcx.build.InBoundsGEP(llheapptr, heap_l));
5479 5480 5481 5482 5483
            llfirsteltptr =
                bcx.build.InBoundsGEP(llheapptr,
                                      [C_int(0),
                                       C_uint(abi::ivec_heap_elt_elems),
                                       C_int(0)]);
5484 5485 5486
        }
    }
    // Store the individual elements.
5487

5488 5489
    auto i = 0u;
    for (@ast::expr e in args) {
5490
        auto rslt = trans_expr(bcx, e);
5491 5492 5493 5494
        bcx = rslt.bcx;
        auto llsrc = rslt.val;
        auto lleltptr;
        if (ty::type_has_dynamic_size(bcx.fcx.lcx.ccx.tcx, unit_ty)) {
5495 5496 5497
            lleltptr =
                bcx.build.InBoundsGEP(llfirsteltptr,
                                      [bcx.build.Mul(C_uint(i), unit_sz)]);
5498
        } else {
5499
            lleltptr = bcx.build.InBoundsGEP(llfirsteltptr, [C_uint(i)]);
5500 5501 5502 5503 5504 5505 5506
        }
        bcx = copy_val(bcx, INIT, lleltptr, llsrc, unit_ty).bcx;
        i += 1u;
    }
    ret res(bcx, llvecptr);
}

5507 5508
fn trans_rec(&@block_ctxt cx, &vec[ast::field] fields,
             &option::t[@ast::expr] base, &ast::ann ann) -> result {
5509
    auto bcx = cx;
5510
    auto t = node_ann_type(bcx.fcx.lcx.ccx, ann);
5511 5512 5513
    auto rec_res = alloc_ty(bcx, t);
    auto rec_val = rec_res.val;
    bcx = rec_res.bcx;
5514
    find_scope_cx(cx).cleanups += [clean(bind drop_ty(_, rec_val, t))];
5515
    let int i = 0;
G
Graydon Hoare 已提交
5516 5517
    auto base_val = C_nil();
    alt (base) {
5518 5519
        case (none) { }
        case (some(?bexp)) {
G
Graydon Hoare 已提交
5520 5521 5522 5523 5524
            auto base_res = trans_expr(bcx, bexp);
            bcx = base_res.bcx;
            base_val = base_res.val;
        }
    }
5525
    let vec[ty::field] ty_fields = [];
5526 5527
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
        case (ty::ty_rec(?flds)) { ty_fields = flds; }
G
Graydon Hoare 已提交
5528
    }
5529
    for (ty::field tf in ty_fields) {
5530
        auto e_ty = tf.mt.ty;
5531
        auto dst_res = GEP_tup_like(bcx, t, rec_val, [0, i]);
5532
        bcx = dst_res.bcx;
G
Graydon Hoare 已提交
5533 5534
        auto expr_provided = false;
        auto src_res = res(bcx, C_nil());
5535
        for (ast::field f in fields) {
5536
            if (str::eq(f.node.ident, tf.ident)) {
G
Graydon Hoare 已提交
5537
                expr_provided = true;
5538
                src_res = trans_expr(bcx, f.node.expr);
G
Graydon Hoare 已提交
5539 5540 5541
            }
        }
        if (!expr_provided) {
5542
            src_res = GEP_tup_like(bcx, t, base_val, [0, i]);
5543 5544
            src_res =
                res(src_res.bcx, load_if_immediate(bcx, src_res.val, e_ty));
G
Graydon Hoare 已提交
5545 5546
        }
        bcx = src_res.bcx;
5547
        bcx = copy_val(bcx, INIT, dst_res.val, src_res.val, e_ty).bcx;
5548 5549
        i += 1;
    }
5550
    ret res(bcx, rec_val);
5551 5552
}

5553
fn trans_expr(&@block_ctxt cx, &@ast::expr e) -> result {
5554
    ret trans_expr_out(cx, e, return);
5555 5556
}

5557 5558
fn trans_expr_out(&@block_ctxt cx, &@ast::expr e, out_method output) ->
   result {
5559
    // FIXME Fill in cx.sp
5560

5561
    alt (e.node) {
5562
        case (ast::expr_lit(?lit, ?ann)) {
5563
            ret res(cx, trans_lit(cx.fcx.lcx.ccx, *lit, ann));
5564
        }
5565
        case (ast::expr_unary(?op, ?x, ?ann)) {
5566
            if (op != ast::deref) { ret trans_unary(cx, op, x, ann); }
5567
        }
5568
        case (ast::expr_binary(?op, ?x, ?y, _)) {
5569
            ret trans_binary(cx, op, x, y);
5570
        }
5571
        case (ast::expr_if(?cond, ?thn, ?els, ?ann)) {
5572 5573
            ret with_out_method(bind trans_if(cx, cond, thn, els, ann, _), cx,
                                ann, output);
5574
        }
T
Tim Chevalier 已提交
5575 5576 5577 5578
        case (ast::expr_if_check(?cond, ?thn, ?els, ?ann)) {
            ret with_out_method(bind trans_if(cx, cond, thn, els, ann, _), cx,
                                ann, output);
        }
5579
        case (ast::expr_for(?decl, ?seq, ?body, _)) {
G
Graydon Hoare 已提交
5580 5581
            ret trans_for(cx, decl, seq, body);
        }
5582
        case (ast::expr_for_each(?decl, ?seq, ?body, _)) {
5583 5584
            ret trans_for_each(cx, decl, seq, body);
        }
5585
        case (ast::expr_while(?cond, ?body, _)) {
5586
            ret trans_while(cx, cond, body);
5587
        }
5588
        case (ast::expr_do_while(?body, ?cond, _)) {
5589
            ret trans_do_while(cx, body, cond);
5590
        }
5591
        case (ast::expr_alt(?expr, ?arms, ?ann)) {
5592 5593
            ret with_out_method(bind trans_alt(cx, expr, arms, ann, _), cx,
                                ann, output);
P
Patrick Walton 已提交
5594
        }
5595 5596
        case (ast::expr_fn(?f, ?ann)) {
            auto ccx = cx.fcx.lcx.ccx;
5597 5598 5599 5600 5601 5602 5603
            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)
                    }
                };
5604 5605 5606 5607 5608 5609
            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));
        }
5610
        case (ast::expr_block(?blk, ?ann)) {
5611 5612
            auto sub_cx = new_scope_block_ctxt(cx, "block-expr body");
            auto next_cx = new_sub_block_ctxt(cx, "next");
5613 5614 5615
            auto sub =
                with_out_method(bind trans_block(sub_cx, blk, _), cx, ann,
                                output);
5616 5617 5618
            cx.build.Br(sub_cx.llbb);
            sub.bcx.build.Br(next_cx.llbb);
            ret res(next_cx, sub.val);
5619
        }
5620
        case (ast::expr_move(?dst, ?src, _)) {
5621 5622
            auto lhs_res = trans_lval(cx, dst);
            assert (lhs_res.is_mem);
5623
            // FIXME Fill in lhs_res.res.bcx.sp
5624

M
Michael Sullivan 已提交
5625
            auto rhs_res = trans_lval(lhs_res.res.bcx, src);
5626
            auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, src);
5627
            // FIXME: calculate copy init-ness in typestate.
5628 5629 5630 5631

            auto move_res =
                move_val(rhs_res.res.bcx, DROP_EXISTING, lhs_res.res.val,
                         rhs_res.res.val, t);
5632
            ret res(move_res.bcx, C_nil());
5633
        }
5634
        case (ast::expr_assign(?dst, ?src, _)) {
5635
            auto lhs_res = trans_lval(cx, dst);
5636
            assert (lhs_res.is_mem);
5637
            // FIXME Fill in lhs_res.res.bcx.sp
5638

5639
            auto rhs_res = trans_expr(lhs_res.res.bcx, src);
5640
            auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, src);
G
Graydon Hoare 已提交
5641
            // FIXME: calculate copy init-ness in typestate.
5642 5643 5644 5645

            auto copy_res =
                copy_val(rhs_res.bcx, DROP_EXISTING, lhs_res.res.val,
                         rhs_res.val, t);
5646
            ret res(copy_res.bcx, C_nil());
5647
        }
M
Michael Sullivan 已提交
5648 5649 5650 5651 5652 5653 5654 5655 5656
        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.
5657 5658 5659 5660 5661 5662 5663 5664

            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 已提交
5665 5666
            ret res(move3_res.bcx, C_nil());
        }
5667 5668
        case (ast::expr_assign_op(?op, ?dst, ?src, _)) {
            auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, src);
5669
            auto lhs_res = trans_lval(cx, dst);
5670
            assert (lhs_res.is_mem);
5671
            // FIXME Fill in lhs_res.res.bcx.sp
5672

5673
            auto rhs_res = trans_expr(lhs_res.res.bcx, src);
5674
            if (ty::type_is_sequence(cx.fcx.lcx.ccx.tcx, t)) {
5675
                alt (op) {
5676
                    case (ast::add) {
5677
                        if (ty::sequence_is_interior(cx.fcx.lcx.ccx.tcx, t)) {
5678 5679 5680
                            ret ivec::trans_append(rhs_res.bcx, t,
                                                   lhs_res.res.val,
                                                   rhs_res.val);
5681
                        }
5682
                        ret trans_vec_append(rhs_res.bcx, t, lhs_res.res.val,
5683 5684 5685 5686 5687
                                             rhs_res.val);
                    }
                    case (_) { }
                }
            }
5688 5689 5690
            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);
5691
            // FIXME: calculate copy init-ness in typestate.
5692 5693 5694

            auto copy_res =
                copy_val(v.bcx, DROP_EXISTING, lhs_res.res.val, v.val, t);
5695
            ret res(copy_res.bcx, C_nil());
5696
        }
5697
        case (ast::expr_bind(?f, ?args, ?ann)) {
5698 5699
            ret trans_bind(cx, f, args, ann);
        }
5700
        case (ast::expr_call(?f, ?args, ?ann)) {
5701
            ret trans_call(cx, f, none[ValueRef], args, ann);
5702
        }
5703
        case (ast::expr_cast(?e, _, ?ann)) { ret trans_cast(cx, e, ann); }
5704
        case (ast::expr_vec(?args, _, ast::sk_rc, ?ann)) {
G
Graydon Hoare 已提交
5705 5706
            ret trans_vec(cx, args, ann);
        }
5707 5708 5709
        case (ast::expr_vec(?args, _, ast::sk_unique, ?ann)) {
            ret trans_ivec(cx, args, ann);
        }
5710
        case (ast::expr_tup(?args, ?ann)) { ret trans_tup(cx, args, ann); }
5711
        case (ast::expr_rec(?args, ?base, ?ann)) {
5712
            ret trans_rec(cx, args, base, ann);
5713
        }
5714
        case (ast::expr_ext(_, _, _, ?expanded, _)) {
5715
            ret trans_expr(cx, expanded);
5716
        }
J
Josh Matthews 已提交
5717 5718 5719
        case (ast::expr_fail(_, ?str)) {
            auto failmsg;
            alt (str) {
5720 5721
                case (some(?msg)) { failmsg = msg; }
                case (_) { failmsg = "explicit failure"; }
J
Josh Matthews 已提交
5722 5723
            }
            ret trans_fail(cx, some(e.span), failmsg);
5724
        }
5725
        case (ast::expr_log(?lvl, ?a, _)) { ret trans_log(lvl, cx, a); }
5726
        case (ast::expr_assert(?a, _)) {
5727
            ret trans_check_expr(cx, a, "Assertion");
5728
        }
5729
        case (ast::expr_check(?a, _)) {
5730
            ret trans_check_expr(cx, a, "Predicate");
5731
        }
5732 5733 5734 5735 5736 5737 5738
        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); }
5739
        case (ast::expr_send(?lhs, ?rhs, ?ann)) {
B
Brian Anderson 已提交
5740 5741
            ret trans_send(cx, lhs, rhs, ann);
        }
5742
        case (ast::expr_recv(?lhs, ?rhs, ?ann)) {
B
Brian Anderson 已提交
5743 5744
            ret trans_recv(cx, lhs, rhs, ann);
        }
5745
        case (ast::expr_spawn(?dom, ?name, ?func, ?args, ?ann)) {
5746
            ret trans_spawn(cx, dom, name, func, args, ann);
5747
        }
L
Lindsey Kuper 已提交
5748
        case (ast::expr_anon_obj(?anon_obj, ?tps, ?odid, ?ann)) {
L
Lindsey Kuper 已提交
5749
            ret trans_anon_obj(cx, e.span, anon_obj, tps, odid.ctor, ann);
L
Lindsey Kuper 已提交
5750
        }
5751
        case (_) {
5752
            // The expression is an lvalue. Fall through.
T
Tim Chevalier 已提交
5753 5754
            assert (ty::is_lval(e)); // make sure it really is and that we 
                               // didn't forget to add a case for a new expr!
5755
        }
5756
    }
5757 5758 5759
    // lval cases fall through to trans_lval and then
    // possibly load the result (if it's non-structural).

5760
    auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
5761
    auto sub = trans_lval(cx, e);
5762
    ret res(sub.res.bcx, load_if_immediate(sub.res.bcx, sub.res.val, t));
5763 5764
}

5765
fn with_out_method(fn(&out_method) -> result  work, @block_ctxt cx,
5766 5767 5768 5769 5770 5771
                   &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);
5772
        if (ty::type_is_nil(ccx.tcx, tp)) { ret work(return); }
5773 5774
        auto res_alloca = alloc_ty(cx, tp);
        cx = zero_alloca(res_alloca.bcx, res_alloca.val, tp).bcx;
5775 5776
        fn drop_hoisted_ty(&@block_ctxt cx, ValueRef target, ty::t t) ->
           result {
5777 5778 5779 5780 5781 5782
            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 已提交
5783
        done = res(done.bcx, load_if_immediate(done.bcx, res_alloca.val, tp));
5784 5785 5786 5787
        ret done;
    }
}

5788

5789
// We pass structural values around the compiler "by pointer" and
5790 5791 5792 5793
// 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.
5794
fn type_is_immediate(&@crate_ctxt ccx, &ty::t t) -> bool {
5795 5796
    ret ty::type_is_scalar(ccx.tcx, t) || ty::type_is_boxed(ccx.tcx, t) ||
            ty::type_is_native(ccx.tcx, t);
5797 5798
}

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

5802 5803 5804 5805
    auto llptr = alloca(cx, val_ty(v));
    cx.build.Store(v, llptr);
    ret llptr;
}
5806

5807
fn spill_if_immediate(&@block_ctxt cx, ValueRef v, &ty::t t) -> ValueRef {
5808
    if (type_is_immediate(cx.fcx.lcx.ccx, t)) { ret do_spill(cx, v); }
5809 5810 5811
    ret v;
}

5812
fn load_if_immediate(&@block_ctxt cx, ValueRef v, &ty::t t) -> ValueRef {
5813
    if (type_is_immediate(cx.fcx.lcx.ccx, t)) { ret cx.build.Load(v); }
5814
    ret v;
5815 5816
}

5817
fn trans_log(int lvl, &@block_ctxt cx, &@ast::expr e) -> result {
5818
    auto lcx = cx.fcx.lcx;
5819
    auto modname = str::connect(lcx.module_path, "::");
5820 5821 5822 5823
    auto global;
    if (lcx.ccx.module_data.contains_key(modname)) {
        global = lcx.ccx.module_data.get(modname);
    } else {
5824 5825 5826 5827 5828
        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));
5829 5830
        llvm::LLVMSetGlobalConstant(global, False);
        llvm::LLVMSetInitializer(global, C_null(T_int()));
5831 5832
        llvm::LLVMSetLinkage(global,
                             lib::llvm::LLVMInternalLinkage as llvm::Linkage);
5833 5834
        lcx.ccx.module_data.insert(modname, global);
    }
5835
    auto log_cx = new_scope_block_ctxt(cx, "log");
5836 5837
    auto after_cx = new_sub_block_ctxt(cx, "after");
    auto load = cx.build.Load(global);
5838
    auto test = cx.build.ICmp(lib::llvm::LLVMIntSGE, load, C_int(lvl));
5839 5840
    cx.build.CondBr(test, log_cx.llbb, after_cx.llbb);
    auto sub = trans_expr(log_cx, e);
5841
    auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
5842
    auto log_bcx = sub.bcx;
5843
    if (ty::type_is_fp(cx.fcx.lcx.ccx.tcx, e_ty)) {
5844 5845
        let TypeRef tr;
        let bool is32bit = false;
5846 5847
        alt (ty::struct(cx.fcx.lcx.ccx.tcx, e_ty)) {
            case (ty::ty_machine(util::common::ty_f32)) {
5848 5849 5850
                tr = T_f32();
                is32bit = true;
            }
5851 5852
            case (ty::ty_machine(util::common::ty_f64)) { tr = T_f64(); }
            case (_) { tr = T_float(); }
5853 5854
        }
        if (is32bit) {
5855
            log_bcx.build.Call(log_bcx.fcx.lcx.ccx.upcalls.log_float,
5856
                               [log_bcx.fcx.lltaskptr, C_int(lvl), sub.val]);
5857
        } else {
5858
            // FIXME: Eliminate this level of indirection.
5859

5860
            auto tmp = alloca(log_bcx, tr);
5861
            sub.bcx.build.Store(sub.val, tmp);
5862
            log_bcx.build.Call(log_bcx.fcx.lcx.ccx.upcalls.log_double,
5863
                               [log_bcx.fcx.lltaskptr, C_int(lvl), tmp]);
5864
        }
5865
    } else if (ty::type_is_integral(cx.fcx.lcx.ccx.tcx, e_ty) ||
5866
                   ty::type_is_bool(cx.fcx.lcx.ccx.tcx, e_ty)) {
5867
        // FIXME: Handle signedness properly.
5868 5869 5870

        auto llintval =
            int_cast(log_bcx, T_int(), val_ty(sub.val), sub.val, false);
5871
        log_bcx.build.Call(log_bcx.fcx.lcx.ccx.upcalls.log_int,
5872
                           [log_bcx.fcx.lltaskptr, C_int(lvl), llintval]);
5873
    } else {
5874 5875
        alt (ty::struct(cx.fcx.lcx.ccx.tcx, e_ty)) {
            case (ty::ty_str) {
5876
                log_bcx.build.Call(log_bcx.fcx.lcx.ccx.upcalls.log_str,
5877
                                   [log_bcx.fcx.lltaskptr, C_int(lvl),
5878
                                    sub.val]);
5879 5880
            }
            case (_) {
5881
                // FIXME: Support these types.
5882

5883
                cx.fcx.lcx.ccx.sess.span_err(e.span,
5884 5885 5886 5887
                                             "log called on unsupported type "
                                                 +
                                                 ty_to_str(cx.fcx.lcx.ccx.tcx,
                                                           e_ty));
5888
            }
5889 5890
        }
    }
5891 5892
    log_bcx = trans_block_cleanups(log_bcx, log_cx);
    log_bcx.build.Br(after_cx.llbb);
5893
    ret res(after_cx, C_nil());
5894 5895
}

5896
fn trans_check_expr(&@block_ctxt cx, &@ast::expr e, &str s) -> result {
5897
    auto cond_res = trans_expr(cx, e);
5898
    auto expr_str = s + " " + expr_to_str(e) + " failed";
5899
    auto fail_cx = new_sub_block_ctxt(cx, "fail");
5900
    auto fail_res = trans_fail(fail_cx, some[common::span](e.span), expr_str);
5901
    auto next_cx = new_sub_block_ctxt(cx, "next");
5902
    cond_res.bcx.build.CondBr(cond_res.val, next_cx.llbb, fail_cx.llbb);
5903 5904 5905
    ret res(next_cx, C_nil());
}

5906
fn trans_fail(&@block_ctxt cx, &option::t[common::span] sp_opt, &str fail_str)
5907
   -> result {
5908
    auto V_fail_str = C_cstr(cx.fcx.lcx.ccx, fail_str);
5909 5910
    auto V_filename;
    auto V_line;
5911
    alt (sp_opt) {
5912
        case (some(?sp)) {
5913
            auto loc = cx.fcx.lcx.ccx.sess.lookup_pos(sp.lo);
5914
            V_filename = C_cstr(cx.fcx.lcx.ccx, loc.filename);
5915 5916
            V_line = loc.line as int;
        }
5917
        case (none) {
5918
            V_filename = C_cstr(cx.fcx.lcx.ccx, "<runtime>");
5919 5920 5921
            V_line = 0;
        }
    }
5922 5923
    V_fail_str = cx.build.PointerCast(V_fail_str, T_ptr(T_i8()));
    V_filename = cx.build.PointerCast(V_filename, T_ptr(T_i8()));
5924
    auto args = [cx.fcx.lltaskptr, V_fail_str, V_filename, C_int(V_line)];
5925 5926 5927
    cx.build.Call(cx.fcx.lcx.ccx.upcalls._fail, args);
    cx.build.Unreachable();
    ret res(cx, C_nil());
B
Brian Anderson 已提交
5928 5929
}

5930
fn trans_put(&@block_ctxt cx, &option::t[@ast::expr] e) -> result {
5931 5932
    auto llcallee = C_nil();
    auto llenv = C_nil();
5933
    alt ({ cx.fcx.lliterbody }) {
5934
        case (some(?lli)) {
5935
            auto slot = alloca(cx, val_ty(lli));
5936
            cx.build.Store(lli, slot);
5937 5938
            llcallee =
                cx.build.GEP(slot, [C_int(0), C_int(abi::fn_field_code)]);
5939
            llcallee = cx.build.Load(llcallee);
5940
            llenv = cx.build.GEP(slot, [C_int(0), C_int(abi::fn_field_box)]);
5941 5942 5943 5944
            llenv = cx.build.Load(llenv);
        }
    }
    auto bcx = cx;
5945
    auto dummy_retslot = alloca(bcx, T_nil());
5946
    let vec[ValueRef] llargs = [dummy_retslot, cx.fcx.lltaskptr, llenv];
5947
    alt (e) {
5948 5949
        case (none) { }
        case (some(?x)) {
5950
            auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, x);
5951
            auto arg = rec(mode=ty::mo_alias(false), ty=e_ty);
5952 5953
            auto arg_tys =
                type_of_explicit_args(cx.fcx.lcx.ccx, x.span, [arg]);
5954
            auto r = trans_arg_expr(bcx, arg, arg_tys.(0), x);
5955
            bcx = r.bcx;
5956
            llargs += [r.val];
5957 5958 5959
        }
    }
    ret res(bcx, bcx.build.FastCall(llcallee, llargs));
5960 5961
}

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

5966 5967 5968
    auto cleanup_cx = cx;
    while (true) {
        bcx = trans_block_cleanups(bcx, cleanup_cx);
5969
        alt ({ cleanup_cx.kind }) {
5970 5971 5972 5973 5974
            case (LOOP_SCOPE_BLOCK(?_cont, ?_break)) {
                if (to_end) {
                    bcx.build.Br(_break.llbb);
                } else {
                    alt (_cont) {
5975
                        case (option::some(?_cont)) {
5976 5977
                            bcx.build.Br(_cont.llbb);
                        }
5978
                        case (_) { bcx.build.Br(cleanup_cx.llbb); }
5979 5980
                    }
                }
5981 5982
                ret res(new_sub_block_ctxt(bcx, "break_cont.unreachable"),
                        C_nil());
5983 5984
            }
            case (_) {
5985
                alt ({ cleanup_cx.parent }) {
5986
                    case (parent_some(?cx)) { cleanup_cx = cx; }
5987 5988
                    case (parent_none) {
                        cx.fcx.lcx.ccx.sess.span_err(sp,
5989 5990 5991 5992
                                                     if (to_end) {
                                                         "Break"
                                                     } else { "Cont" } +
                                                         " outside a loop");
5993
                    }
5994 5995 5996 5997
                }
            }
        }
    }
5998
    // If we get here without returning, it's a bug
5999

6000
    cx.fcx.lcx.ccx.sess.bug("in trans::trans_break_cont()");
6001 6002
}

6003 6004
fn trans_break(&span sp, &@block_ctxt cx) -> result {
    ret trans_break_cont(sp, cx, true);
6005 6006
}

6007 6008
fn trans_cont(&span sp, &@block_ctxt cx) -> result {
    ret trans_break_cont(sp, cx, false);
6009 6010
}

6011
fn trans_ret(&@block_ctxt cx, &option::t[@ast::expr] e) -> result {
6012 6013
    auto bcx = cx;
    auto val = C_nil();
6014
    alt (e) {
6015
        case (some(?x)) {
6016
            auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, x);
6017 6018 6019
            auto r = trans_expr(cx, x);
            bcx = r.bcx;
            val = r.val;
6020
            bcx = copy_val(bcx, INIT, cx.fcx.llretptr, val, t).bcx;
6021
        }
6022
        case (_) {
6023 6024
            auto t = llvm::LLVMGetElementType(val_ty(cx.fcx.llretptr));
            auto null = lib::llvm::llvm::LLVMConstNull(t);
6025 6026
            bcx.build.Store(null, cx.fcx.llretptr);
        }
6027
    }
6028
    // run all cleanups and back out.
6029

6030
    let bool more_cleanups = true;
6031
    auto cleanup_cx = cx;
6032
    while (more_cleanups) {
6033
        bcx = trans_block_cleanups(bcx, cleanup_cx);
6034 6035 6036
        alt ({ cleanup_cx.parent }) {
            case (parent_some(?b)) { cleanup_cx = b; }
            case (parent_none) { more_cleanups = false; }
6037 6038
        }
    }
6039
    bcx.build.RetVoid();
6040
    ret res(new_sub_block_ctxt(bcx, "ret.unreachable"), C_nil());
6041 6042
}

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

6046
    assert (ast::is_call_expr(e));
6047 6048
    // FIXME: Turn this into a real tail call once
    // calling convention issues are settled
6049

6050 6051 6052
    ret trans_ret(cx, some(e));
}

6053
fn trans_port(&@block_ctxt cx, &ast::ann ann) -> result {
6054
    auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
B
Brian Anderson 已提交
6055
    auto unit_ty;
6056
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
6057 6058
        case (ty::ty_port(?t)) { unit_ty = t; }
        case (_) { cx.fcx.lcx.ccx.sess.bug("non-port type in trans_port"); }
B
Brian Anderson 已提交
6059
    }
6060
    auto llunit_ty = type_of(cx.fcx.lcx.ccx, cx.sp, unit_ty);
B
Brian Anderson 已提交
6061 6062 6063
    auto bcx = cx;
    auto unit_sz = size_of(bcx, unit_ty);
    bcx = unit_sz.bcx;
6064 6065 6066
    auto port_raw_val =
        bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.new_port,
                       [bcx.fcx.lltaskptr, unit_sz.val]);
6067
    auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, t);
6068
    auto port_val = bcx.build.PointerCast(port_raw_val, llty);
B
Brian Anderson 已提交
6069
    auto dropref = clean(bind drop_ty(_, port_val, t));
6070
    find_scope_cx(bcx).cleanups += [dropref];
B
Brian Anderson 已提交
6071 6072 6073
    ret res(bcx, port_val);
}

6074
fn trans_chan(&@block_ctxt cx, &@ast::expr e, &ast::ann ann) -> result {
B
Brian Anderson 已提交
6075 6076 6077
    auto bcx = cx;
    auto prt = trans_expr(bcx, e);
    bcx = prt.bcx;
6078
    auto prt_val = bcx.build.PointerCast(prt.val, T_opaque_port_ptr());
6079 6080 6081
    auto chan_raw_val =
        bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.new_chan,
                       [bcx.fcx.lltaskptr, prt_val]);
6082
    auto chan_ty = node_ann_type(bcx.fcx.lcx.ccx, ann);
6083
    auto chan_llty = type_of(bcx.fcx.lcx.ccx, e.span, chan_ty);
6084
    auto chan_val = bcx.build.PointerCast(chan_raw_val, chan_llty);
B
Brian Anderson 已提交
6085
    auto dropref = clean(bind drop_ty(_, chan_val, chan_ty));
6086
    find_scope_cx(bcx).cleanups += [dropref];
B
Brian Anderson 已提交
6087 6088 6089
    ret res(bcx, chan_val);
}

6090 6091 6092
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 {
6093
    auto bcx = cx;
6094 6095
    // Make the task name

6096 6097 6098 6099 6100 6101 6102 6103
    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 }
        };
6104
    // Generate code
6105 6106 6107 6108 6109 6110 6111 6112 6113
    //
    // 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)
    //
6114
    // 3. Fill the tuple with the arguments we evaluated.
6115
    // 
6116 6117 6118 6119 6120 6121
    // 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.
6122 6123
    //
    // 5. Oh yeah, we have to create the task before we start it...
6124

6125 6126
    // Translate the arguments, remembering their types and where the values
    // ended up.
6127

6128
    let vec[ty::t] arg_tys = [];
6129
    let vec[ValueRef] arg_vals = [];
6130
    for (@ast::expr e in args) {
6131 6132 6133
        auto arg = trans_expr(bcx, e);
        bcx = arg.bcx;
        vec::push[ValueRef](arg_vals, arg.val);
6134
        vec::push[ty::t](arg_tys, ty::expr_ty(cx.fcx.lcx.ccx.tcx, e));
6135
    }
6136
    // Make the tuple.
6137

6138 6139 6140
    auto args_ty = ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, arg_tys);
    // Allocate and fill the tuple.

6141
    auto llargs = alloc_ty(bcx, args_ty);
6142
    auto i = 0u;
6143
    for (ValueRef v in arg_vals) {
6144 6145
        // log_err #fmt("ty(llargs) = %s", 
        //              val_str(bcx.fcx.lcx.ccx.tn, llargs.val));
6146

6147 6148 6149 6150 6151 6152
        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);
6153
        i += 1u;
6154 6155 6156
    }
    // Now we're ready to do the upcall.

6157 6158
    // But first, we'll create a task.

6159 6160 6161 6162
    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]);
6163
    // Okay, start the task.
6164

6165
    auto llargs_i = bcx.build.PointerCast(llargs.val, T_int());
6166
    // Generate the wrapper function
6167

6168
    auto wrapper = mk_spawn_wrapper(bcx, func, args_ty);
6169 6170 6171
    bcx = wrapper.bcx;
    auto llfnptr_i = bcx.build.PointerCast(wrapper.val, T_int());
    // And start the task
6172

6173
    auto args_size = size_of(bcx, args_ty).val;
6174
    bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.start_task,
6175 6176
                   [bcx.fcx.lltaskptr, new_task, llfnptr_i, llargs_i,
                    args_size]);
E
Eric Holk 已提交
6177 6178 6179
    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];
6180
    ret res(bcx, new_task);
6181 6182
}

6183 6184
fn mk_spawn_wrapper(&@block_ctxt cx, &@ast::expr func, &ty::t args_ty) ->
   result {
6185 6186 6187 6188
    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,
6189
                   [rec(mode=ty::mo_alias(false), ty=args_ty)], ty::idx_nil,
6190 6191
                   0u);
    // TODO: construct a name based on tname
6192

6193
    let str wrap_name =
6194
        mangle_internal_name_by_path_and_seq(cx.fcx.lcx.ccx, cx.fcx.lcx.path,
6195
                                             "spawn_wrapper");
6196
    auto llfndecl = decl_cdecl_fn(llmod, wrap_name, wrapper_fn_type);
6197 6198 6199 6200
    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

6201
    let ValueRef arg = llvm::LLVMGetParam(fcx.llfn, 3u);
6202
    let vec[ValueRef] child_args =
6203
        [llvm::LLVMGetParam(fcx.llfn, 0u), llvm::LLVMGetParam(fcx.llfn, 1u),
6204 6205
         llvm::LLVMGetParam(fcx.llfn, 2u)];
    // unpack the arguments
6206 6207 6208

    alt (ty::struct(fcx.lcx.ccx.tcx, args_ty)) {
        case (ty::ty_tup(?elements)) {
6209
            auto i = 0;
6210
            for (ty::mt m in elements) {
6211 6212 6213 6214 6215 6216 6217 6218
                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
6219

6220 6221
    auto fnptr = trans_lval(fbcx, func).res;
    fbcx = fnptr.bcx;
6222
    auto llfnptr = fbcx.build.GEP(fnptr.val, [C_int(0), C_int(0)]);
6223
    auto llfn = fbcx.build.Load(llfnptr);
6224
    fbcx.build.FastCall(llfn, child_args);
6225 6226 6227
    fbcx.build.RetVoid();
    finish_fn(fcx, fbcx.llbb);
    // TODO: make sure we clean up everything we need to.
6228

6229 6230 6231
    ret res(cx, llfndecl);
}

6232 6233
fn trans_send(&@block_ctxt cx, &@ast::expr lhs, &@ast::expr rhs,
              &ast::ann ann) -> result {
6234 6235 6236 6237 6238
    auto bcx = cx;
    auto chn = trans_expr(bcx, lhs);
    bcx = chn.bcx;
    auto data = trans_expr(bcx, rhs);
    bcx = data.bcx;
6239
    auto chan_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
6240
    auto unit_ty;
6241
    alt (ty::struct(cx.fcx.lcx.ccx.tcx, chan_ty)) {
6242 6243
        case (ty::ty_chan(?t)) { unit_ty = t; }
        case (_) { bcx.fcx.lcx.ccx.sess.bug("non-chan type in trans_send"); }
6244
    }
6245 6246
    auto data_alloc = alloc_ty(bcx, unit_ty);
    bcx = data_alloc.bcx;
6247
    auto data_tmp = copy_val(bcx, INIT, data_alloc.val, data.val, unit_ty);
6248
    bcx = data_tmp.bcx;
6249
    find_scope_cx(bcx).cleanups +=
6250
        [clean(bind drop_ty(_, data_alloc.val, unit_ty))];
6251 6252 6253
    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,
6254
                   [bcx.fcx.lltaskptr, llchanval, lldataptr]);
6255
    ret res(bcx, chn.val);
B
Brian Anderson 已提交
6256 6257
}

6258 6259
fn trans_recv(&@block_ctxt cx, &@ast::expr lhs, &@ast::expr rhs,
              &ast::ann ann) -> result {
6260
    auto bcx = cx;
B
Brian Anderson 已提交
6261
    auto data = trans_lval(bcx, lhs);
6262
    assert (data.is_mem);
B
Brian Anderson 已提交
6263
    bcx = data.res.bcx;
6264
    auto unit_ty = node_ann_type(bcx.fcx.lcx.ccx, ann);
6265 6266
    // FIXME: calculate copy init-ness in typestate.

6267 6268
    ret recv_val(bcx, data.res.val, rhs, unit_ty, DROP_EXISTING);
}
6269

6270 6271
fn recv_val(&@block_ctxt cx, ValueRef lhs, &@ast::expr rhs, &ty::t unit_ty,
            copy_action action) -> result {
6272
    auto bcx = cx;
6273 6274
    auto prt = trans_expr(bcx, rhs);
    bcx = prt.bcx;
6275 6276 6277
    auto lldataptr = bcx.build.PointerCast(lhs, T_ptr(T_ptr(T_i8())));
    auto llportptr = bcx.build.PointerCast(prt.val, T_opaque_port_ptr());
    bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.recv,
6278
                   [bcx.fcx.lltaskptr, lldataptr, llportptr]);
6279
    auto data_load = load_if_immediate(bcx, lhs, unit_ty);
6280
    auto cp = copy_val(bcx, action, lhs, data_load, unit_ty);
6281
    bcx = cp.bcx;
6282
    // TODO: Any cleanup need to be done here?
6283

6284
    ret res(bcx, lhs);
B
Brian Anderson 已提交
6285 6286
}

L
Lindsey Kuper 已提交
6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318

/*

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

6320 6321 6322 6323 6324
// 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.
6325
fn trans_anon_obj(@block_ctxt bcx, &span sp, &ast::anon_obj anon_obj,
6326
                  &vec[ast::ty_param] ty_params, ast::def_id oid,
L
Lindsey Kuper 已提交
6327
                  &ast::ann ann) -> result {
6328 6329 6330 6331 6332 6333
    // 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).

6334
    assert (vec::len(ty_params) == 0u);
6335
    auto ccx = bcx.fcx.lcx.ccx;
L
Lindsey Kuper 已提交
6336 6337
    // If with_obj (the object being extended) exists, translate it, producing
    // a result.
6338

L
Lindsey Kuper 已提交
6339 6340
    let option::t[result] with_obj_val = none[result];
    alt (anon_obj.with_obj) {
6341 6342
        case (none) { }
        case (some(?e)) {
6343 6344 6345
            // 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.
6346

6347
            with_obj_val = some[result](trans_expr(bcx, e));
L
Lindsey Kuper 已提交
6348 6349
        }
    }
L
Lindsey Kuper 已提交
6350 6351 6352 6353
    // 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.

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

6359
    auto pair = alloca(bcx, llself_ty);
L
Lindsey Kuper 已提交
6360 6361 6362
    // 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'.
6363

6364 6365 6366 6367
    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)]);
6368 6369
    // 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.
6370

6371 6372 6373 6374 6375
    let vec[ast::obj_field] addtl_fields = [];
    alt (anon_obj.fields) {
        case (none) { }
        case (some(?fields)) { addtl_fields = fields; }
    }
6376 6377 6378 6379 6380 6381
    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 已提交
6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394
    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);
6395
    alt (anon_obj.fields) {
6396
        case (none) {
6397 6398
            // If the object we're translating has no fields or type
            // parameters, there's not much to do.
L
Lindsey Kuper 已提交
6399

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

6402
            bcx.build.Store(C_null(llbox_ty), pair_box);
L
Lindsey Kuper 已提交
6403
        }
6404 6405 6406
        case (some(?fields)) {
            // For the moment let's pretend that there are no additional
            // fields.
6407

6408 6409
            bcx.fcx.lcx.ccx.sess.unimpl("anon objs don't support " +
                                            "adding fields yet");
6410 6411
            // FIXME (issue #417): drop these fields into the newly created
            // object.
6412

L
Lindsey Kuper 已提交
6413 6414 6415
        }
    }
    // Return the object we built.
6416

L
Lindsey Kuper 已提交
6417
    ret res(bcx, pair);
L
Lindsey Kuper 已提交
6418 6419
}

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

P
Paul Stansifer 已提交
6423 6424 6425
    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);
6426
    auto bcx = cx;
6427
    find_scope_cx(cx).cleanups += [clean(bind drop_slot(_, llptr, ty))];
P
Paul Stansifer 已提交
6428
    alt (local.node.init) {
6429
        case (some(?init)) {
6430
            alt (init.op) {
6431
                case (ast::init_assign) {
6432 6433 6434
                    // 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.
6435 6436 6437 6438

                    ty =
                        node_ann_type(cx.fcx.lcx.ccx,
                                      ty::expr_ann(init.expr));
6439
                    auto sub = trans_expr(bcx, init.expr);
6440
                    bcx = copy_val(sub.bcx, INIT, llptr, sub.val, ty).bcx;
6441
                }
6442 6443
                case (ast::init_move) {
                    auto sub = trans_lval(bcx, init.expr);
6444 6445 6446
                    bcx =
                        move_val(sub.res.bcx, INIT, llptr, sub.res.val,
                                 ty).bcx;
6447
                }
6448
                case (ast::init_recv) {
6449 6450 6451
                    bcx = recv_val(bcx, llptr, init.expr, ty, INIT).bcx;
                }
            }
6452
        }
6453
        case (_) { bcx = zero_alloca(bcx, llptr, ty).bcx; }
6454 6455 6456 6457
    }
    ret res(bcx, llptr);
}

6458
fn zero_alloca(&@block_ctxt cx, ValueRef llptr, ty::t t) -> result {
6459
    auto bcx = cx;
6460
    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
6461
        auto llsz = size_of(bcx, t);
6462
        auto llalign = align_of(llsz.bcx, t);
6463
        bcx = call_bzero(llalign.bcx, llptr, llsz.val, llalign.val).bcx;
6464
    } else {
6465
        auto llty = type_of(bcx.fcx.lcx.ccx, cx.sp, t);
6466
        auto null = lib::llvm::llvm::LLVMConstNull(llty);
6467 6468 6469
        bcx.build.Store(null, llptr);
    }
    ret res(bcx, llptr);
6470
}
6471

6472
fn trans_stmt(&@block_ctxt cx, &ast::stmt s) -> result {
6473
    // FIXME Fill in cx.sp
6474

6475
    auto bcx = cx;
6476
    alt (s.node) {
6477 6478
        case (ast::stmt_expr(?e, _)) { bcx = trans_expr(cx, e).bcx; }
        case (ast::stmt_decl(?d, _)) {
6479
            alt (d.node) {
6480
                case (ast::decl_local(?local)) {
6481
                    bcx = init_local(bcx, local).bcx;
6482
                }
6483
                case (ast::decl_item(?i)) { trans_item(cx.fcx.lcx, *i); }
6484 6485
            }
        }
6486
        case (_) { cx.fcx.lcx.ccx.sess.unimpl("stmt variant"); }
6487
    }
6488
    ret res(bcx, C_nil());
6489 6490
}

6491
fn new_builder(BasicBlockRef llbb) -> builder {
6492 6493
    let BuilderRef llbuild = llvm::LLVMCreateBuilder();
    llvm::LLVMPositionBuilderAtEnd(llbuild, llbb);
6494
    ret builder(llbuild, @mutable false);
6495 6496
}

6497

6498 6499
// You probably don't want to use this one. See the
// next three functions instead.
6500
fn new_block_ctxt(&@fn_ctxt cx, &block_parent parent, block_kind kind,
G
Graydon Hoare 已提交
6501
                  &str name) -> @block_ctxt {
6502
    let vec[cleanup] cleanups = [];
6503
    auto s = str::buf("");
6504
    if (cx.lcx.ccx.sess.get_opts().save_temps) {
6505
        s = str::buf(cx.lcx.ccx.names.next(name));
6506
    }
6507
    let BasicBlockRef llbb = llvm::LLVMAppendBasicBlock(cx.llfn, s);
6508
    ret @rec(llbb=llbb,
6509
             build=new_builder(llbb),
6510
             parent=parent,
6511
             kind=kind,
6512
             mutable cleanups=cleanups,
6513
             sp=cx.sp,
6514 6515 6516
             fcx=cx);
}

6517

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

6523

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

6529
fn new_loop_scope_block_ctxt(&@block_ctxt bcx, &option::t[@block_ctxt] _cont,
G
Graydon Hoare 已提交
6530
                             &@block_ctxt _break, &str n) -> @block_ctxt {
6531 6532 6533 6534
    ret new_block_ctxt(bcx.fcx, parent_some(bcx),
                       LOOP_SCOPE_BLOCK(_cont, _break), n);
}

6535

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

6541
fn new_raw_block_ctxt(&@fn_ctxt fcx, BasicBlockRef llbb) -> @block_ctxt {
6542
    let vec[cleanup] cleanups = [];
6543 6544 6545 6546 6547 6548
    ret @rec(llbb=llbb,
             build=new_builder(llbb),
             parent=parent_none,
             kind=NON_SCOPE_BLOCK,
             mutable cleanups=cleanups,
             sp=fcx.sp,
6549
             fcx=fcx);
6550 6551
}

6552

6553 6554 6555 6556 6557 6558 6559
// 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.
6560 6561
fn trans_block_cleanups(&@block_ctxt cx, &@block_ctxt cleanup_cx) ->
   @block_ctxt {
6562
    auto bcx = cx;
6563
    if (cleanup_cx.kind == NON_SCOPE_BLOCK) {
6564
        assert (vec::len[cleanup](cleanup_cx.cleanups) == 0u);
6565
    }
6566
    auto i = vec::len[cleanup](cleanup_cx.cleanups);
6567 6568 6569
    while (i > 0u) {
        i -= 1u;
        auto c = cleanup_cx.cleanups.(i);
6570
        alt (c) { case (clean(?cfn)) { bcx = cfn(bcx).bcx; } }
6571
    }
6572 6573 6574
    ret bcx;
}

P
Paul Stansifer 已提交
6575
iter block_locals(&ast::block b) -> @ast::local {
6576 6577
    // FIXME: putting from inside an iter block doesn't work, so we can't
    // use the index here.
6578
    for (@ast::stmt s in b.node.stmts) {
6579
        alt (s.node) {
6580
            case (ast::stmt_decl(?d, _)) {
6581
                alt (d.node) {
6582 6583
                    case (ast::decl_local(?local)) { put local; }
                    case (_) {/* fall through */ }
6584 6585
                }
            }
6586
            case (_) {/* fall through */ }
6587 6588 6589 6590
        }
    }
}

G
Graydon Hoare 已提交
6591
fn llallocas_block_ctxt(&@fn_ctxt fcx) -> @block_ctxt {
6592
    let vec[cleanup] cleanups = [];
6593 6594 6595 6596 6597
    ret @rec(llbb=fcx.llallocas,
             build=new_builder(fcx.llallocas),
             parent=parent_none,
             kind=SCOPE_BLOCK,
             mutable cleanups=cleanups,
6598
             sp=fcx.sp,
6599 6600 6601
             fcx=fcx);
}

6602
fn alloc_ty(&@block_ctxt cx, &ty::t t) -> result {
6603
    auto val = C_int(0);
6604
    if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
6605 6606 6607 6608 6609 6610 6611 6612
        // NB: we have to run this particular 'size_of' in a
        // block_ctxt built on the llallocas block for the fn,
        // so that the size dominates the array_alloca that
        // comes next.

        auto n = size_of(llallocas_block_ctxt(cx.fcx), t);
        cx.fcx.llallocas = n.bcx.llbb;
        val = array_alloca(cx, T_i8(), n.val);
6613
    } else { val = alloca(cx, type_of(cx.fcx.lcx.ccx, cx.sp, t)); }
6614 6615 6616 6617 6618 6619
    // 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.
6620

6621
    ret res(cx, val);
6622 6623
}

P
Paul Stansifer 已提交
6624 6625
fn alloc_local(&@block_ctxt cx, &@ast::local local) -> result {
    auto t = node_ann_type(cx.fcx.lcx.ccx, local.node.ann);
6626
    auto r = alloc_ty(cx, t);
P
Paul Stansifer 已提交
6627
    r.bcx.fcx.lllocals.insert(local.node.id, r.val);
6628 6629 6630
    ret r;
}

6631
fn trans_block(&@block_ctxt cx, &ast::block b, &out_method output) -> result {
6632
    auto bcx = cx;
P
Paul Stansifer 已提交
6633
    for each (@ast::local local in block_locals(b)) {
6634
        // FIXME Update bcx.sp
6635
        bcx = alloc_local(bcx, local).bcx;
6636
    }
6637
    auto r = res(bcx, C_nil());
6638
    for (@ast::stmt s in b.node.stmts) {
6639 6640
        r = trans_stmt(bcx, *s);
        bcx = r.bcx;
6641

6642 6643
        // If we hit a terminator, control won't go any further so
        // we're in dead-code land. Stop here.
6644
        if (is_terminated(bcx)) { ret r; }
6645
    }
6646 6647
    fn accept_out_method(&@ast::expr expr) -> bool {
        ret alt (expr.node) {
6648 6649 6650 6651 6652
                case (ast::expr_if(_, _, _, _)) { true }
                case (ast::expr_alt(_, _, _)) { true }
                case (ast::expr_block(_, _)) { true }
                case (_) { false }
            };
6653
    }
6654
    alt (b.node.expr) {
6655
        case (some(?e)) {
6656 6657 6658
            auto pass = output != return && accept_out_method(e);
            if (pass) {
                r = trans_expr_out(bcx, e, output);
6659
            } else { r = trans_expr(bcx, e); }
6660
            bcx = r.bcx;
6661 6662
            auto ccx = cx.fcx.lcx.ccx;
            auto r_ty = ty::expr_ty(ccx.tcx, e);
6663
            if (is_terminated(bcx) || ty::type_is_bot(ccx.tcx, r_ty)) {
6664
                ret r;
6665 6666 6667 6668 6669 6670 6671
            } 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!
6672 6673 6674

                        auto res_copy =
                            copy_val(bcx, INIT, target, r.val, r_ty);
6675 6676
                        bcx = res_copy.bcx;
                        r = res(bcx, C_nil());
6677
                    }
6678
                    case (return) { }
6679
                }
6680 6681
            }
        }
6682
        case (none) { r = res(bcx, C_nil()); }
6683
    }
6684
    bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
6685
    ret res(bcx, r.val);
6686 6687
}

G
Graydon Hoare 已提交
6688
fn new_local_ctxt(&@crate_ctxt ccx) -> @local_ctxt {
6689 6690 6691
    let vec[str] pth = [];
    let vec[ast::ty_param] obj_typarams = [];
    let vec[ast::obj_field] obj_fields = [];
6692
    ret @rec(path=pth,
6693
             module_path=[ccx.crate_meta_name],
6694 6695 6696
             obj_typarams=obj_typarams,
             obj_fields=obj_fields,
             ccx=ccx);
6697 6698
}

6699

6700 6701 6702
// Creates the standard trio of basic blocks: allocas, copy-args, and derived
// tydescs.
fn mk_standard_basic_blocks(ValueRef llfn) ->
6703
   tup(BasicBlockRef, BasicBlockRef, BasicBlockRef) {
6704 6705 6706
    ret tup(llvm::LLVMAppendBasicBlock(llfn, str::buf("allocas")),
            llvm::LLVMAppendBasicBlock(llfn, str::buf("copy_args")),
            llvm::LLVMAppendBasicBlock(llfn, str::buf("derived_tydescs")));
6707 6708
}

6709

6710 6711 6712 6713 6714 6715
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args
6716
fn new_fn_ctxt(@local_ctxt cx, &span sp, ValueRef llfndecl) -> @fn_ctxt {
6717 6718 6719 6720 6721 6722 6723
    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]();
6724
    auto derived_tydescs =
6725
        map::mk_hashmap[ty::t, derived_tydesc_info](ty::hash_ty, ty::eq_ty);
6726
    auto llbbs = mk_standard_basic_blocks(llfndecl);
6727
    ret @rec(llfn=llfndecl,
6728
             lltaskptr=lltaskptr,
6729 6730
             llenv=llenv,
             llretptr=llretptr,
6731 6732 6733
             mutable llallocas=llbbs._0,
             mutable llcopyargs=llbbs._1,
             mutable llderivedtydescs=llbbs._2,
L
Lindsey Kuper 已提交
6734
             mutable llself=none[val_self_pair],
6735
             mutable lliterbody=none[ValueRef],
6736
             llargs=llargs,
6737
             llobjfields=llobjfields,
6738
             lllocals=lllocals,
6739
             llupvars=llupvars,
6740
             mutable lltydescs=vec::empty[ValueRef](),
6741
             derived_tydescs=derived_tydescs,
6742
             sp=sp,
6743
             lcx=cx);
6744 6745
}

6746

6747 6748 6749 6750 6751 6752 6753
// NB: must keep 4 fns in sync:
//
//  - type_of_fn_full
//  - create_llargs_for_fn_args.
//  - new_fn_ctxt
//  - trans_args

L
Lindsey Kuper 已提交
6754 6755 6756 6757 6758 6759 6760
// 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
6761 6762
fn create_llargs_for_fn_args(&@fn_ctxt cx, ast::proto proto,
                             option::t[ty_self_pair] ty_self, ty::t ret_ty,
6763 6764
                             &vec[ast::arg] args,
                             &vec[ast::ty_param] ty_params) {
L
Lindsey Kuper 已提交
6765 6766 6767
    // 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.
6768

6769
    auto arg_n = 3u;
6770
    alt (ty_self) {
6771
        case (some(?tt)) {
6772
            cx.llself = some[val_self_pair](rec(v=cx.llenv, t=tt._1));
6773
        }
6774
        case (none) {
6775
            auto i = 0u;
6776 6777
            for (ast::ty_param tp in ty_params) {
                auto llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
6778
                assert (llarg as int != 0);
6779
                cx.lltydescs += [llarg];
6780
                arg_n += 1u;
6781
                i += 1u;
6782
            }
6783
        }
6784
    }
L
Lindsey Kuper 已提交
6785 6786 6787
    // 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.
6788

6789 6790
    if (proto == ast::proto_iter) {
        auto llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
6791
        assert (llarg as int != 0);
6792 6793 6794
        cx.lliterbody = some[ValueRef](llarg);
        arg_n += 1u;
    }
6795

L
Lindsey Kuper 已提交
6796 6797
    // Populate the llargs field of the function context with the ValueRefs
    // that we get from llvm::LLVMGetParam for each argument.
6798 6799
    for (ast::arg arg in args) {
        auto llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
6800
        assert (llarg as int != 0);
6801 6802 6803 6804 6805
        cx.llargs.insert(arg.id, llarg);
        arg_n += 1u;
    }
}

6806

6807 6808 6809
// 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.
6810
fn copy_any_self_to_alloca(@fn_ctxt fcx, option::t[ty_self_pair] ty_self) {
6811
    auto bcx = llallocas_block_ctxt(fcx);
6812
    alt ({ fcx.llself }) {
L
Lindsey Kuper 已提交
6813
        case (some(?pair)) {
6814
            alt (ty_self) {
L
Lindsey Kuper 已提交
6815
                case (some[ty_self_pair](?tt)) {
6816
                    auto a = alloca(bcx, tt._0);
L
Lindsey Kuper 已提交
6817
                    bcx.build.Store(pair.v, a);
6818
                    fcx.llself = some[val_self_pair](rec(v=a, t=pair.t));
6819 6820 6821
                }
            }
        }
6822
        case (_) { }
6823
    }
6824 6825
}

6826
fn copy_args_to_allocas(@fn_ctxt fcx, vec[ast::arg] args,
6827
                        vec[ty::arg] arg_tys) {
6828 6829
    auto bcx = new_raw_block_ctxt(fcx, fcx.llcopyargs);
    let uint arg_n = 0u;
6830
    for (ast::arg aarg in args) {
6831
        if (aarg.mode == ast::val) {
6832
            auto arg_t = type_of_arg(bcx.fcx.lcx, fcx.sp, arg_tys.(arg_n));
6833
            auto a = alloca(bcx, arg_t);
6834
            auto argval = bcx.fcx.llargs.get(aarg.id);
6835
            bcx.build.Store(argval, a);
6836
            // Overwrite the llargs entry for this arg with its alloca.
6837

6838
            bcx.fcx.llargs.insert(aarg.id, a);
6839
        }
6840 6841 6842 6843
        arg_n += 1u;
    }
}

6844
fn add_cleanups_for_args(&@block_ctxt bcx, vec[ast::arg] args,
6845
                         vec[ty::arg] arg_tys) {
6846
    let uint arg_n = 0u;
6847
    for (ast::arg aarg in args) {
6848
        if (aarg.mode == ast::val) {
6849 6850
            auto argval = bcx.fcx.llargs.get(aarg.id);
            find_scope_cx(bcx).cleanups +=
6851
                [clean(bind drop_slot(_, argval, arg_tys.(arg_n).ty))];
6852 6853 6854 6855 6856
        }
        arg_n += 1u;
    }
}

G
Graydon Hoare 已提交
6857
fn is_terminated(&@block_ctxt cx) -> bool {
6858 6859
    auto inst = llvm::LLVMGetLastInstruction(cx.llbb);
    ret llvm::LLVMIsATerminatorInst(inst) as int != 0;
6860 6861
}

6862
fn arg_tys_of_fn(&@crate_ctxt ccx, ast::ann ann) -> vec[ty::arg] {
6863
    alt (ty::struct(ccx.tcx, ty::ann_to_type(ccx.tcx, ann))) {
6864
        case (ty::ty_fn(_, ?arg_tys, _, _, _)) { ret arg_tys; }
6865 6866 6867
    }
}

6868 6869
fn ret_ty_of_fn_ty(&@crate_ctxt ccx, ty::t t) -> ty::t {
    alt (ty::struct(ccx.tcx, t)) {
6870
        case (ty::ty_fn(_, _, ?ret_ty, _, _)) { ret ret_ty; }
6871
        case (_) {
6872 6873
            ccx.sess.bug("ret_ty_of_fn_ty() called on non-function type: " +
                             ty_to_str(ccx.tcx, t));
6874
        }
6875 6876 6877
    }
}

6878
fn ret_ty_of_fn(&@crate_ctxt ccx, ast::ann ann) -> ty::t {
6879
    ret ret_ty_of_fn_ty(ccx, ty::ann_to_type(ccx.tcx, ann));
6880 6881
}

L
Lindsey Kuper 已提交
6882
fn populate_fn_ctxt_from_llself(@fn_ctxt fcx, val_self_pair llself) {
6883
    auto bcx = llallocas_block_ctxt(fcx);
6884
    let vec[ty::t] field_tys = [];
6885
    for (ast::obj_field f in bcx.fcx.lcx.obj_fields) {
6886
        field_tys += [node_ann_type(bcx.fcx.lcx.ccx, f.ann)];
6887
    }
6888 6889 6890
    // Synthesize a tuple type for the fields so that GEP_tup_like() can work
    // its magic.

6891
    auto fields_tup_ty = ty::mk_imm_tup(fcx.lcx.ccx.tcx, field_tys);
6892
    auto n_typarams = vec::len[ast::ty_param](bcx.fcx.lcx.obj_typarams);
6893
    let TypeRef llobj_box_ty = T_obj_ptr(bcx.fcx.lcx.ccx.tn, n_typarams);
6894
    auto box_cell =
6895
        bcx.build.GEP(llself.v, [C_int(0), C_int(abi::obj_field_box)]);
6896 6897
    auto box_ptr = bcx.build.Load(box_cell);
    box_ptr = bcx.build.PointerCast(box_ptr, llobj_box_ty);
6898 6899 6900 6901
    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)]);
6902 6903 6904
    // The object fields immediately follow the type parameters, so we skip
    // over them to get the pointer.

6905 6906
    auto et = llvm::LLVMGetElementType(val_ty(obj_typarams));
    auto obj_fields = bcx.build.Add(vp2i(bcx, obj_typarams), llsize_of(et));
6907 6908 6909
    // 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 *.
6910

6911
    if (!ty::type_has_dynamic_size(fcx.lcx.ccx.tcx, fields_tup_ty)) {
6912
        auto llfields_ty = type_of(fcx.lcx.ccx, fcx.sp, fields_tup_ty);
6913
        obj_fields = vi2p(bcx, obj_fields, T_ptr(llfields_ty));
6914
    } else { obj_fields = vi2p(bcx, obj_fields, T_ptr(T_i8())); }
6915
    let int i = 0;
6916
    for (ast::ty_param p in fcx.lcx.obj_typarams) {
6917 6918
        let ValueRef lltyparam =
            bcx.build.GEP(obj_typarams, [C_int(0), C_int(i)]);
6919
        lltyparam = bcx.build.Load(lltyparam);
6920
        fcx.lltydescs += [lltyparam];
6921 6922 6923
        i += 1;
    }
    i = 0;
6924
    for (ast::obj_field f in fcx.lcx.obj_fields) {
6925
        auto rslt = GEP_tup_like(bcx, fields_tup_ty, obj_fields, [0, i]);
6926
        bcx = llallocas_block_ctxt(fcx);
6927
        auto llfield = rslt.val;
6928
        fcx.llobjfields.insert(f.id, llfield);
6929 6930
        i += 1;
    }
6931
    fcx.llallocas = bcx.llbb;
6932 6933
}

6934

6935 6936 6937 6938 6939 6940 6941
// Ties up the llallocas -> llcopyargs -> llderivedtydescs -> lltop edges.
fn finish_fn(&@fn_ctxt fcx, BasicBlockRef lltop) {
    new_builder(fcx.llallocas).Br(fcx.llcopyargs);
    new_builder(fcx.llcopyargs).Br(fcx.llderivedtydescs);
    new_builder(fcx.llderivedtydescs).Br(lltop);
}

6942

6943 6944
// trans_fn: creates an LLVM function corresponding to a source language
// function.
6945
fn trans_fn(@local_ctxt cx, &span sp, &ast::_fn f, ValueRef llfndecl,
6946 6947
            option::t[ty_self_pair] ty_self, &vec[ast::ty_param] ty_params,
            &ast::ann ann) {
6948
    set_uwtable(llfndecl);
L
Lindsey Kuper 已提交
6949
    // Set up arguments to the function.
6950

6951 6952 6953 6954
    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);
6955
    copy_any_self_to_alloca(fcx, ty_self);
6956 6957 6958
    alt ({ fcx.llself }) {
        case (some(?llself)) { populate_fn_ctxt_from_llself(fcx, llself); }
        case (_) { }
6959
    }
6960
    auto arg_tys = arg_tys_of_fn(fcx.lcx.ccx, ann);
6961
    copy_args_to_allocas(fcx, f.decl.inputs, arg_tys);
L
Lindsey Kuper 已提交
6962 6963
    // Create the first basic block in the function and keep a handle on it to
    //  pass to finish_fn later.
6964

6965
    auto bcx = new_top_block_ctxt(fcx);
6966
    add_cleanups_for_args(bcx, f.decl.inputs, arg_tys);
6967
    auto lltop = bcx.llbb;
6968
    auto block_ty = node_ann_type(cx.ccx, f.body.node.a);
L
Lindsey Kuper 已提交
6969 6970 6971 6972
    // 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).
6973

6974 6975 6976 6977 6978
    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) };
6979
    if (!is_terminated(res.bcx)) {
6980 6981
        // FIXME: until LLVM has a unit type, we are moving around
        // C_nil values rather than their void type.
6982

6983
        res.bcx.build.RetVoid();
6984
    }
L
Lindsey Kuper 已提交
6985
    // Insert the mandatory first few basic blocks before lltop.
6986

6987
    finish_fn(fcx, lltop);
6988 6989
}

6990

L
Lindsey Kuper 已提交
6991 6992
// Create a vtable for an object being translated.  Returns a pointer into
// read-only memory.
6993 6994
fn create_vtbl(@local_ctxt cx, TypeRef llself_ty, ty::t self_ty,
               &ast::_obj ob, &vec[ast::ty_param] ty_params) -> ValueRef {
6995 6996
    auto dtor = C_null(T_ptr(T_i8()));
    alt (ob.dtor) {
6997
        case (some(?d)) {
6998
            auto dtor_1 = trans_dtor(cx, llself_ty, self_ty, ty_params, d);
6999
            dtor = llvm::LLVMConstBitCast(dtor_1, val_ty(dtor));
7000
        }
7001
        case (none) { }
7002
    }
7003
    let vec[ValueRef] methods = [dtor];
7004
    fn meth_lteq(&@ast::method a, &@ast::method b) -> bool {
7005
        ret str::lteq(a.node.ident, b.node.ident);
7006
    }
7007 7008
    auto meths =
        std::sort::merge_sort[@ast::method](bind meth_lteq(_, _), ob.methods);
7009
    for (@ast::method m in meths) {
7010
        auto llfnty = T_nil();
7011
        alt (ty::struct(cx.ccx.tcx, node_ann_type(cx.ccx, m.node.ann))) {
7012
            case (ty::ty_fn(?proto, ?inputs, ?output, _, _)) {
7013 7014 7015 7016
                llfnty =
                    type_of_fn_full(cx.ccx, m.span, proto,
                                    some[TypeRef](llself_ty), inputs, output,
                                    vec::len[ast::ty_param](ty_params));
7017 7018
            }
        }
7019 7020
        let @local_ctxt mcx =
            @rec(path=cx.path + ["method", m.node.ident] with *cx);
7021
        let str s = mangle_internal_name_by_path(mcx.ccx, mcx.path);
7022 7023
        let ValueRef llfn =
            decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty);
7024 7025 7026
        // 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.
7027

7028 7029
        cx.ccx.item_ids.insert(m.node.id, llfn);
        cx.ccx.item_symbols.insert(m.node.id, s);
7030
        trans_fn(mcx, m.span, m.node.meth, llfn,
7031 7032
                 some[ty_self_pair](tup(llself_ty, self_ty)), ty_params,
                 m.node.ann);
7033
        methods += [llfn];
G
Graydon Hoare 已提交
7034
    }
7035
    auto vtbl = C_struct(methods);
7036 7037 7038
    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));
7039 7040
    llvm::LLVMSetInitializer(gvar, vtbl);
    llvm::LLVMSetGlobalConstant(gvar, True);
7041 7042
    llvm::LLVMSetLinkage(gvar,
                         lib::llvm::LLVMInternalLinkage as llvm::Linkage);
7043
    ret gvar;
G
Graydon Hoare 已提交
7044 7045
}

7046 7047
fn trans_dtor(@local_ctxt cx, TypeRef llself_ty, ty::t self_ty,
              &vec[ast::ty_param] ty_params, &@ast::method dtor) -> ValueRef {
7048
    auto llfnty = T_dtor(cx.ccx, dtor.span, llself_ty);
7049
    let str s = mangle_internal_name_by_path(cx.ccx, cx.path + ["drop"]);
7050 7051 7052
    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);
7053
    trans_fn(cx, dtor.span, dtor.node.meth, llfn,
7054 7055
             some[ty_self_pair](tup(llself_ty, self_ty)), ty_params,
             dtor.node.ann);
7056 7057 7058
    ret llfn;
}

7059

7060 7061
// trans_obj: creates an LLVM function that is the object constructor for the
// object being translated.
7062
fn trans_obj(@local_ctxt cx, &span sp, &ast::_obj ob, ast::def_id oid,
7063
             &vec[ast::ty_param] ty_params, &ast::ann ann) {
7064 7065 7066
    // To make a function, we have to create a function context and, inside
    // that, a number of block contexts for which code is generated.

7067 7068
    auto ccx = cx.ccx;
    auto llctor_decl = ccx.item_ids.get(oid);
7069 7070 7071 7072
    // 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 已提交
7073 7074
    // The fields of our object will become the arguments to the function
    // we're creating.
7075

7076
    let vec[ast::arg] fn_args = [];
7077
    for (ast::obj_field f in ob.fields) {
7078 7079
        fn_args +=
            [rec(mode=ast::alias(false), ty=f.ty, ident=f.ident, id=f.id)];
7080
    }
7081
    auto fcx = new_fn_ctxt(cx, sp, llctor_decl);
L
Lindsey Kuper 已提交
7082
    // Both regular arguments and type parameters are handled here.
7083

7084 7085
    create_llargs_for_fn_args(fcx, ast::proto_fn, none[ty_self_pair],
                              ret_ty_of_fn(ccx, ann), fn_args, ty_params);
7086
    let vec[ty::arg] arg_tys = arg_tys_of_fn(ccx, ann);
7087
    copy_args_to_allocas(fcx, fn_args, arg_tys);
L
Lindsey Kuper 已提交
7088
    //  Create the first block context in the function and keep a handle on it
7089
    //  to pass to finish_fn later.
7090

7091 7092
    auto bcx = new_top_block_ctxt(fcx);
    auto lltop = bcx.llbb;
L
Lindsey Kuper 已提交
7093 7094
    // 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.
7095

7096
    auto self_ty = ret_ty_of_fn(ccx, ann);
7097
    auto llself_ty = type_of(ccx, sp, self_ty);
L
Lindsey Kuper 已提交
7098 7099 7100 7101 7102
    // 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.)
7103

7104
    auto pair = bcx.fcx.llretptr;
L
Lindsey Kuper 已提交
7105 7106 7107 7108
    // 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'.

7109 7110 7111 7112
    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 已提交
7113 7114 7115 7116
    // 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.
7117

L
Lindsey Kuper 已提交
7118
    auto vtbl = create_vtbl(cx, llself_ty, self_ty, ob, ty_params);
7119
    bcx.build.Store(vtbl, pair_vtbl);
L
Lindsey Kuper 已提交
7120 7121 7122
    // 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.
7123

L
Lindsey Kuper 已提交
7124 7125 7126 7127 7128 7129 7130
    // 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.
7131

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

7137
        // Store null into pair, if no args or typarams.
7138 7139
        bcx.build.Store(C_null(llbox_ty), pair_box);
    } else {
L
Lindsey Kuper 已提交
7140 7141
        // Otherwise, we have to synthesize a big structural type for the
        // object body.
7142
        let vec[ty::t] obj_fields = [];
7143
        for (ty::arg a in arg_tys) { vec::push[ty::t](obj_fields, a.ty); }
L
Lindsey Kuper 已提交
7144

7145
        // Tuple type for fields: [field, ...]
7146 7147
        let ty::t fields_ty = ty::mk_imm_tup(ccx.tcx, obj_fields);

7148
        auto tydesc_ty = ty::mk_type(ccx.tcx);
7149
        let vec[ty::t] tps = [];
7150
        for (ast::ty_param tp in ty_params) {
7151
            vec::push[ty::t](tps, tydesc_ty);
7152
        }
7153 7154

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

7157
        // Tuple type for body: [tydesc_ty, [typaram, ...], [field, ...]]
7158 7159
        let ty::t body_ty =
            ty::mk_imm_tup(ccx.tcx, [tydesc_ty, typarams_ty, fields_ty]);
7160

7161 7162
        // Hand this type we've synthesized off to trans_malloc_boxed, which
        // allocates a box, including space for a refcount.
7163
        auto box = trans_malloc_boxed(bcx, body_ty);
7164
        bcx = box.bcx;
7165

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

7170
        // Grab onto the refcount and body parts of the box we allocated.
7171 7172 7173 7174 7175 7176 7177
        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]);
7178 7179
        bcx = body.bcx;
        bcx.build.Store(C_int(1), rc.val);
7180

7181 7182
        // Put together a tydesc for the body, so that the object can later be
        // freed by calling through its tydesc.
7183 7184 7185 7186 7187 7188

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

7190
        auto body_tydesc =
7191
            GEP_tup_like(bcx, body_ty, body.val,
7192
                         [0, abi::obj_body_elt_tydesc]);
7193
        bcx = body_tydesc.bcx;
7194 7195 7196
        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);
7197
        lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
7198 7199
        bcx = body_td.bcx;
        bcx.build.Store(body_td.val, body_tydesc.val);
7200

7201 7202 7203 7204 7205 7206 7207
        // 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.)

7208 7209 7210
        // Copy typarams into captured typarams.
        auto body_typarams =
            GEP_tup_like(bcx, body_ty, body.val,
7211
                         [0, abi::obj_body_elt_typarams]);
7212 7213
        bcx = body_typarams.bcx;
        let int i = 0;
7214
        for (ast::ty_param tp in ty_params) {
7215
            auto typaram = bcx.fcx.lltydescs.(i);
7216 7217
            auto capture =
                GEP_tup_like(bcx, typarams_ty, body_typarams.val, [0, i]);
7218
            bcx = capture.bcx;
7219
            bcx = copy_val(bcx, INIT, capture.val, typaram, tydesc_ty).bcx;
7220 7221
            i += 1;
        }
7222

7223
        // Copy args into body fields.
7224
        auto body_fields =
7225
            GEP_tup_like(bcx, body_ty, body.val,
7226
                         [0, abi::obj_body_elt_fields]);
7227
        bcx = body_fields.bcx;
7228
        i = 0;
7229
        for (ast::obj_field f in ob.fields) {
7230
            auto arg = bcx.fcx.llargs.get(f.id);
7231
            arg = load_if_immediate(bcx, arg, arg_tys.(i).ty);
7232 7233
            auto field =
                GEP_tup_like(bcx, fields_ty, body_fields.val, [0, i]);
7234
            bcx = field.bcx;
7235
            bcx = copy_val(bcx, INIT, field.val, arg, arg_tys.(i).ty).bcx;
7236 7237
            i += 1;
        }
7238

7239
        // Store box ptr in outer pair.
7240
        auto p = bcx.build.PointerCast(box.val, llbox_ty);
7241
        bcx.build.Store(p, pair_box);
7242
    }
7243
    bcx.build.RetVoid();
7244

7245
    // Insert the mandatory first few basic blocks before lltop.
7246
    finish_fn(fcx, lltop);
7247 7248
}

7249 7250 7251
fn trans_tag_variant(@local_ctxt cx, ast::def_id tag_id,
                     &ast::variant variant, int index,
                     &vec[ast::ty_param] ty_params) {
7252
    if (vec::len[ast::variant_arg](variant.node.args) == 0u) {
7253
        ret; // nullary constructors are just constants
7254

7255
    }
7256
    // Translate variant arguments to function arguments.
7257

7258
    let vec[ast::arg] fn_args = [];
7259
    auto i = 0u;
7260
    for (ast::variant_arg varg in variant.node.args) {
7261 7262 7263 7264 7265
        fn_args +=
            [rec(mode=ast::alias(false),
                 ty=varg.ty,
                 ident="arg" + uint::to_str(i, 10u),
                 id=varg.id)];
7266
    }
7267
    assert (cx.ccx.item_ids.contains_key(variant.node.id));
7268
    let ValueRef llfndecl = cx.ccx.item_ids.get(variant.node.id);
7269
    auto fcx = new_fn_ctxt(cx, variant.span, llfndecl);
7270 7271 7272
    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);
7273
    let vec[ty::t] ty_param_substs = [];
7274
    i = 0u;
7275
    for (ast::ty_param tp in ty_params) {
7276
        ty_param_substs += [ty::mk_param(cx.ccx.tcx, i)];
7277
        i += 1u;
7278
    }
7279
    auto arg_tys = arg_tys_of_fn(cx.ccx, variant.node.ann);
7280
    copy_args_to_allocas(fcx, fn_args, arg_tys);
7281 7282
    auto bcx = new_top_block_ctxt(fcx);
    auto lltop = bcx.llbb;
7283 7284
    // Cast the tag to a type we can GEP into.

7285 7286 7287
    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)]);
7288
    bcx.build.Store(C_int(index), lldiscrimptr);
7289
    auto llblobptr = bcx.build.GEP(lltagptr, [C_int(0), C_int(1)]);
7290
    i = 0u;
7291
    for (ast::variant_arg va in variant.node.args) {
7292 7293 7294
        auto rslt =
            GEP_tag(bcx, llblobptr, tag_id, variant.node.id, ty_param_substs,
                    i as int);
7295 7296
        bcx = rslt.bcx;
        auto lldestptr = rslt.val;
7297 7298 7299 7300
        // 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.

7301 7302
        auto llargptr =
            bcx.build.PointerCast(fcx.llargs.get(va.id), val_ty(lldestptr));
7303 7304
        auto arg_ty = arg_tys.(i).ty;
        auto llargval;
7305 7306
        if (ty::type_is_structural(cx.ccx.tcx, arg_ty) ||
                ty::type_has_dynamic_size(cx.ccx.tcx, arg_ty)) {
7307
            llargval = llargptr;
7308
        } else { llargval = bcx.build.Load(llargptr); }
7309
        rslt = copy_val(bcx, INIT, lldestptr, llargval, arg_ty);
7310
        bcx = rslt.bcx;
7311 7312 7313
        i += 1u;
    }
    bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
7314
    bcx.build.RetVoid();
7315
    finish_fn(fcx, lltop);
7316 7317
}

7318

7319 7320 7321
// 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?
7322
fn trans_const_expr(&@crate_ctxt cx, @ast::expr e) -> ValueRef {
7323
    alt (e.node) {
7324
        case (ast::expr_lit(?lit, ?ann)) { ret trans_lit(cx, *lit, ann); }
7325 7326 7327
        case (_) {
            cx.sess.span_unimpl(e.span, "consts that's not a plain literal");
        }
7328 7329 7330
    }
}

7331 7332
fn trans_const(&@crate_ctxt cx, @ast::expr e, &ast::def_id cid,
               &ast::ann ann) {
7333 7334
    auto t = node_ann_type(cx, ann);
    auto v = trans_const_expr(cx, e);
7335 7336
    // The scalars come back as 1st class LLVM vals
    // which we have to stick into global constants.
7337

7338
    auto g = cx.consts.get(cid);
7339 7340
    llvm::LLVMSetInitializer(g, v);
    llvm::LLVMSetGlobalConstant(g, True);
7341 7342
}

7343
fn trans_item(@local_ctxt cx, &ast::item item) {
7344
    alt (item.node) {
7345 7346 7347
        case (ast::item_fn(?f, ?tps)) {
            auto sub_cx = extend_path(cx, item.ident);
            auto llfndecl = cx.ccx.item_ids.get(item.id);
7348
            trans_fn(sub_cx, item.span, f, llfndecl, none[ty_self_pair], tps,
7349
                     item.ann);
7350
        }
7351
        case (ast::item_obj(?ob, ?tps, ?ctor_id)) {
7352 7353
            auto sub_cx =
                @rec(obj_typarams=tps, obj_fields=ob.fields
7354 7355
                     with *extend_path(cx, item.ident));
            trans_obj(sub_cx, item.span, ob, ctor_id, tps, item.ann);
7356
        }
7357
        case (ast::item_mod(?m)) {
7358
            auto sub_cx =
7359 7360
                @rec(path=cx.path + [item.ident],
                     module_path=cx.module_path + [item.ident] with *cx);
7361
            trans_mod(sub_cx, m);
7362
        }
7363 7364
        case (ast::item_tag(?variants, ?tps)) {
            auto sub_cx = extend_path(cx, item.ident);
7365
            auto i = 0;
7366
            for (ast::variant variant in variants) {
7367
                trans_tag_variant(sub_cx, item.id, variant, i, tps);
7368
                i += 1;
7369 7370
            }
        }
7371 7372
        case (ast::item_const(_, ?expr)) {
            trans_const(cx.ccx, expr, item.id, item.ann);
7373
        }
7374
        case (_) {/* fall through */ }
7375 7376 7377
    }
}

7378

7379 7380 7381 7382 7383
// 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.
7384
fn trans_mod(@local_ctxt cx, &ast::_mod m) {
7385
    for (@ast::item item in m.items) { trans_item(cx, *item); }
7386 7387
}

7388 7389
fn get_pair_fn_ty(TypeRef llpairty) -> TypeRef {
    // Bit of a kludge: pick the fn typeref out of the pair.
7390

7391
    ret struct_elt(llpairty, 0u);
7392 7393
}

7394 7395
fn decl_fn_and_pair(&@crate_ctxt ccx, &span sp, vec[str] path, str flav,
                    vec[ast::ty_param] ty_params, &ast::ann ann,
7396
                    ast::def_id id) {
7397
    auto llfty;
7398
    alt (ty::struct(ccx.tcx, node_ann_type(ccx, ann))) {
7399
        case (ty::ty_fn(?proto, ?inputs, ?output, _, _)) {
7400 7401 7402
            llfty =
                type_of_fn(ccx, sp, proto, inputs, output,
                           vec::len[ast::ty_param](ty_params));
7403 7404
        }
        case (_) {
7405
            ccx.sess.bug("decl_fn_and_pair(): fn item doesn't have fn type!");
7406 7407
        }
    }
7408 7409
    let bool is_main =
        str::eq(vec::top(path), "main") && !ccx.sess.get_opts().shared;
7410
    // Declare the function itself.
7411

7412 7413 7414 7415
    let str s =
        if (is_main) {
            "_rust_main"
        } else { mangle_internal_name_by_path(ccx, path) };
7416
    let ValueRef llfn = decl_internal_fastcall_fn(ccx.llmod, s, llfty);
7417
    // Declare the global constant pair that points to it.
7418

7419
    let str ps = mangle_exported_name(ccx, path, node_ann_type(ccx, ann));
7420
    register_fn_pair(ccx, ps, llfty, llfn, id);
7421
    if (is_main) {
7422 7423 7424
        if (ccx.main_fn != none[ValueRef]) {
            ccx.sess.span_err(sp, "multiple 'main' functions");
        }
7425 7426
        llvm::LLVMSetLinkage(llfn,
                             lib::llvm::LLVMExternalLinkage as llvm::Linkage);
7427 7428
        ccx.main_fn = some(llfn);
    }
7429 7430
}

7431 7432
fn create_fn_pair(&@crate_ctxt cx, str ps, TypeRef llfnty, ValueRef llfn,
                  bool external) -> ValueRef {
7433 7434
    auto gvar =
        llvm::LLVMAddGlobal(cx.llmod, T_fn_pair(cx.tn, llfnty), str::buf(ps));
7435
    auto pair = C_struct([llfn, C_null(T_opaque_closure_ptr(cx.tn))]);
7436 7437
    llvm::LLVMSetInitializer(gvar, pair);
    llvm::LLVMSetGlobalConstant(gvar, True);
7438
    if (!external) {
7439 7440
        llvm::LLVMSetLinkage(gvar,
                             lib::llvm::LLVMInternalLinkage as llvm::Linkage);
7441
    }
7442 7443
    ret gvar;
}
7444

7445 7446 7447
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.
7448 7449 7450

    auto gvar =
        create_fn_pair(cx, ps, llfnty, llfn, cx.sess.get_opts().shared);
7451
    cx.item_ids.insert(id, llfn);
P
Patrick Walton 已提交
7452
    cx.item_symbols.insert(id, ps);
7453 7454 7455
    cx.fn_pairs.insert(id, gvar);
}

7456

7457
// Returns the number of type parameters that the given native function has.
7458
fn native_fn_ty_param_count(&@crate_ctxt cx, &ast::def_id id) -> uint {
7459 7460 7461
    auto count;
    auto native_item = cx.native_items.get(id);
    alt (native_item.node) {
7462
        case (ast::native_item_ty(_, _)) {
7463
            cx.sess.bug("decl_native_fn_and_pair(): native fn isn't " +
7464
                            "actually a fn");
7465
        }
7466
        case (ast::native_item_fn(_, _, _, ?tps, _, _)) {
7467
            count = vec::len[ast::ty_param](tps);
7468 7469 7470 7471 7472
        }
    }
    ret count;
}

7473
fn native_fn_wrapper_type(&@crate_ctxt cx, &span sp, uint ty_param_count,
7474
                          ty::t x) -> TypeRef {
7475 7476
    alt (ty::struct(cx.tcx, x)) {
        case (ty::ty_native_fn(?abi, ?args, ?out)) {
7477
            ret type_of_fn(cx, sp, ast::proto_fn, args, out, ty_param_count);
7478 7479 7480 7481
        }
    }
}

7482 7483
fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, vec[str] path,
                           str name, &ast::ann ann, ast::def_id id) {
7484
    auto num_ty_param = native_fn_ty_param_count(ccx, id);
7485
    // Declare the wrapper.
7486

7487
    auto t = node_ann_type(ccx, ann);
7488
    auto wrapper_type = native_fn_wrapper_type(ccx, sp, num_ty_param, t);
7489
    let str s = mangle_internal_name_by_path(ccx, path);
7490 7491
    let ValueRef wrapper_fn =
        decl_internal_fastcall_fn(ccx.llmod, s, wrapper_type);
7492
    // Declare the global constant pair that points to it.
7493

7494
    let str ps = mangle_exported_name(ccx, path, node_ann_type(ccx, ann));
7495
    register_fn_pair(ccx, ps, wrapper_type, wrapper_fn, id);
7496
    // Build the wrapper.
7497

7498
    auto fcx = new_fn_ctxt(new_local_ctxt(ccx), sp, wrapper_fn);
7499
    auto bcx = new_top_block_ctxt(fcx);
7500
    auto lltop = bcx.llbb;
7501
    // Declare the function itself.
7502

7503
    auto item = ccx.native_items.get(id);
7504
    auto fn_type = node_ann_type(ccx, ann); // NB: has no type params
7505

7506
    auto abi = ty::ty_fn_abi(ccx.tcx, fn_type);
7507 7508 7509
    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);
7510 7511 7512 7513
    // 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.

7514 7515
    auto rty_is_nil =
        ty::type_is_nil(ccx.tcx, ty::ty_fn_ret(ccx.tcx, fn_type));
7516
    auto pass_task;
7517
    auto cast_to_i32;
7518
    alt (abi) {
7519
        case (ast::native_abi_rust) { pass_task = true; cast_to_i32 = true; }
7520
        case (ast::native_abi_rust_intrinsic) {
7521
            pass_task = true;
7522
            cast_to_i32 = false;
7523
        }
7524
        case (ast::native_abi_cdecl) {
7525
            pass_task = false;
7526
            cast_to_i32 = true;
7527
        }
7528
        case (ast::native_abi_llvm) {
7529
            pass_task = false;
7530 7531 7532 7533 7534 7535
            cast_to_i32 = false;
        }
    }
    auto lltaskptr;
    if (cast_to_i32) {
        lltaskptr = vp2i(bcx, fcx.lltaskptr);
7536
    } else { lltaskptr = fcx.lltaskptr; }
7537 7538
    let vec[ValueRef] call_args = [];
    if (pass_task) { call_args += [lltaskptr]; }
7539
    auto arg_n = 3u;
7540
    for each (uint i in uint::range(0u, num_ty_param)) {
7541
        auto llarg = llvm::LLVMGetParam(fcx.llfn, arg_n);
7542
        fcx.lltydescs += [llarg];
7543 7544
        assert (llarg as int != 0);
        if (cast_to_i32) {
7545
            call_args += [vp2i(bcx, llarg)];
7546
        } else { call_args += [llarg]; }
7547
        arg_n += 1u;
7548
    }
7549 7550
    fn convert_arg_to_i32(&@block_ctxt cx, ValueRef v, ty::t t, ty::mode mode)
       -> ValueRef {
7551 7552
        if (mode == ty::mo_val) {
            if (ty::type_is_integral(cx.fcx.lcx.ccx.tcx, t)) {
7553
                auto lldsttype = T_int();
7554
                auto llsrctype = type_of(cx.fcx.lcx.ccx, cx.sp, t);
7555
                if (llvm::LLVMGetIntTypeWidth(lldsttype) >
7556
                        llvm::LLVMGetIntTypeWidth(llsrctype)) {
7557
                    ret cx.build.ZExtOrBitCast(v, T_int());
7558
                }
7559
                ret cx.build.TruncOrBitCast(v, T_int());
7560
            }
7561
            if (ty::type_is_fp(cx.fcx.lcx.ccx.tcx, t)) {
7562
                ret cx.build.FPToSI(v, T_int());
7563 7564
            }
        }
7565
        ret vp2i(cx, v);
7566
    }
7567
    fn trans_simple_native_abi(&@block_ctxt bcx, str name,
7568
                               &mutable vec[ValueRef] call_args,
7569 7570
                               ty::t fn_type, uint first_arg_n) ->
       tup(ValueRef, ValueRef) {
7571
        let vec[TypeRef] call_arg_tys = [];
7572
        for (ValueRef arg in call_args) { call_arg_tys += [val_ty(arg)]; }
7573 7574
        auto llnativefnty =
            T_fn(call_arg_tys,
7575
                 type_of(bcx.fcx.lcx.ccx, bcx.sp,
7576
                         ty::ty_fn_ret(bcx.fcx.lcx.ccx.tcx, fn_type)));
7577 7578 7579
        auto llnativefn =
            get_extern_fn(bcx.fcx.lcx.ccx.externs, bcx.fcx.lcx.ccx.llmod,
                          name, lib::llvm::LLVMCCallConv, llnativefnty);
7580 7581 7582 7583
        auto r = bcx.build.Call(llnativefn, call_args);
        auto rptr = bcx.fcx.llretptr;
        ret tup(r, rptr);
    }
7584
    auto args = ty::ty_fn_args(ccx.tcx, fn_type);
7585
    // Build up the list of arguments.
7586

7587
    let vec[tup(ValueRef, ty::t)] drop_args = [];
7588
    auto i = arg_n;
7589 7590
    for (ty::arg arg in args) {
        auto llarg = llvm::LLVMGetParam(fcx.llfn, i);
7591 7592 7593
        assert (llarg as int != 0);
        if (cast_to_i32) {
            auto llarg_i32 = convert_arg_to_i32(bcx, llarg, arg.ty, arg.mode);
7594
            call_args += [llarg_i32];
7595 7596
        } else { call_args += [llarg]; }
        if (arg.mode == ty::mo_val) { drop_args += [tup(llarg, arg.ty)]; }
7597 7598
        i += 1u;
    }
7599 7600 7601
    auto r;
    auto rptr;
    alt (abi) {
7602
        case (ast::native_abi_llvm) {
7603 7604 7605 7606
            auto result =
                trans_simple_native_abi(bcx, name, call_args, fn_type, arg_n);
            r = result._0;
            rptr = result._1;
7607
        }
7608
        case (ast::native_abi_rust_intrinsic) {
7609
            auto external_name = "rust_intrinsic_" + name;
7610 7611 7612 7613 7614
            auto result =
                trans_simple_native_abi(bcx, external_name, call_args,
                                        fn_type, arg_n);
            r = result._0;
            rptr = result._1;
7615
        }
7616
        case (_) {
7617 7618
            r =
                trans_native_call(bcx.build, ccx.glues, lltaskptr,
7619 7620 7621
                                  ccx.externs, ccx.tn, ccx.llmod, name,
                                  pass_task, call_args);
            rptr = bcx.build.BitCast(fcx.llretptr, T_ptr(T_i32()));
G
Graydon Hoare 已提交
7622
        }
7623
    }
7624 7625 7626 7627
    // 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.

7628
    if (!rty_is_nil) { bcx.build.Store(r, rptr); }
7629
    for (tup(ValueRef, ty::t) d in drop_args) {
7630 7631
        bcx = drop_ty(bcx, d._0, d._1).bcx;
    }
7632
    bcx.build.RetVoid();
7633
    finish_fn(fcx, lltop);
7634 7635
}

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

7638 7639
fn collect_native_item(@crate_ctxt ccx, &@ast::native_item i, &vec[str] pt,
                       &vt[vec[str]] v) {
7640
    alt (i.node) {
7641
        case (ast::native_item_fn(?name, _, _, _, ?fid, ?ann)) {
7642 7643
            ccx.native_items.insert(fid, i);
            if (!ccx.obj_methods.contains_key(fid)) {
7644
                decl_native_fn_and_pair(ccx, i.span, pt, name, ann, fid);
7645
            }
7646
        }
7647
        case (ast::native_item_ty(_, ?tid)) {
7648
            ccx.native_items.insert(tid, i);
7649 7650 7651
        }
    }
}
7652

7653 7654
fn collect_item_1(@crate_ctxt ccx, &@ast::item i, &vec[str] pt,
                  &vt[vec[str]] v) {
7655
    visit::visit_item(i, pt + item_path(i), v);
7656
    alt (i.node) {
7657 7658
        case (ast::item_const(_, _)) {
            auto typ = node_ann_type(ccx, i.ann);
7659 7660
            auto g =
                llvm::LLVMAddGlobal(ccx.llmod, type_of(ccx, i.span, typ),
7661
                                    str::buf(ccx.names.next(i.ident)));
7662 7663 7664
            llvm::LLVMSetLinkage(g,
                                 lib::llvm::LLVMInternalLinkage as
                                     llvm::Linkage);
7665 7666
            ccx.items.insert(i.id, i);
            ccx.consts.insert(i.id, g);
7667
        }
7668 7669 7670 7671
        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); }
7672
        case (_) { }
7673 7674 7675
    }
}

7676 7677
fn collect_item_2(&@crate_ctxt ccx, &@ast::item i, &vec[str] pt,
                  &vt[vec[str]] v) {
7678 7679
    auto new_pt = pt + item_path(i);
    visit::visit_item(i, new_pt, v);
7680
    alt (i.node) {
7681 7682 7683 7684
        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);
7685
            }
7686
        }
7687 7688 7689 7690
        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);
7691
            for (@ast::method m in ob.methods) {
7692
                ccx.obj_methods.insert(m.node.id, ());
7693
            }
7694
        }
7695
        case (_) { }
7696 7697 7698
    }
}

7699
fn collect_items(&@crate_ctxt ccx, @ast::crate crate) {
7700
    auto visitor0 = visit::default_visitor();
7701 7702 7703 7704 7705
    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);
7706 7707 7708 7709
    visit::visit_crate(*crate, [], visit::vtor(visitor1));
    visit::visit_crate(*crate, [], visit::vtor(visitor2));
}

7710 7711
fn collect_tag_ctor(@crate_ctxt ccx, &@ast::item i, &vec[str] pt,
                    &vt[vec[str]] v) {
7712 7713
    auto new_pt = pt + item_path(i);
    visit::visit_item(i, new_pt, v);
7714
    alt (i.node) {
7715
        case (ast::item_tag(?variants, ?tps)) {
7716
            for (ast::variant variant in variants) {
7717
                if (vec::len[ast::variant_arg](variant.node.args) != 0u) {
7718
                    decl_fn_and_pair(ccx, i.span,
7719 7720
                                     new_pt + [variant.node.name], "tag", tps,
                                     variant.node.ann, variant.node.id);
7721 7722 7723
                }
            }
        }
7724
        case (_) {/* fall through */ }
7725 7726 7727
    }
}

7728
fn collect_tag_ctors(&@crate_ctxt ccx, @ast::crate crate) {
7729 7730 7731
    auto visitor =
        @rec(visit_item=bind collect_tag_ctor(ccx, _, _, _)
             with *visit::default_visitor());
7732
    visit::visit_crate(*crate, [], visit::vtor(visitor));
7733 7734
}

7735

7736 7737 7738
// The constant translation pass.
fn trans_constant(@crate_ctxt ccx, &@ast::item it, &vec[str] pt,
                  &vt[vec[str]] v) {
7739 7740
    auto new_pt = pt + item_path(it);
    visit::visit_item(it, new_pt, v);
7741
    alt (it.node) {
7742
        case (ast::item_tag(?variants, _)) {
7743
            auto i = 0u;
7744
            auto n_variants = vec::len[ast::variant](variants);
7745 7746
            while (i < n_variants) {
                auto variant = variants.(i);
7747
                auto discrim_val = C_int(i as int);
7748
                auto p = new_pt + [it.ident, variant.node.name, "discrim"];
7749
                auto s = mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx));
7750 7751
                auto discrim_gvar =
                    llvm::LLVMAddGlobal(ccx.llmod, T_int(), str::buf(s));
7752 7753
                llvm::LLVMSetInitializer(discrim_gvar, discrim_val);
                llvm::LLVMSetGlobalConstant(discrim_gvar, True);
7754 7755
                ccx.discrims.insert(variant.node.id, discrim_gvar);
                ccx.discrim_symbols.insert(variant.node.id, s);
7756 7757 7758
                i += 1u;
            }
        }
7759
        case (ast::item_const(_, ?expr)) {
7760 7761
            // FIXME: The whole expr-translation system needs cloning to deal
            // with consts.
7762

7763
            auto v = C_int(1);
7764
            ccx.item_ids.insert(it.id, v);
7765
            auto s =
7766 7767 7768
                mangle_exported_name(ccx, new_pt + [it.ident],
                                     node_ann_type(ccx, it.ann));
            ccx.item_symbols.insert(it.id, s);
7769
        }
7770
        case (_) { }
7771 7772 7773
    }
}

7774
fn trans_constants(&@crate_ctxt ccx, @ast::crate crate) {
7775 7776 7777
    auto visitor =
        @rec(visit_item=bind trans_constant(ccx, _, _, _)
             with *visit::default_visitor());
7778
    visit::visit_crate(*crate, [], visit::vtor(visitor));
7779 7780
}

G
Graydon Hoare 已提交
7781
fn vp2i(&@block_ctxt cx, ValueRef v) -> ValueRef {
7782 7783 7784
    ret cx.build.PtrToInt(v, T_int());
}

G
Graydon Hoare 已提交
7785
fn vi2p(&@block_ctxt cx, ValueRef v, TypeRef t) -> ValueRef {
7786 7787 7788
    ret cx.build.IntToPtr(v, t);
}

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

7791
fn i2p(ValueRef v, TypeRef t) -> ValueRef {
7792
    ret llvm::LLVMConstIntToPtr(v, t);
7793 7794
}

G
Graydon Hoare 已提交
7795
fn create_typedefs(&@crate_ctxt cx) {
7796 7797
    llvm::LLVMAddTypeName(cx.llmod, str::buf("task"), T_task(cx.tn));
    llvm::LLVMAddTypeName(cx.llmod, str::buf("tydesc"), T_tydesc(cx.tn));
7798 7799
}

7800 7801 7802 7803 7804 7805 7806 7807 7808
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()];
7809
    let vec[TypeRef] T_trap_args = [];
7810 7811 7812 7813 7814 7815 7816 7817 7818 7819 7820 7821 7822 7823
    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()));
7824
    auto intrinsics = new_str_hash[ValueRef]();
7825 7826
    intrinsics.insert("llvm.memmove.p0i8.p0i8.i32", memmove32);
    intrinsics.insert("llvm.memmove.p0i8.p0i8.i64", memmove64);
7827 7828
    intrinsics.insert("llvm.memset.p0i8.i32", memset32);
    intrinsics.insert("llvm.memset.p0i8.i64", memset64);
7829 7830
    intrinsics.insert("llvm.trap", trap);
    ret intrinsics;
7831 7832
}

G
Graydon Hoare 已提交
7833
fn trace_str(&@block_ctxt cx, str s) {
7834
    cx.build.Call(cx.fcx.lcx.ccx.upcalls.trace_str,
7835
                  [cx.fcx.lltaskptr, C_cstr(cx.fcx.lcx.ccx, s)]);
7836 7837
}

G
Graydon Hoare 已提交
7838
fn trace_word(&@block_ctxt cx, ValueRef v) {
7839
    cx.build.Call(cx.fcx.lcx.ccx.upcalls.trace_word, [cx.fcx.lltaskptr, v]);
7840 7841
}

G
Graydon Hoare 已提交
7842
fn trace_ptr(&@block_ctxt cx, ValueRef v) {
7843 7844 7845
    trace_word(cx, cx.build.PtrToInt(v, T_int()));
}

G
Graydon Hoare 已提交
7846
fn trap(&@block_ctxt bcx) {
7847
    let vec[ValueRef] v = [];
7848
    bcx.build.Call(bcx.fcx.lcx.ccx.intrinsics.get("llvm.trap"), v);
7849
}
7850

7851
fn decl_no_op_type_glue(ModuleRef llmod, type_names tn) -> ValueRef {
7852
    auto ty = T_fn([T_taskptr(tn), T_ptr(T_i8())], T_void());
7853
    ret decl_fastcall_fn(llmod, abi::no_op_type_glue_name(), ty);
7854 7855 7856
}

fn make_no_op_type_glue(ValueRef fun) {
7857
    auto bb_name = str::buf("_rust_no_op_type_glue_bb");
7858
    auto llbb = llvm::LLVMAppendBasicBlock(fun, bb_name);
7859
    new_builder(llbb).RetVoid();
7860 7861
}

G
Graydon Hoare 已提交
7862
fn vec_fill(&@block_ctxt bcx, ValueRef v) -> ValueRef {
7863 7864
    ret bcx.build.Load(bcx.build.GEP(v,
                                     [C_int(0), C_int(abi::vec_elt_fill)]));
7865 7866
}

G
Graydon Hoare 已提交
7867
fn vec_p0(&@block_ctxt bcx, ValueRef v) -> ValueRef {
7868
    auto p = bcx.build.GEP(v, [C_int(0), C_int(abi::vec_elt_data)]);
7869 7870 7871
    ret bcx.build.PointerCast(p, T_ptr(T_i8()));
}

G
Graydon Hoare 已提交
7872
fn make_glues(ModuleRef llmod, &type_names tn) -> @glue_fns {
7873
    ret @rec(no_op_type_glue=decl_no_op_type_glue(llmod, tn));
7874 7875
}

7876
fn make_common_glue(&session::session sess, &str output) {
7877
    // FIXME: part of this is repetitive and is probably a good idea
7878
    // to autogen it.
7879

7880
    auto llmod =
7881
        llvm::LLVMModuleCreateWithNameInContext(str::buf("rust_out"),
7882
                                                llvm::LLVMGetGlobalContext());
7883 7884
    llvm::LLVMSetDataLayout(llmod, str::buf(x86::get_data_layout()));
    llvm::LLVMSetTarget(llmod, str::buf(x86::get_target_triple()));
7885
    auto td = mk_target_data(x86::get_data_layout());
7886
    auto tn = mk_type_names();
7887
    auto intrinsics = declare_intrinsics(llmod);
7888
    llvm::LLVMSetModuleInlineAsm(llmod, str::buf(x86::get_module_asm()));
7889
    auto glues = make_glues(llmod, tn);
7890
    link::write::run_passes(sess, llmod, output);
7891 7892
}

G
Graydon Hoare 已提交
7893
fn create_module_map(&@crate_ctxt ccx) -> ValueRef {
7894
    auto elttype = T_struct([T_int(), T_int()]);
7895
    auto maptype = T_array(elttype, ccx.module_data.size() + 1u);
7896 7897
    auto map =
        llvm::LLVMAddGlobal(ccx.llmod, maptype, str::buf("_rust_mod_map"));
7898
    let vec[ValueRef] elts = [];
7899
    for each (@tup(str, ValueRef) item in ccx.module_data.items()) {
7900
        auto elt = C_struct([p2i(C_cstr(ccx, item._0)), p2i(item._1)]);
7901
        vec::push[ValueRef](elts, elt);
7902
    }
7903
    auto term = C_struct([C_int(0), C_int(0)]);
7904
    vec::push[ValueRef](elts, term);
7905
    llvm::LLVMSetInitializer(map, C_array(elttype, elts));
7906 7907 7908
    ret map;
}

7909

7910
// FIXME use hashed metadata instead of crate names once we have that
G
Graydon Hoare 已提交
7911
fn create_crate_map(&@crate_ctxt ccx) -> ValueRef {
7912
    let vec[ValueRef] subcrates = [];
7913 7914 7915
    auto i = 1;
    while (ccx.sess.has_external_crate(i)) {
        auto name = ccx.sess.get_external_crate(i).name;
7916 7917 7918
        auto cr =
            llvm::LLVMAddGlobal(ccx.llmod, T_int(),
                                str::buf("_rust_crate_map_" + name));
7919
        vec::push[ValueRef](subcrates, p2i(cr));
7920 7921
        i += 1;
    }
7922
    vec::push[ValueRef](subcrates, C_int(0));
7923 7924
    auto mapname;
    if (ccx.sess.get_opts().shared) {
7925
        mapname = ccx.crate_meta_name;
7926
    } else { mapname = "toplevel"; }
7927
    auto sym_name = "_rust_crate_map_" + mapname;
7928
    auto arrtype = T_array(T_int(), vec::len[ValueRef](subcrates));
7929
    auto maptype = T_struct([T_int(), arrtype]);
7930
    auto map = llvm::LLVMAddGlobal(ccx.llmod, maptype, str::buf(sym_name));
7931 7932 7933 7934 7935
    llvm::LLVMSetLinkage(map,
                         lib::llvm::LLVMExternalLinkage as llvm::Linkage);
    llvm::LLVMSetInitializer(map,
                             C_struct([p2i(create_module_map(ccx)),
                                       C_array(T_int(), subcrates)]));
7936 7937 7938
    ret map;
}

7939 7940
fn trans_crate(&session::session sess, &@ast::crate crate, &ty::ctxt tcx,
               &str output) -> ModuleRef {
7941
    auto llmod =
7942
        llvm::LLVMModuleCreateWithNameInContext(str::buf("rust_out"),
7943
                                                llvm::LLVMGetGlobalContext());
7944 7945
    llvm::LLVMSetDataLayout(llmod, str::buf(x86::get_data_layout()));
    llvm::LLVMSetTarget(llmod, str::buf(x86::get_target_triple()));
7946
    auto td = mk_target_data(x86::get_data_layout());
7947
    auto tn = mk_type_names();
7948
    auto intrinsics = declare_intrinsics(llmod);
7949
    auto glues = make_glues(llmod, tn);
7950 7951
    auto hasher = ty::hash_ty;
    auto eqer = ty::eq_ty;
7952 7953 7954 7955 7956 7957
    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);
7958
    auto sha = std::sha1::mk_sha1();
7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 7993 7994 7995
    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));
7996
    auto cx = new_local_ctxt(ccx);
7997
    create_typedefs(ccx);
7998
    collect_items(ccx, crate);
7999 8000
    collect_tag_ctors(ccx, crate);
    trans_constants(ccx, crate);
8001
    trans_mod(cx, crate.node.module);
8002
    auto crate_map = create_crate_map(ccx);
8003
    emit_tydescs(ccx);
8004
    // Translate the metadata:
8005

8006
    middle::metadata::write_metadata(cx.ccx, crate);
8007 8008 8009 8010 8011 8012 8013 8014
    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);
    }
8015
    ret llmod;
8016 8017 8018 8019 8020 8021 8022 8023
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
8024
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
8025 8026
// End:
//