2011-02-24 19:24:12 -08:00
|
|
|
import std._int;
|
2010-09-22 15:21:06 -07:00
|
|
|
import std._str;
|
2010-12-02 19:30:06 -08:00
|
|
|
import std._uint;
|
2010-09-22 17:05:38 -07:00
|
|
|
import std._vec;
|
|
|
|
import std._str.rustrt.sbuf;
|
|
|
|
import std._vec.rustrt.vbuf;
|
2010-12-10 15:02:23 -08:00
|
|
|
import std.map;
|
2010-09-23 18:38:37 -07:00
|
|
|
import std.map.hashmap;
|
2010-11-03 17:10:37 -07:00
|
|
|
import std.option;
|
|
|
|
import std.option.some;
|
|
|
|
import std.option.none;
|
2010-09-22 15:21:06 -07:00
|
|
|
|
2010-09-23 15:46:31 -07:00
|
|
|
import front.ast;
|
2011-03-29 13:21:16 -07:00
|
|
|
import front.creader;
|
2011-04-05 14:18:44 -07:00
|
|
|
import pretty.pprust;
|
2010-09-22 15:21:06 -07:00
|
|
|
import driver.session;
|
2010-12-21 12:13:51 -08:00
|
|
|
import middle.ty;
|
2010-09-23 15:46:31 -07:00
|
|
|
import back.x86;
|
2010-09-23 17:16:34 -07:00
|
|
|
import back.abi;
|
|
|
|
|
2011-04-01 17:20:22 -07:00
|
|
|
import pretty.pprust;
|
|
|
|
|
2010-12-21 12:13:51 -08:00
|
|
|
import middle.ty.pat_ty;
|
2010-12-15 09:38:23 -08:00
|
|
|
|
2010-10-19 14:54:10 -07:00
|
|
|
import util.common;
|
2010-09-23 17:16:34 -07:00
|
|
|
import util.common.istr;
|
2010-10-19 14:54:10 -07:00
|
|
|
import util.common.new_def_hash;
|
2010-09-23 18:38:37 -07:00
|
|
|
import util.common.new_str_hash;
|
2010-09-22 15:21:06 -07:00
|
|
|
|
|
|
|
import lib.llvm.llvm;
|
|
|
|
import lib.llvm.builder;
|
2010-12-03 16:55:59 -08:00
|
|
|
import lib.llvm.target_data;
|
2010-12-01 19:03:47 -08:00
|
|
|
import lib.llvm.type_handle;
|
2011-02-17 18:16:51 -08:00
|
|
|
import lib.llvm.type_names;
|
2010-12-06 17:17:49 -08:00
|
|
|
import lib.llvm.mk_pass_manager;
|
2010-12-03 16:55:59 -08:00
|
|
|
import lib.llvm.mk_target_data;
|
2010-12-06 17:17:49 -08:00
|
|
|
import lib.llvm.mk_type_handle;
|
2011-02-17 18:16:51 -08:00
|
|
|
import lib.llvm.mk_type_names;
|
2010-09-22 17:05:38 -07:00
|
|
|
import lib.llvm.llvm.ModuleRef;
|
|
|
|
import lib.llvm.llvm.ValueRef;
|
|
|
|
import lib.llvm.llvm.TypeRef;
|
2010-12-01 19:03:47 -08:00
|
|
|
import lib.llvm.llvm.TypeHandleRef;
|
2010-09-22 17:05:38 -07:00
|
|
|
import lib.llvm.llvm.BuilderRef;
|
|
|
|
import lib.llvm.llvm.BasicBlockRef;
|
2010-09-22 15:21:06 -07:00
|
|
|
|
2010-09-22 17:05:38 -07:00
|
|
|
import lib.llvm.False;
|
|
|
|
import lib.llvm.True;
|
2010-09-22 15:21:06 -07:00
|
|
|
|
2010-09-28 12:23:40 -07:00
|
|
|
state obj namegen(mutable int i) {
|
|
|
|
fn next(str prefix) -> str {
|
|
|
|
i += 1;
|
|
|
|
ret prefix + istr(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-23 17:16:34 -07:00
|
|
|
type glue_fns = rec(ValueRef activate_glue,
|
|
|
|
ValueRef yield_glue,
|
2010-09-27 15:38:34 -07:00
|
|
|
ValueRef exit_task_glue,
|
2011-03-25 15:48:00 -07:00
|
|
|
vec[ValueRef] native_glues_rust,
|
|
|
|
vec[ValueRef] native_glues_cdecl,
|
2011-01-17 17:24:33 -08:00
|
|
|
ValueRef no_op_type_glue,
|
2011-01-18 15:38:35 -08:00
|
|
|
ValueRef memcpy_glue,
|
2011-03-02 16:42:09 -08:00
|
|
|
ValueRef bzero_glue,
|
2011-03-03 18:18:51 -08:00
|
|
|
ValueRef vec_append_glue);
|
2010-09-23 17:16:34 -07:00
|
|
|
|
2011-03-04 17:22:43 -08:00
|
|
|
type tydesc_info = rec(ValueRef tydesc,
|
|
|
|
ValueRef take_glue,
|
2011-04-18 10:56:52 -07:00
|
|
|
ValueRef drop_glue,
|
|
|
|
ValueRef cmp_glue);
|
2011-03-04 17:22:43 -08:00
|
|
|
|
2011-03-25 15:48:00 -07:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* A "native" is a combination of an extern that references C code, plus a
|
|
|
|
* glue-code stub that "looks like" a rust function, emitted here, plus a
|
|
|
|
* generic N-ary bit of asm glue (found over in back/x86.rs) that performs a
|
|
|
|
* control transfer into C from rust. Natives may be normal C library code.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2010-11-21 12:06:09 -08:00
|
|
|
state type crate_ctxt = rec(session.session sess,
|
2010-09-28 12:23:40 -07:00
|
|
|
ModuleRef llmod,
|
2010-12-03 16:55:59 -08:00
|
|
|
target_data td,
|
2011-02-17 18:16:51 -08:00
|
|
|
type_names tn,
|
2011-01-31 15:03:05 -08:00
|
|
|
ValueRef crate_ptr,
|
2011-03-25 15:48:00 -07:00
|
|
|
hashmap[str, ValueRef] externs,
|
2010-11-25 17:45:26 -08:00
|
|
|
hashmap[str, ValueRef] intrinsics,
|
2010-12-02 17:30:07 -08:00
|
|
|
hashmap[ast.def_id, ValueRef] item_ids,
|
2010-10-22 19:31:33 -07:00
|
|
|
hashmap[ast.def_id, @ast.item] items,
|
2011-02-16 11:33:14 -08:00
|
|
|
hashmap[ast.def_id,
|
|
|
|
@ast.native_item] native_items,
|
2011-03-30 17:23:25 -07:00
|
|
|
ty.type_cache type_cache,
|
2011-03-23 15:43:18 -07:00
|
|
|
hashmap[ast.def_id, str] item_symbols,
|
2011-03-04 15:08:33 -08:00
|
|
|
// TODO: hashmap[tup(tag_id,subtys), @tag_info]
|
2011-04-22 12:27:28 -07:00
|
|
|
hashmap[ty.t, uint] tag_sizes,
|
2011-03-03 17:57:36 -08:00
|
|
|
hashmap[ast.def_id, ValueRef] discrims,
|
2011-03-23 15:43:18 -07:00
|
|
|
hashmap[ast.def_id, str] discrim_symbols,
|
2011-01-05 15:31:35 -08:00
|
|
|
hashmap[ast.def_id, ValueRef] fn_pairs,
|
2011-01-21 12:09:25 -08:00
|
|
|
hashmap[ast.def_id, ValueRef] consts,
|
2011-01-05 15:31:35 -08:00
|
|
|
hashmap[ast.def_id,()] obj_methods,
|
2011-04-22 12:27:28 -07:00
|
|
|
hashmap[ty.t, @tydesc_info] tydescs,
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
hashmap[str, ValueRef] module_data,
|
2011-04-22 12:27:28 -07:00
|
|
|
hashmap[ty.t, TypeRef] lltypes,
|
2010-09-28 12:23:40 -07:00
|
|
|
@glue_fns glues,
|
|
|
|
namegen names,
|
2011-04-20 18:52:04 -07:00
|
|
|
std.sha1.sha1 sha,
|
|
|
|
@ty.type_store tystore);
|
2010-09-23 13:15:51 -07:00
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
type local_ctxt = rec(vec[str] path,
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
vec[str] module_path,
|
2011-04-17 14:24:45 +02:00
|
|
|
vec[ast.ty_param] obj_typarams,
|
|
|
|
vec[ast.obj_field] obj_fields,
|
|
|
|
@crate_ctxt ccx);
|
|
|
|
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
type self_vt = rec(ValueRef v, ty.t t);
|
2011-04-05 14:18:44 -07:00
|
|
|
|
2010-09-28 12:23:40 -07:00
|
|
|
state type fn_ctxt = rec(ValueRef llfn,
|
|
|
|
ValueRef lltaskptr,
|
2011-02-08 11:47:53 -08:00
|
|
|
ValueRef llenv,
|
|
|
|
ValueRef llretptr,
|
2011-03-28 18:04:52 -07:00
|
|
|
mutable BasicBlockRef llallocas,
|
2011-04-05 14:18:44 -07:00
|
|
|
mutable option.t[self_vt] llself,
|
2011-02-17 12:20:55 -08:00
|
|
|
mutable option.t[ValueRef] lliterbody,
|
2010-10-21 18:13:57 -07:00
|
|
|
hashmap[ast.def_id, ValueRef] llargs,
|
2010-12-30 17:01:20 -08:00
|
|
|
hashmap[ast.def_id, ValueRef] llobjfields,
|
2010-10-19 14:54:10 -07:00
|
|
|
hashmap[ast.def_id, ValueRef] lllocals,
|
2011-03-10 16:49:00 -08:00
|
|
|
hashmap[ast.def_id, ValueRef] llupvars,
|
2011-04-15 17:45:37 -07:00
|
|
|
mutable vec[ValueRef] lltydescs,
|
2011-04-17 14:24:45 +02:00
|
|
|
@local_ctxt lcx);
|
2010-09-24 14:56:04 -07:00
|
|
|
|
2010-09-29 17:22:07 -07:00
|
|
|
tag cleanup {
|
2010-10-04 15:55:12 -07:00
|
|
|
clean(fn(@block_ctxt cx) -> result);
|
2010-09-29 17:22:07 -07:00
|
|
|
}
|
|
|
|
|
2011-01-24 15:26:10 -08:00
|
|
|
|
|
|
|
tag block_kind {
|
|
|
|
SCOPE_BLOCK;
|
2011-03-25 16:28:16 +01:00
|
|
|
LOOP_SCOPE_BLOCK(option.t[@block_ctxt], @block_ctxt);
|
2011-01-24 15:26:10 -08:00
|
|
|
NON_SCOPE_BLOCK;
|
|
|
|
}
|
|
|
|
|
2010-09-29 17:22:07 -07:00
|
|
|
state type block_ctxt = rec(BasicBlockRef llbb,
|
|
|
|
builder build,
|
2010-11-10 17:46:49 -08:00
|
|
|
block_parent parent,
|
2011-01-24 15:26:10 -08:00
|
|
|
block_kind kind,
|
2010-09-29 17:22:07 -07:00
|
|
|
mutable vec[cleanup] cleanups,
|
|
|
|
@fn_ctxt fcx);
|
|
|
|
|
2010-11-10 17:46:49 -08:00
|
|
|
// FIXME: we should be able to use option.t[@block_parent] here but
|
|
|
|
// the infinite-tag check in rustboot gets upset.
|
|
|
|
|
|
|
|
tag block_parent {
|
|
|
|
parent_none;
|
|
|
|
parent_some(@block_ctxt);
|
|
|
|
}
|
|
|
|
|
2010-09-29 17:22:07 -07:00
|
|
|
|
2010-10-04 15:55:12 -07:00
|
|
|
state type result = rec(mutable @block_ctxt bcx,
|
|
|
|
mutable ValueRef val);
|
|
|
|
|
2011-02-10 14:59:20 -08:00
|
|
|
fn sep() -> str {
|
|
|
|
ret "_";
|
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
fn extend_path(@local_ctxt cx, str name) -> @local_ctxt {
|
2011-04-01 16:04:22 -07:00
|
|
|
ret @rec(path = cx.path + vec(name) with *cx);
|
2011-03-26 17:36:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn path_name(vec[str] path) -> str {
|
|
|
|
ret _str.connect(path, sep());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn mangle_name_by_type(@crate_ctxt ccx, vec[str] path, ty.t t) -> str {
|
2011-04-20 17:23:45 +02:00
|
|
|
ccx.sha.reset();
|
2011-04-22 14:48:25 -07:00
|
|
|
|
2011-03-26 17:36:47 -07:00
|
|
|
auto f = metadata.def_to_str;
|
2011-04-22 17:00:46 -07:00
|
|
|
auto cx = @rec(ds=f, tystore=ccx.tystore);
|
2011-04-22 14:48:25 -07:00
|
|
|
ccx.sha.input_str(metadata.Encode.ty_str(cx, t));
|
|
|
|
|
2011-03-26 17:36:47 -07:00
|
|
|
ret sep() + "rust" + sep()
|
2011-04-20 17:23:45 +02:00
|
|
|
+ _str.substr(ccx.sha.result_str(), 0u, 16u) + sep()
|
|
|
|
+ path_name(path);
|
2011-03-26 17:36:47 -07:00
|
|
|
}
|
|
|
|
|
2011-04-20 17:23:45 +02:00
|
|
|
fn mangle_name_by_seq(@crate_ctxt ccx, vec[str] path, str flav) -> str {
|
2011-03-26 17:36:47 -07:00
|
|
|
ret sep() + "rust" + sep()
|
2011-04-20 17:23:45 +02:00
|
|
|
+ ccx.names.next(flav) + sep()
|
|
|
|
+ path_name(path);
|
2011-03-26 17:36:47 -07:00
|
|
|
}
|
|
|
|
|
2010-10-04 15:55:12 -07:00
|
|
|
fn res(@block_ctxt bcx, ValueRef val) -> result {
|
|
|
|
ret rec(mutable bcx = bcx,
|
|
|
|
mutable val = val);
|
|
|
|
}
|
|
|
|
|
2011-02-17 18:16:51 -08:00
|
|
|
fn ty_str(type_names tn, TypeRef t) -> str {
|
|
|
|
ret lib.llvm.type_to_str(tn, t);
|
2010-09-29 17:22:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn val_ty(ValueRef v) -> TypeRef {
|
|
|
|
ret llvm.LLVMTypeOf(v);
|
|
|
|
}
|
|
|
|
|
2011-02-17 18:16:51 -08:00
|
|
|
fn val_str(type_names tn, ValueRef v) -> str {
|
|
|
|
ret ty_str(tn, val_ty(v));
|
2010-09-29 17:22:07 -07:00
|
|
|
}
|
2010-09-24 14:56:04 -07:00
|
|
|
|
|
|
|
|
|
|
|
// LLVM type constructors.
|
|
|
|
|
2010-10-04 15:55:12 -07:00
|
|
|
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.
|
2010-09-22 17:05:38 -07:00
|
|
|
ret llvm.LLVMVoidType();
|
|
|
|
}
|
|
|
|
|
2010-10-04 15:55:12 -07:00
|
|
|
fn T_nil() -> TypeRef {
|
|
|
|
// NB: See above in T_void().
|
|
|
|
ret llvm.LLVMInt1Type();
|
|
|
|
}
|
|
|
|
|
2010-09-28 16:17:28 -07:00
|
|
|
fn T_i1() -> TypeRef {
|
|
|
|
ret llvm.LLVMInt1Type();
|
|
|
|
}
|
|
|
|
|
2010-09-28 12:23:40 -07:00
|
|
|
fn T_i8() -> TypeRef {
|
|
|
|
ret llvm.LLVMInt8Type();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn T_i16() -> TypeRef {
|
|
|
|
ret llvm.LLVMInt16Type();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn T_i32() -> TypeRef {
|
2010-09-22 17:05:38 -07:00
|
|
|
ret llvm.LLVMInt32Type();
|
|
|
|
}
|
|
|
|
|
2010-09-28 12:23:40 -07:00
|
|
|
fn T_i64() -> TypeRef {
|
|
|
|
ret llvm.LLVMInt64Type();
|
|
|
|
}
|
|
|
|
|
2010-10-19 14:54:10 -07:00
|
|
|
fn T_f32() -> TypeRef {
|
|
|
|
ret llvm.LLVMFloatType();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn T_f64() -> TypeRef {
|
|
|
|
ret llvm.LLVMDoubleType();
|
|
|
|
}
|
|
|
|
|
2010-10-19 17:24:15 -07:00
|
|
|
fn T_bool() -> TypeRef {
|
|
|
|
ret T_i1();
|
|
|
|
}
|
|
|
|
|
2010-09-28 12:23:40 -07:00
|
|
|
fn T_int() -> TypeRef {
|
|
|
|
// FIXME: switch on target type.
|
|
|
|
ret T_i32();
|
|
|
|
}
|
|
|
|
|
2011-03-21 17:12:05 -07:00
|
|
|
fn T_float() -> TypeRef {
|
|
|
|
// FIXME: switch on target type.
|
|
|
|
ret T_f64();
|
|
|
|
}
|
|
|
|
|
2010-10-19 14:54:10 -07:00
|
|
|
fn T_char() -> TypeRef {
|
|
|
|
ret T_i32();
|
|
|
|
}
|
|
|
|
|
2010-09-22 17:05:38 -07:00
|
|
|
fn T_fn(vec[TypeRef] inputs, TypeRef output) -> TypeRef {
|
|
|
|
ret llvm.LLVMFunctionType(output,
|
|
|
|
_vec.buf[TypeRef](inputs),
|
|
|
|
_vec.len[TypeRef](inputs),
|
2010-09-23 17:16:34 -07:00
|
|
|
False);
|
|
|
|
}
|
|
|
|
|
2011-02-17 18:16:51 -08:00
|
|
|
fn T_fn_pair(type_names tn, TypeRef tfn) -> TypeRef {
|
2011-01-04 15:29:38 -08:00
|
|
|
ret T_struct(vec(T_ptr(tfn),
|
2011-02-17 18:16:51 -08:00
|
|
|
T_opaque_closure_ptr(tn)));
|
2011-01-03 22:39:43 -08:00
|
|
|
}
|
|
|
|
|
2010-09-23 17:16:34 -07:00
|
|
|
fn T_ptr(TypeRef t) -> TypeRef {
|
|
|
|
ret llvm.LLVMPointerType(t, 0u);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn T_struct(vec[TypeRef] elts) -> TypeRef {
|
|
|
|
ret llvm.LLVMStructType(_vec.buf[TypeRef](elts),
|
|
|
|
_vec.len[TypeRef](elts),
|
|
|
|
False);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn T_opaque() -> TypeRef {
|
|
|
|
ret llvm.LLVMOpaqueType();
|
|
|
|
}
|
|
|
|
|
2011-02-17 18:16:51 -08:00
|
|
|
fn T_task(type_names tn) -> TypeRef {
|
|
|
|
auto s = "task";
|
|
|
|
if (tn.name_has_type(s)) {
|
|
|
|
ret tn.get_type(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto t = T_struct(vec(T_int(), // Refcount
|
|
|
|
T_int(), // Delegate pointer
|
|
|
|
T_int(), // Stack segment pointer
|
|
|
|
T_int(), // Runtime SP
|
|
|
|
T_int(), // Rust SP
|
|
|
|
T_int(), // GC chain
|
|
|
|
T_int(), // Domain pointer
|
|
|
|
T_int() // Crate cache pointer
|
|
|
|
));
|
|
|
|
tn.associate(s, t);
|
|
|
|
ret t;
|
2010-09-24 15:22:48 -07:00
|
|
|
}
|
|
|
|
|
2011-04-18 10:56:52 -07:00
|
|
|
fn T_tydesc_field(type_names tn, int field) -> TypeRef {
|
|
|
|
// Bit of a kludge: pick the fn typeref out of the tydesc..
|
|
|
|
let vec[TypeRef] tydesc_elts =
|
|
|
|
_vec.init_elt[TypeRef](T_nil(), abi.n_tydesc_fields as uint);
|
|
|
|
llvm.LLVMGetStructElementTypes(T_tydesc(tn),
|
|
|
|
_vec.buf[TypeRef](tydesc_elts));
|
|
|
|
auto t = llvm.LLVMGetElementType(tydesc_elts.(field));
|
|
|
|
ret t;
|
|
|
|
}
|
|
|
|
|
2011-02-17 18:16:51 -08:00
|
|
|
fn T_glue_fn(type_names tn) -> TypeRef {
|
|
|
|
auto s = "glue_fn";
|
|
|
|
if (tn.name_has_type(s)) {
|
|
|
|
ret tn.get_type(s);
|
|
|
|
}
|
|
|
|
|
2011-04-18 10:56:52 -07:00
|
|
|
auto t = T_tydesc_field(tn, abi.tydesc_field_drop_glue);
|
|
|
|
tn.associate(s, t);
|
|
|
|
ret t;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn T_cmp_glue_fn(type_names tn) -> TypeRef {
|
|
|
|
auto s = "cmp_glue_fn";
|
|
|
|
if (tn.name_has_type(s)) {
|
|
|
|
ret tn.get_type(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto t = T_tydesc_field(tn, abi.tydesc_field_cmp_glue);
|
2011-02-17 18:16:51 -08:00
|
|
|
tn.associate(s, t);
|
|
|
|
ret t;
|
2011-02-08 11:47:53 -08:00
|
|
|
}
|
|
|
|
|
2011-02-17 18:16:51 -08:00
|
|
|
fn T_tydesc(type_names tn) -> TypeRef {
|
|
|
|
|
|
|
|
auto s = "tydesc";
|
|
|
|
if (tn.name_has_type(s)) {
|
|
|
|
ret tn.get_type(s);
|
|
|
|
}
|
2011-01-28 14:34:25 -08:00
|
|
|
|
|
|
|
auto th = mk_type_handle();
|
|
|
|
auto abs_tydesc = llvm.LLVMResolveTypeHandle(th.llth);
|
2011-01-28 15:45:13 -08:00
|
|
|
auto tydescpp = T_ptr(T_ptr(abs_tydesc));
|
2010-12-16 16:34:20 -08:00
|
|
|
auto pvoid = T_ptr(T_i8());
|
2011-02-08 11:47:53 -08:00
|
|
|
auto glue_fn_ty = T_ptr(T_fn(vec(T_ptr(T_nil()),
|
2011-02-17 18:16:51 -08:00
|
|
|
T_taskptr(tn),
|
2011-02-08 11:47:53 -08:00
|
|
|
T_ptr(T_nil()),
|
2011-01-28 15:45:13 -08:00
|
|
|
tydescpp,
|
2011-01-28 14:34:25 -08:00
|
|
|
pvoid), T_void()));
|
2011-04-19 15:22:57 -07:00
|
|
|
auto cmp_glue_fn_ty = T_ptr(T_fn(vec(T_ptr(T_i1()),
|
2011-04-18 10:56:52 -07:00
|
|
|
T_taskptr(tn),
|
|
|
|
T_ptr(T_nil()),
|
|
|
|
tydescpp,
|
|
|
|
pvoid,
|
2011-04-18 12:44:50 -07:00
|
|
|
pvoid,
|
|
|
|
T_i8()), T_void()));
|
2011-01-28 15:45:13 -08:00
|
|
|
auto tydesc = T_struct(vec(tydescpp, // first_param
|
2011-01-28 14:34:25 -08:00
|
|
|
T_int(), // size
|
|
|
|
T_int(), // align
|
2011-04-09 00:54:46 +00:00
|
|
|
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
|
2011-04-18 10:56:52 -07:00
|
|
|
glue_fn_ty, // is_stateful
|
|
|
|
cmp_glue_fn_ty)); // cmp_glue
|
2011-01-28 14:34:25 -08:00
|
|
|
|
|
|
|
llvm.LLVMRefineType(abs_tydesc, tydesc);
|
2011-02-17 18:16:51 -08:00
|
|
|
auto t = llvm.LLVMResolveTypeHandle(th.llth);
|
|
|
|
tn.associate(s, t);
|
|
|
|
ret t;
|
2010-12-16 16:34:20 -08:00
|
|
|
}
|
|
|
|
|
2010-10-01 18:25:42 -07:00
|
|
|
fn T_array(TypeRef t, uint n) -> TypeRef {
|
|
|
|
ret llvm.LLVMArrayType(t, n);
|
|
|
|
}
|
|
|
|
|
2010-11-22 14:28:05 -08:00
|
|
|
fn T_vec(TypeRef t) -> TypeRef {
|
|
|
|
ret T_struct(vec(T_int(), // Refcount
|
|
|
|
T_int(), // Alloc
|
|
|
|
T_int(), // Fill
|
2011-04-02 19:03:43 -07:00
|
|
|
T_int(), // Pad
|
2010-11-22 14:28:05 -08:00
|
|
|
T_array(t, 0u) // Body elements
|
2010-09-29 17:22:07 -07:00
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2011-03-06 12:46:33 -08:00
|
|
|
fn T_opaque_vec_ptr() -> TypeRef {
|
|
|
|
ret T_ptr(T_vec(T_int()));
|
|
|
|
}
|
|
|
|
|
2010-11-22 14:28:05 -08:00
|
|
|
fn T_str() -> TypeRef {
|
|
|
|
ret T_vec(T_i8());
|
2010-10-01 18:25:42 -07:00
|
|
|
}
|
|
|
|
|
2010-10-19 14:54:10 -07:00
|
|
|
fn T_box(TypeRef t) -> TypeRef {
|
|
|
|
ret T_struct(vec(T_int(), t));
|
|
|
|
}
|
|
|
|
|
2011-03-16 21:49:15 -04:00
|
|
|
fn T_port(TypeRef t) -> TypeRef {
|
|
|
|
ret T_struct(vec(T_int())); // Refcount
|
|
|
|
}
|
|
|
|
|
|
|
|
fn T_chan(TypeRef t) -> TypeRef {
|
|
|
|
ret T_struct(vec(T_int())); // Refcount
|
|
|
|
}
|
|
|
|
|
2011-02-17 18:16:51 -08:00
|
|
|
fn T_crate(type_names tn) -> TypeRef {
|
|
|
|
auto s = "crate";
|
|
|
|
if (tn.name_has_type(s)) {
|
|
|
|
ret tn.get_type(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto t = T_struct(vec(T_int(), // ptrdiff_t image_base_off
|
|
|
|
T_int(), // uintptr_t self_addr
|
|
|
|
T_int(), // ptrdiff_t debug_abbrev_off
|
|
|
|
T_int(), // size_t debug_abbrev_sz
|
|
|
|
T_int(), // ptrdiff_t debug_info_off
|
|
|
|
T_int(), // size_t debug_info_sz
|
2011-04-09 00:54:46 +00:00
|
|
|
T_int(), // size_t activate_glue
|
|
|
|
T_int(), // size_t yield_glue
|
|
|
|
T_int(), // size_t unwind_glue
|
|
|
|
T_int(), // size_t gc_glue
|
|
|
|
T_int(), // size_t main_exit_task_glue
|
2011-02-17 18:16:51 -08:00
|
|
|
T_int(), // int n_rust_syms
|
|
|
|
T_int(), // int n_c_syms
|
2011-02-22 16:37:01 -08:00
|
|
|
T_int(), // int n_libs
|
2011-04-18 16:18:55 +02:00
|
|
|
T_int() // uintptr_t abi_tag
|
2011-02-17 18:16:51 -08:00
|
|
|
));
|
|
|
|
tn.associate(s, t);
|
|
|
|
ret t;
|
2010-09-24 16:41:01 -07:00
|
|
|
}
|
|
|
|
|
2011-02-17 18:16:51 -08:00
|
|
|
fn T_taskptr(type_names tn) -> TypeRef {
|
|
|
|
ret T_ptr(T_task(tn));
|
2010-09-23 17:16:34 -07:00
|
|
|
}
|
|
|
|
|
2011-03-04 18:05:48 -08:00
|
|
|
// This type must never be used directly; it must always be cast away.
|
|
|
|
fn T_typaram(type_names tn) -> TypeRef {
|
2011-02-17 18:16:51 -08:00
|
|
|
auto s = "typaram";
|
|
|
|
if (tn.name_has_type(s)) {
|
|
|
|
ret tn.get_type(s);
|
|
|
|
}
|
|
|
|
|
2011-03-04 18:05:48 -08:00
|
|
|
auto t = T_i8();
|
2011-02-17 18:16:51 -08:00
|
|
|
tn.associate(s, t);
|
|
|
|
ret t;
|
2011-01-14 16:46:44 -08:00
|
|
|
}
|
|
|
|
|
2011-03-04 18:05:48 -08:00
|
|
|
fn T_typaram_ptr(type_names tn) -> TypeRef {
|
|
|
|
ret T_ptr(T_typaram(tn));
|
|
|
|
}
|
|
|
|
|
2011-02-17 18:16:51 -08:00
|
|
|
fn T_closure_ptr(type_names tn,
|
|
|
|
TypeRef lltarget_ty,
|
2011-02-23 10:58:43 -08:00
|
|
|
TypeRef llbindings_ty,
|
|
|
|
uint n_ty_params) -> TypeRef {
|
2011-03-07 18:13:39 -08:00
|
|
|
|
|
|
|
// NB: keep this in sync with code in trans_bind; we're making
|
|
|
|
// an LLVM typeref structure that has the same "shape" as the ty.t
|
|
|
|
// it constructs.
|
2011-02-17 18:16:51 -08:00
|
|
|
ret T_ptr(T_box(T_struct(vec(T_ptr(T_tydesc(tn)),
|
2011-01-07 15:12:23 -08:00
|
|
|
lltarget_ty,
|
2011-02-23 10:58:43 -08:00
|
|
|
llbindings_ty,
|
|
|
|
T_captured_tydescs(tn, n_ty_params))
|
2011-01-07 15:12:23 -08:00
|
|
|
)));
|
|
|
|
}
|
|
|
|
|
2011-02-17 18:16:51 -08:00
|
|
|
fn T_opaque_closure_ptr(type_names tn) -> TypeRef {
|
|
|
|
auto s = "*closure";
|
|
|
|
if (tn.name_has_type(s)) {
|
|
|
|
ret tn.get_type(s);
|
|
|
|
}
|
|
|
|
auto t = T_closure_ptr(tn, T_struct(vec(T_ptr(T_nil()),
|
|
|
|
T_ptr(T_nil()))),
|
2011-02-23 10:58:43 -08:00
|
|
|
T_nil(),
|
|
|
|
0u);
|
2011-02-17 18:16:51 -08:00
|
|
|
tn.associate(s, t);
|
|
|
|
ret t;
|
2011-01-07 15:12:23 -08:00
|
|
|
}
|
|
|
|
|
2011-03-04 15:08:33 -08:00
|
|
|
fn T_tag(type_names tn, uint size) -> TypeRef {
|
|
|
|
auto s = "tag_" + _uint.to_str(size, 10u);
|
|
|
|
if (tn.name_has_type(s)) {
|
|
|
|
ret tn.get_type(s);
|
|
|
|
}
|
|
|
|
auto t = T_struct(vec(T_int(), T_array(T_i8(), size)));
|
|
|
|
tn.associate(s, t);
|
|
|
|
ret t;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn T_opaque_tag(type_names tn) -> TypeRef {
|
2011-04-07 14:28:57 -07:00
|
|
|
auto s = "opaque_tag";
|
2011-03-03 15:52:54 -08:00
|
|
|
if (tn.name_has_type(s)) {
|
|
|
|
ret tn.get_type(s);
|
|
|
|
}
|
2011-03-04 15:08:33 -08:00
|
|
|
auto t = T_struct(vec(T_int(), T_i8()));
|
2011-03-03 15:52:54 -08:00
|
|
|
tn.associate(s, t);
|
|
|
|
ret t;
|
|
|
|
}
|
|
|
|
|
2011-03-04 15:08:33 -08:00
|
|
|
fn T_opaque_tag_ptr(type_names tn) -> TypeRef {
|
|
|
|
ret T_ptr(T_opaque_tag(tn));
|
|
|
|
}
|
|
|
|
|
2011-02-17 18:16:51 -08:00
|
|
|
fn T_captured_tydescs(type_names tn, uint n) -> TypeRef {
|
|
|
|
ret T_struct(_vec.init_elt[TypeRef](T_ptr(T_tydesc(tn)), n));
|
2011-02-03 14:40:57 -08:00
|
|
|
}
|
|
|
|
|
2011-03-03 11:49:35 -08:00
|
|
|
fn T_obj_ptr(type_names tn, uint n_captured_tydescs) -> TypeRef {
|
|
|
|
// This function is not publicly exposed because it returns an incomplete
|
|
|
|
// type. The dynamically-sized fields follow the captured tydescs.
|
|
|
|
fn T_obj(type_names tn, uint n_captured_tydescs) -> TypeRef {
|
|
|
|
ret T_struct(vec(T_ptr(T_tydesc(tn)),
|
|
|
|
T_captured_tydescs(tn, n_captured_tydescs)));
|
|
|
|
}
|
2011-02-03 14:40:57 -08:00
|
|
|
|
2011-03-03 11:49:35 -08:00
|
|
|
ret T_ptr(T_box(T_obj(tn, n_captured_tydescs)));
|
2011-02-03 14:40:57 -08:00
|
|
|
}
|
|
|
|
|
2011-02-17 18:16:51 -08:00
|
|
|
fn T_opaque_obj_ptr(type_names tn) -> TypeRef {
|
2011-03-03 11:49:35 -08:00
|
|
|
ret T_obj_ptr(tn, 0u);
|
2011-02-03 14:40:57 -08:00
|
|
|
}
|
|
|
|
|
2011-01-07 15:12:23 -08:00
|
|
|
|
2011-03-03 14:10:36 -08:00
|
|
|
// 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.
|
2011-04-22 12:27:28 -07:00
|
|
|
fn type_of(@crate_ctxt cx, ty.t t) -> TypeRef {
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_has_dynamic_size(cx.tystore, t)) {
|
2011-04-19 12:02:06 +02:00
|
|
|
log_err "type_of() called on a type with dynamic size: " +
|
2011-04-22 17:00:46 -07:00
|
|
|
ty.ty_to_str(cx.tystore, t);
|
2011-03-03 14:10:36 -08:00
|
|
|
fail;
|
|
|
|
}
|
|
|
|
|
2011-04-15 10:18:23 -07:00
|
|
|
ret type_of_inner(cx, t);
|
2010-11-20 22:04:34 -08:00
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
fn type_of_explicit_args(@crate_ctxt cx, vec[ty.arg] inputs) -> vec[TypeRef] {
|
2011-02-16 16:16:11 -05:00
|
|
|
let vec[TypeRef] atys = vec();
|
|
|
|
for (ty.arg arg in inputs) {
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_has_dynamic_size(cx.tystore, arg.ty)) {
|
2011-02-16 16:16:11 -05:00
|
|
|
check (arg.mode == ast.alias);
|
2011-03-16 14:58:02 -07:00
|
|
|
atys += vec(T_typaram_ptr(cx.tn));
|
2011-02-16 16:16:11 -05:00
|
|
|
} else {
|
2011-03-04 15:08:33 -08:00
|
|
|
let TypeRef t;
|
2011-02-16 16:16:11 -05:00
|
|
|
alt (arg.mode) {
|
|
|
|
case (ast.alias) {
|
2011-04-15 10:18:23 -07:00
|
|
|
t = T_ptr(type_of_inner(cx, arg.ty));
|
2011-03-04 15:08:33 -08:00
|
|
|
}
|
|
|
|
case (_) {
|
2011-04-15 10:18:23 -07:00
|
|
|
t = type_of_inner(cx, arg.ty);
|
2011-02-16 16:16:11 -05:00
|
|
|
}
|
|
|
|
}
|
2011-03-16 14:58:02 -07:00
|
|
|
atys += vec(t);
|
2011-02-16 16:16:11 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ret atys;
|
|
|
|
}
|
2011-02-08 11:47:53 -08:00
|
|
|
|
|
|
|
// NB: must keep 4 fns in sync:
|
|
|
|
//
|
|
|
|
// - type_of_fn_full
|
|
|
|
// - create_llargs_for_fn_args.
|
|
|
|
// - new_fn_ctxt
|
|
|
|
// - trans_args
|
|
|
|
|
2010-12-23 17:31:16 -08:00
|
|
|
fn type_of_fn_full(@crate_ctxt cx,
|
2011-02-18 17:30:57 -08:00
|
|
|
ast.proto proto,
|
2010-12-23 17:31:16 -08:00
|
|
|
option.t[TypeRef] obj_self,
|
|
|
|
vec[ty.arg] inputs,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t output,
|
2011-03-08 16:51:23 -08:00
|
|
|
uint ty_param_count) -> TypeRef {
|
2011-02-08 11:47:53 -08:00
|
|
|
let vec[TypeRef] atys = vec();
|
2010-12-16 16:34:20 -08:00
|
|
|
|
2011-02-08 11:47:53 -08:00
|
|
|
// Arg 0: Output pointer.
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_has_dynamic_size(cx.tystore, output)) {
|
2011-03-16 14:58:02 -07:00
|
|
|
atys += vec(T_typaram_ptr(cx.tn));
|
2011-02-08 11:47:53 -08:00
|
|
|
} else {
|
2011-04-15 10:18:23 -07:00
|
|
|
atys += vec(T_ptr(type_of_inner(cx, output)));
|
2011-01-14 16:46:44 -08:00
|
|
|
}
|
|
|
|
|
2011-02-08 11:47:53 -08:00
|
|
|
// Arg 1: Task pointer.
|
2011-03-16 14:58:02 -07:00
|
|
|
atys += vec(T_taskptr(cx.tn));
|
2011-02-08 11:47:53 -08:00
|
|
|
|
|
|
|
// Arg 2: Env (closure-bindings / self-obj)
|
2010-12-23 17:31:16 -08:00
|
|
|
alt (obj_self) {
|
|
|
|
case (some[TypeRef](?t)) {
|
|
|
|
check (t as int != 0);
|
2011-03-16 14:58:02 -07:00
|
|
|
atys += vec(t);
|
2010-12-23 17:31:16 -08:00
|
|
|
}
|
2011-01-07 15:12:23 -08:00
|
|
|
case (_) {
|
2011-03-16 14:58:02 -07:00
|
|
|
atys += vec(T_opaque_closure_ptr(cx.tn));
|
2011-01-07 15:12:23 -08:00
|
|
|
}
|
2010-12-23 17:31:16 -08:00
|
|
|
}
|
|
|
|
|
2011-02-09 09:54:58 -08:00
|
|
|
// Args >3: ty params, if not acquired via capture...
|
|
|
|
if (obj_self == none[TypeRef]) {
|
|
|
|
auto i = 0u;
|
|
|
|
while (i < ty_param_count) {
|
2011-03-16 14:58:02 -07:00
|
|
|
atys += vec(T_ptr(T_tydesc(cx.tn)));
|
2011-02-09 09:54:58 -08:00
|
|
|
i += 1u;
|
|
|
|
}
|
2011-02-08 11:47:53 -08:00
|
|
|
}
|
|
|
|
|
2011-02-18 17:30:57 -08:00
|
|
|
if (proto == ast.proto_iter) {
|
2011-02-17 12:20:55 -08:00
|
|
|
// 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.
|
2011-03-16 14:58:02 -07:00
|
|
|
atys +=
|
|
|
|
vec(T_fn_pair(cx.tn,
|
2011-02-18 17:30:57 -08:00
|
|
|
type_of_fn_full(cx, ast.proto_fn, none[TypeRef],
|
2011-04-23 14:17:44 -07:00
|
|
|
vec(rec(mode=ast.alias, ty=output)),
|
2011-04-20 18:52:04 -07:00
|
|
|
ty.mk_nil(cx.tystore), 0u)));
|
2011-02-17 12:20:55 -08:00
|
|
|
}
|
|
|
|
|
2011-02-08 11:47:53 -08:00
|
|
|
// ... then explicit args.
|
2011-02-16 16:16:11 -05:00
|
|
|
atys += type_of_explicit_args(cx, inputs);
|
2010-12-16 10:23:47 -08:00
|
|
|
|
2011-02-08 11:47:53 -08:00
|
|
|
ret T_fn(atys, llvm.LLVMVoidType());
|
2010-12-16 10:23:47 -08:00
|
|
|
}
|
|
|
|
|
2011-02-17 12:20:55 -08:00
|
|
|
fn type_of_fn(@crate_ctxt cx,
|
2011-02-18 17:30:57 -08:00
|
|
|
ast.proto proto,
|
2011-03-08 16:51:23 -08:00
|
|
|
vec[ty.arg] inputs,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t output,
|
2011-03-08 16:51:23 -08:00
|
|
|
uint ty_param_count) -> TypeRef {
|
|
|
|
ret type_of_fn_full(cx, proto, none[TypeRef], inputs, output,
|
|
|
|
ty_param_count);
|
2010-12-23 17:31:16 -08:00
|
|
|
}
|
|
|
|
|
2011-02-25 15:58:08 -05:00
|
|
|
fn type_of_native_fn(@crate_ctxt cx, ast.native_abi abi,
|
|
|
|
vec[ty.arg] inputs,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t output,
|
2011-03-18 15:01:45 -07:00
|
|
|
uint ty_param_count) -> TypeRef {
|
2011-02-28 10:37:49 -05:00
|
|
|
let vec[TypeRef] atys = vec();
|
|
|
|
if (abi == ast.native_abi_rust) {
|
2011-03-16 14:58:02 -07:00
|
|
|
atys += vec(T_taskptr(cx.tn));
|
2011-02-28 10:37:49 -05:00
|
|
|
auto t = ty.ty_native_fn(abi, inputs, output);
|
|
|
|
auto i = 0u;
|
|
|
|
while (i < ty_param_count) {
|
2011-03-16 14:58:02 -07:00
|
|
|
atys += vec(T_ptr(T_tydesc(cx.tn)));
|
2011-02-28 10:37:49 -05:00
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
atys += type_of_explicit_args(cx, inputs);
|
2011-04-15 10:18:23 -07:00
|
|
|
ret T_fn(atys, type_of_inner(cx, output));
|
2011-02-16 16:16:11 -05:00
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn type_of_inner(@crate_ctxt cx, ty.t t) -> TypeRef {
|
2011-04-19 16:40:46 -07:00
|
|
|
// Check the cache.
|
|
|
|
if (cx.lltypes.contains_key(t)) {
|
|
|
|
ret cx.lltypes.get(t);
|
|
|
|
}
|
|
|
|
|
2011-02-25 16:24:19 -08:00
|
|
|
let TypeRef llty = 0 as TypeRef;
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.tystore, t)) {
|
2011-02-25 16:24:19 -08:00
|
|
|
case (ty.ty_native) { llty = T_ptr(T_i8()); }
|
|
|
|
case (ty.ty_nil) { llty = T_nil(); }
|
|
|
|
case (ty.ty_bool) { llty = T_bool(); }
|
|
|
|
case (ty.ty_int) { llty = T_int(); }
|
2011-03-21 17:12:05 -07:00
|
|
|
case (ty.ty_float) { llty = T_float(); }
|
2011-02-25 16:24:19 -08:00
|
|
|
case (ty.ty_uint) { llty = T_int(); }
|
2010-12-21 12:13:51 -08:00
|
|
|
case (ty.ty_machine(?tm)) {
|
2010-10-19 14:54:10 -07:00
|
|
|
alt (tm) {
|
2011-02-25 16:24:19 -08:00
|
|
|
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(); }
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
|
|
|
}
|
2011-02-25 16:24:19 -08:00
|
|
|
case (ty.ty_char) { llty = T_char(); }
|
|
|
|
case (ty.ty_str) { llty = T_ptr(T_str()); }
|
2011-03-04 15:08:33 -08:00
|
|
|
case (ty.ty_tag(_, _)) {
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_has_dynamic_size(cx.tystore, t)) {
|
2011-03-04 15:08:33 -08:00
|
|
|
llty = T_opaque_tag(cx.tn);
|
|
|
|
} else {
|
|
|
|
auto size = static_size_of_tag(cx, t);
|
|
|
|
llty = T_tag(cx.tn, size);
|
|
|
|
}
|
2010-12-01 19:03:47 -08:00
|
|
|
}
|
2011-03-17 17:39:47 -07:00
|
|
|
case (ty.ty_box(?mt)) {
|
2011-04-15 10:18:23 -07:00
|
|
|
llty = T_ptr(T_box(type_of_inner(cx, mt.ty)));
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2011-03-17 17:39:47 -07:00
|
|
|
case (ty.ty_vec(?mt)) {
|
2011-04-15 10:18:23 -07:00
|
|
|
llty = T_ptr(T_vec(type_of_inner(cx, mt.ty)));
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2011-03-16 21:49:15 -04:00
|
|
|
case (ty.ty_port(?t)) {
|
2011-04-15 10:18:23 -07:00
|
|
|
llty = T_ptr(T_port(type_of_inner(cx, t)));
|
2011-03-16 21:49:15 -04:00
|
|
|
}
|
|
|
|
case (ty.ty_chan(?t)) {
|
2011-04-15 10:18:23 -07:00
|
|
|
llty = T_ptr(T_chan(type_of_inner(cx, t)));
|
2011-03-16 21:49:15 -04:00
|
|
|
}
|
2010-12-21 12:13:51 -08:00
|
|
|
case (ty.ty_tup(?elts)) {
|
2010-10-19 14:54:10 -07:00
|
|
|
let vec[TypeRef] tys = vec();
|
2011-03-17 17:39:47 -07:00
|
|
|
for (ty.mt elt in elts) {
|
2011-04-15 10:18:23 -07:00
|
|
|
tys += vec(type_of_inner(cx, elt.ty));
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2011-02-25 16:24:19 -08:00
|
|
|
llty = T_struct(tys);
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2010-12-21 12:13:51 -08:00
|
|
|
case (ty.ty_rec(?fields)) {
|
2010-11-30 10:39:35 -08:00
|
|
|
let vec[TypeRef] tys = vec();
|
2010-12-21 12:13:51 -08:00
|
|
|
for (ty.field f in fields) {
|
2011-04-15 10:18:23 -07:00
|
|
|
tys += vec(type_of_inner(cx, f.mt.ty));
|
2010-11-30 10:39:35 -08:00
|
|
|
}
|
2011-02-25 16:24:19 -08:00
|
|
|
llty = T_struct(tys);
|
2010-11-30 10:39:35 -08:00
|
|
|
}
|
2011-02-18 17:30:57 -08:00
|
|
|
case (ty.ty_fn(?proto, ?args, ?out)) {
|
2011-03-08 16:51:23 -08:00
|
|
|
llty = T_fn_pair(cx.tn, type_of_fn(cx, proto, args, out, 0u));
|
2010-12-16 10:23:47 -08:00
|
|
|
}
|
2011-02-25 15:58:08 -05:00
|
|
|
case (ty.ty_native_fn(?abi, ?args, ?out)) {
|
2011-04-03 15:23:58 -07:00
|
|
|
auto nft = native_fn_wrapper_type(cx, 0u, t);
|
2011-03-18 15:01:45 -07:00
|
|
|
llty = T_fn_pair(cx.tn, nft);
|
2011-02-16 16:16:11 -05:00
|
|
|
}
|
2010-12-21 12:13:51 -08:00
|
|
|
case (ty.ty_obj(?meths)) {
|
2010-12-23 17:31:16 -08:00
|
|
|
auto th = mk_type_handle();
|
|
|
|
auto self_ty = llvm.LLVMResolveTypeHandle(th.llth);
|
|
|
|
|
2010-12-16 10:23:47 -08:00
|
|
|
let vec[TypeRef] mtys = vec();
|
2010-12-21 12:13:51 -08:00
|
|
|
for (ty.method m in meths) {
|
2010-12-23 17:31:16 -08:00
|
|
|
let TypeRef mty =
|
2011-02-18 17:30:57 -08:00
|
|
|
type_of_fn_full(cx, m.proto,
|
2010-12-23 17:31:16 -08:00
|
|
|
some[TypeRef](self_ty),
|
2011-03-08 16:51:23 -08:00
|
|
|
m.inputs, m.output, 0u);
|
2011-03-16 14:58:02 -07:00
|
|
|
mtys += vec(T_ptr(mty));
|
2010-12-13 16:12:45 -08:00
|
|
|
}
|
2010-12-16 10:23:47 -08:00
|
|
|
let TypeRef vtbl = T_struct(mtys);
|
2011-02-03 14:40:57 -08:00
|
|
|
let TypeRef pair = T_struct(vec(T_ptr(vtbl),
|
2011-02-17 18:16:51 -08:00
|
|
|
T_opaque_obj_ptr(cx.tn)));
|
2011-02-03 14:40:57 -08:00
|
|
|
|
2010-12-23 17:31:16 -08:00
|
|
|
auto abs_pair = llvm.LLVMResolveTypeHandle(th.llth);
|
|
|
|
llvm.LLVMRefineType(abs_pair, pair);
|
|
|
|
abs_pair = llvm.LLVMResolveTypeHandle(th.llth);
|
2011-02-25 16:24:19 -08:00
|
|
|
llty = abs_pair;
|
2010-11-19 20:08:57 -08:00
|
|
|
}
|
2010-12-21 12:13:51 -08:00
|
|
|
case (ty.ty_var(_)) {
|
2011-04-19 12:02:06 +02:00
|
|
|
log_err "ty_var in trans.type_of";
|
2010-12-16 12:23:48 -08:00
|
|
|
fail;
|
|
|
|
}
|
2010-12-21 12:13:51 -08:00
|
|
|
case (ty.ty_param(_)) {
|
2011-03-07 14:05:16 -08:00
|
|
|
llty = T_i8();
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2011-04-08 21:27:54 -07:00
|
|
|
case (ty.ty_bound_param(_)) {
|
2011-04-19 12:02:06 +02:00
|
|
|
log_err "ty_bound_param in trans.type_of";
|
2011-04-08 21:27:54 -07:00
|
|
|
fail;
|
|
|
|
}
|
2011-02-25 16:24:19 -08:00
|
|
|
case (ty.ty_type) { llty = T_ptr(T_tydesc(cx.tn)); }
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2011-02-25 16:24:19 -08:00
|
|
|
|
|
|
|
check (llty as int != 0);
|
2011-04-22 17:00:46 -07:00
|
|
|
llvm.LLVMAddTypeName(cx.llmod, _str.buf(ty.ty_to_str(cx.tystore, t)),
|
|
|
|
llty);
|
2011-04-19 16:40:46 -07:00
|
|
|
cx.lltypes.insert(t, llty);
|
2011-02-25 16:24:19 -08:00
|
|
|
ret llty;
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
fn type_of_arg(@local_ctxt cx, &ty.arg arg) -> TypeRef {
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.ccx.tystore, arg.ty)) {
|
2011-03-02 16:13:33 -08:00
|
|
|
case (ty.ty_param(_)) {
|
|
|
|
if (arg.mode == ast.alias) {
|
2011-04-17 14:24:45 +02:00
|
|
|
ret T_typaram_ptr(cx.ccx.tn);
|
2011-03-02 16:13:33 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
case (_) {
|
|
|
|
// fall through
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-04 15:08:33 -08:00
|
|
|
auto typ;
|
2010-12-06 16:50:24 -08:00
|
|
|
if (arg.mode == ast.alias) {
|
2011-04-17 14:24:45 +02:00
|
|
|
typ = T_ptr(type_of_inner(cx.ccx, arg.ty));
|
2011-03-04 15:08:33 -08:00
|
|
|
} else {
|
2011-04-17 14:24:45 +02:00
|
|
|
typ = type_of_inner(cx.ccx, arg.ty);
|
2010-12-06 16:50:24 -08:00
|
|
|
}
|
2011-03-02 16:13:33 -08:00
|
|
|
ret typ;
|
2010-12-06 16:50:24 -08:00
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
fn type_of_ty_param_count_and_ty(@local_ctxt lcx,
|
2011-04-12 15:09:50 -07:00
|
|
|
ty.ty_param_count_and_ty tpt) -> TypeRef {
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(lcx.ccx.tystore, tpt._1)) {
|
2011-03-30 18:15:29 -07:00
|
|
|
case (ty.ty_fn(?proto, ?inputs, ?output)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llfnty = type_of_fn(lcx.ccx, proto, inputs, output, tpt._0);
|
|
|
|
ret T_fn_pair(lcx.ccx.tn, llfnty);
|
2011-03-30 18:15:29 -07:00
|
|
|
}
|
|
|
|
case (_) {
|
|
|
|
// fall through
|
|
|
|
}
|
|
|
|
}
|
2011-04-17 14:24:45 +02:00
|
|
|
ret type_of(lcx.ccx, tpt._1);
|
2011-03-30 18:15:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-10 15:02:23 -08:00
|
|
|
// Name sanitation. LLVM will happily accept identifiers with weird names, but
|
|
|
|
// gas doesn't!
|
|
|
|
|
|
|
|
fn sanitize(str s) -> str {
|
|
|
|
auto result = "";
|
|
|
|
for (u8 c in s) {
|
|
|
|
if (c == ('@' as u8)) {
|
|
|
|
result += "boxed_";
|
|
|
|
} else {
|
2010-12-20 19:52:14 -08:00
|
|
|
if (c == (',' as u8)) {
|
|
|
|
result += "_";
|
|
|
|
} else {
|
|
|
|
if (c == ('{' as u8) || c == ('(' as u8)) {
|
|
|
|
result += "_of_";
|
|
|
|
} else {
|
|
|
|
if (c != 10u8 && c != ('}' as u8) && c != (')' as u8) &&
|
2011-01-21 07:50:02 -08:00
|
|
|
c != (' ' as u8) && c != ('\t' as u8) &&
|
|
|
|
c != (';' as u8)) {
|
2010-12-20 19:52:14 -08:00
|
|
|
auto v = vec(c);
|
|
|
|
result += _str.from_bytes(v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ret result;
|
|
|
|
}
|
|
|
|
|
2010-09-24 14:56:04 -07:00
|
|
|
// LLVM constant constructors.
|
|
|
|
|
|
|
|
fn C_null(TypeRef t) -> ValueRef {
|
|
|
|
ret llvm.LLVMConstNull(t);
|
|
|
|
}
|
|
|
|
|
2010-09-28 12:23:40 -07:00
|
|
|
fn C_integral(int i, TypeRef t) -> ValueRef {
|
2010-09-24 14:56:04 -07:00
|
|
|
// FIXME. We can't use LLVM.ULongLong with our existing minimal native
|
|
|
|
// API, which only knows word-sized args. Lucky for us LLVM has a "take a
|
|
|
|
// string encoding" version. Hilarious. Please fix to handle:
|
|
|
|
//
|
|
|
|
// ret llvm.LLVMConstInt(T_int(), t as LLVM.ULongLong, False);
|
|
|
|
//
|
2010-09-28 12:23:40 -07:00
|
|
|
ret llvm.LLVMConstIntOfString(t, _str.buf(istr(i)), 10);
|
|
|
|
}
|
|
|
|
|
2011-03-21 17:12:05 -07:00
|
|
|
fn C_float(str s) -> ValueRef {
|
|
|
|
ret llvm.LLVMConstRealOfString(T_float(), _str.buf(s));
|
|
|
|
}
|
|
|
|
|
2011-03-22 17:25:40 -07:00
|
|
|
fn C_floating(str s, TypeRef t) -> ValueRef {
|
|
|
|
ret llvm.LLVMConstRealOfString(t, _str.buf(s));
|
|
|
|
}
|
|
|
|
|
2010-10-04 15:55:12 -07:00
|
|
|
fn C_nil() -> ValueRef {
|
|
|
|
// NB: See comment above in T_void().
|
|
|
|
ret C_integral(0, T_i1());
|
|
|
|
}
|
|
|
|
|
2010-09-28 14:01:21 -07:00
|
|
|
fn C_bool(bool b) -> ValueRef {
|
|
|
|
if (b) {
|
2010-10-19 17:24:15 -07:00
|
|
|
ret C_integral(1, T_bool());
|
2010-09-28 14:01:21 -07:00
|
|
|
} else {
|
2010-10-19 17:24:15 -07:00
|
|
|
ret C_integral(0, T_bool());
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-28 12:23:40 -07:00
|
|
|
fn C_int(int i) -> ValueRef {
|
|
|
|
ret C_integral(i, T_int());
|
2010-09-24 14:56:04 -07:00
|
|
|
}
|
|
|
|
|
2011-04-19 15:22:57 -07:00
|
|
|
fn C_i8(uint i) -> ValueRef {
|
|
|
|
ret C_integral(i as int, T_i8());
|
|
|
|
}
|
|
|
|
|
2011-01-21 12:09:25 -08:00
|
|
|
// This is a 'c-like' raw string, which differs from
|
|
|
|
// our boxed-and-length-annotated strings.
|
|
|
|
fn C_cstr(@crate_ctxt cx, str s) -> ValueRef {
|
2010-09-28 12:23:40 -07:00
|
|
|
auto sc = llvm.LLVMConstString(_str.buf(s), _str.byte_len(s), False);
|
2010-09-29 17:22:07 -07:00
|
|
|
auto g = llvm.LLVMAddGlobal(cx.llmod, val_ty(sc),
|
2010-09-28 12:23:40 -07:00
|
|
|
_str.buf(cx.names.next("str")));
|
|
|
|
llvm.LLVMSetInitializer(g, sc);
|
2010-12-09 13:49:26 -08:00
|
|
|
llvm.LLVMSetGlobalConstant(g, True);
|
2011-04-01 15:01:46 -07:00
|
|
|
llvm.LLVMSetLinkage(g, lib.llvm.LLVMInternalLinkage
|
2011-01-05 15:31:35 -08:00
|
|
|
as llvm.Linkage);
|
2010-09-28 12:23:40 -07:00
|
|
|
ret g;
|
2010-09-24 14:56:04 -07:00
|
|
|
}
|
|
|
|
|
2011-01-21 12:09:25 -08:00
|
|
|
// A rust boxed-and-length-annotated string.
|
|
|
|
fn C_str(@crate_ctxt cx, str s) -> ValueRef {
|
|
|
|
auto len = _str.byte_len(s);
|
|
|
|
auto box = C_struct(vec(C_int(abi.const_refcount as int),
|
|
|
|
C_int(len + 1u as int), // 'alloc'
|
|
|
|
C_int(len + 1u as int), // 'fill'
|
2011-04-02 19:03:43 -07:00
|
|
|
C_int(0), // 'pad'
|
2011-01-21 12:09:25 -08:00
|
|
|
llvm.LLVMConstString(_str.buf(s),
|
|
|
|
len, False)));
|
|
|
|
auto g = llvm.LLVMAddGlobal(cx.llmod, val_ty(box),
|
|
|
|
_str.buf(cx.names.next("str")));
|
|
|
|
llvm.LLVMSetInitializer(g, box);
|
|
|
|
llvm.LLVMSetGlobalConstant(g, True);
|
2011-04-01 15:01:46 -07:00
|
|
|
llvm.LLVMSetLinkage(g, lib.llvm.LLVMInternalLinkage
|
2011-01-21 12:09:25 -08:00
|
|
|
as llvm.Linkage);
|
|
|
|
ret llvm.LLVMConstPointerCast(g, T_ptr(T_str()));
|
|
|
|
}
|
|
|
|
|
2010-12-03 16:55:59 -08:00
|
|
|
fn C_zero_byte_arr(uint size) -> ValueRef {
|
|
|
|
auto i = 0u;
|
|
|
|
let vec[ValueRef] elts = vec();
|
|
|
|
while (i < size) {
|
|
|
|
elts += vec(C_integral(0, T_i8()));
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
ret llvm.LLVMConstArray(T_i8(), _vec.buf[ValueRef](elts),
|
|
|
|
_vec.len[ValueRef](elts));
|
|
|
|
}
|
|
|
|
|
2010-09-24 14:56:04 -07:00
|
|
|
fn C_struct(vec[ValueRef] elts) -> ValueRef {
|
|
|
|
ret llvm.LLVMConstStruct(_vec.buf[ValueRef](elts),
|
|
|
|
_vec.len[ValueRef](elts),
|
|
|
|
False);
|
|
|
|
}
|
|
|
|
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
fn C_array(TypeRef ty, vec[ValueRef] elts) -> ValueRef {
|
|
|
|
ret llvm.LLVMConstArray(ty, _vec.buf[ValueRef](elts),
|
|
|
|
_vec.len[ValueRef](elts));
|
|
|
|
}
|
|
|
|
|
2010-11-03 16:43:12 -07:00
|
|
|
fn decl_fn(ModuleRef llmod, str name, uint cc, TypeRef llty) -> ValueRef {
|
2010-09-23 17:16:34 -07:00
|
|
|
let ValueRef llfn =
|
|
|
|
llvm.LLVMAddFunction(llmod, _str.buf(name), llty);
|
2010-11-14 12:28:07 -08:00
|
|
|
llvm.LLVMSetFunctionCallConv(llfn, cc);
|
2010-09-23 17:16:34 -07:00
|
|
|
ret llfn;
|
|
|
|
}
|
|
|
|
|
2010-11-03 16:43:12 -07:00
|
|
|
fn decl_cdecl_fn(ModuleRef llmod, str name, TypeRef llty) -> ValueRef {
|
|
|
|
ret decl_fn(llmod, name, lib.llvm.LLVMCCallConv, llty);
|
2010-11-14 12:28:07 -08:00
|
|
|
}
|
|
|
|
|
2010-11-03 16:43:12 -07:00
|
|
|
fn decl_fastcall_fn(ModuleRef llmod, str name, TypeRef llty) -> ValueRef {
|
|
|
|
ret decl_fn(llmod, name, lib.llvm.LLVMFastCallConv, llty);
|
2010-11-14 12:28:07 -08:00
|
|
|
}
|
|
|
|
|
2011-04-01 15:01:46 -07:00
|
|
|
fn decl_internal_fastcall_fn(ModuleRef llmod,
|
2011-04-01 16:04:22 -07:00
|
|
|
str name, TypeRef llty) -> ValueRef {
|
2011-03-26 19:14:07 -07:00
|
|
|
auto llfn = decl_fn(llmod, name, lib.llvm.LLVMFastCallConv, llty);
|
2011-04-01 15:01:46 -07:00
|
|
|
llvm.LLVMSetLinkage(llfn, lib.llvm.LLVMInternalLinkage as llvm.Linkage);
|
2011-03-26 19:14:07 -07:00
|
|
|
ret llfn;
|
|
|
|
}
|
|
|
|
|
2011-02-17 18:16:51 -08:00
|
|
|
fn decl_glue(ModuleRef llmod, type_names tn, str s) -> ValueRef {
|
|
|
|
ret decl_cdecl_fn(llmod, s, T_fn(vec(T_taskptr(tn)), T_void()));
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
|
|
|
|
2011-03-25 15:48:00 -07:00
|
|
|
fn decl_native_glue(ModuleRef llmod, type_names tn,
|
2011-03-21 17:47:38 -04:00
|
|
|
bool pass_task, uint _n) -> ValueRef {
|
2010-09-24 15:22:48 -07:00
|
|
|
// It doesn't actually matter what type we come up with here, at the
|
2011-03-25 15:48:00 -07:00
|
|
|
// moment, as we cast the native function pointers to int before passing
|
|
|
|
// them to the indirect native-invocation glue. But eventually we'd like
|
2010-09-24 15:22:48 -07:00
|
|
|
// to call them directly, once we have a calling convention worked out.
|
2010-09-23 17:16:34 -07:00
|
|
|
let int n = _n as int;
|
2011-03-25 15:48:00 -07:00
|
|
|
let str s = abi.native_glue_name(n, pass_task);
|
2011-03-21 17:47:38 -04:00
|
|
|
let vec[TypeRef] args = vec(T_int()); // callee
|
2011-03-23 16:31:30 -07:00
|
|
|
if (!pass_task) {
|
|
|
|
args += vec(T_int()); // taskptr, will not be passed
|
2011-03-21 17:47:38 -04:00
|
|
|
}
|
|
|
|
args += _vec.init_elt[TypeRef](T_int(), n as uint);
|
2010-09-23 17:16:34 -07:00
|
|
|
|
2010-11-03 16:43:12 -07:00
|
|
|
ret decl_fastcall_fn(llmod, s, T_fn(args, T_int()));
|
2010-09-23 17:16:34 -07:00
|
|
|
}
|
|
|
|
|
2011-03-25 17:59:45 -07:00
|
|
|
fn get_extern_fn(&hashmap[str, ValueRef] externs,
|
|
|
|
ModuleRef llmod, str name,
|
|
|
|
uint cc, TypeRef ty) -> ValueRef {
|
2011-03-25 15:48:00 -07:00
|
|
|
if (externs.contains_key(name)) {
|
|
|
|
ret externs.get(name);
|
2010-09-23 18:38:37 -07:00
|
|
|
}
|
2011-03-25 17:59:45 -07:00
|
|
|
auto f = decl_fn(llmod, name, cc, ty);
|
2011-03-25 15:48:00 -07:00
|
|
|
externs.insert(name, f);
|
2010-09-23 18:38:37 -07:00
|
|
|
ret f;
|
|
|
|
}
|
|
|
|
|
2011-03-25 17:59:45 -07:00
|
|
|
fn get_extern_const(&hashmap[str, ValueRef] externs,
|
|
|
|
ModuleRef llmod, str name, TypeRef ty) -> ValueRef {
|
|
|
|
if (externs.contains_key(name)) {
|
|
|
|
ret externs.get(name);
|
|
|
|
}
|
|
|
|
auto c = llvm.LLVMAddGlobal(llmod, ty, _str.buf(name));
|
|
|
|
externs.insert(name, c);
|
|
|
|
ret c;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_simple_extern_fn(&hashmap[str, ValueRef] externs,
|
2011-04-01 16:04:22 -07:00
|
|
|
ModuleRef llmod, str name, int n_args) -> ValueRef {
|
2011-03-25 17:59:45 -07:00
|
|
|
auto inputs = _vec.init_elt[TypeRef](T_int(), n_args as uint);
|
|
|
|
auto output = T_int();
|
|
|
|
auto t = T_fn(inputs, output);
|
|
|
|
ret get_extern_fn(externs, llmod, name, lib.llvm.LLVMCCallConv, t);
|
|
|
|
}
|
|
|
|
|
2010-10-04 15:55:12 -07:00
|
|
|
fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args) -> result {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto cxx = cx.fcx.lcx.ccx;
|
2011-03-23 16:31:30 -07:00
|
|
|
auto lltaskptr = cx.build.PtrToInt(cx.fcx.lltaskptr, T_int());
|
|
|
|
auto args2 = vec(lltaskptr) + args;
|
2011-03-29 13:21:36 -07:00
|
|
|
auto t = trans_native_call(cx.build, cxx.glues, lltaskptr,
|
|
|
|
cxx.externs, cxx.tn, cxx.llmod, name,
|
|
|
|
true, args2);
|
2011-03-10 17:25:11 -08:00
|
|
|
ret res(cx, t);
|
|
|
|
}
|
|
|
|
|
2011-03-29 13:21:36 -07:00
|
|
|
fn trans_native_call(builder b, @glue_fns glues, ValueRef lltaskptr,
|
|
|
|
&hashmap[str, ValueRef] externs,
|
|
|
|
type_names tn, ModuleRef llmod, str name,
|
|
|
|
bool pass_task, vec[ValueRef] args) -> ValueRef {
|
2011-03-21 11:59:14 -04:00
|
|
|
let int n = (_vec.len[ValueRef](args) as int);
|
2011-03-25 17:59:45 -07:00
|
|
|
let ValueRef llnative = get_simple_extern_fn(externs, llmod, name, n);
|
2011-03-25 15:48:00 -07:00
|
|
|
llnative = llvm.LLVMConstPointerCast(llnative, T_int());
|
2010-09-24 14:56:04 -07:00
|
|
|
|
2011-03-21 17:47:38 -04:00
|
|
|
let ValueRef llglue;
|
|
|
|
if (pass_task) {
|
2011-03-25 15:48:00 -07:00
|
|
|
llglue = glues.native_glues_rust.(n);
|
2011-03-21 17:47:38 -04:00
|
|
|
} else {
|
2011-03-25 15:48:00 -07:00
|
|
|
llglue = glues.native_glues_cdecl.(n);
|
2011-03-21 17:47:38 -04:00
|
|
|
}
|
2011-03-25 15:48:00 -07:00
|
|
|
let vec[ValueRef] call_args = vec(llnative);
|
2011-03-21 17:12:05 -07:00
|
|
|
|
2011-03-23 16:31:30 -07:00
|
|
|
if (!pass_task) {
|
|
|
|
call_args += vec(lltaskptr);
|
|
|
|
}
|
2011-02-08 11:47:53 -08:00
|
|
|
|
2010-09-28 12:23:40 -07:00
|
|
|
for (ValueRef a in args) {
|
2011-03-16 14:58:02 -07:00
|
|
|
call_args += vec(b.ZExtOrBitCast(a, T_int()));
|
2010-09-28 12:23:40 -07:00
|
|
|
}
|
2011-02-08 11:47:53 -08:00
|
|
|
|
2011-03-10 17:25:11 -08:00
|
|
|
ret b.FastCall(llglue, call_args);
|
2010-09-24 14:56:04 -07:00
|
|
|
}
|
|
|
|
|
2010-10-04 15:55:12 -07:00
|
|
|
fn trans_non_gc_free(@block_ctxt cx, ValueRef v) -> result {
|
2011-03-02 16:42:09 -08:00
|
|
|
ret trans_upcall(cx, "upcall_free", vec(vp2i(cx, v),
|
2010-10-04 15:55:12 -07:00
|
|
|
C_int(0)));
|
2010-09-29 17:22:07 -07:00
|
|
|
}
|
|
|
|
|
2010-12-02 19:12:34 -08:00
|
|
|
fn find_scope_cx(@block_ctxt cx) -> @block_ctxt {
|
2011-03-25 16:28:16 +01:00
|
|
|
if (cx.kind != NON_SCOPE_BLOCK) {
|
2010-12-02 19:12:34 -08:00
|
|
|
ret cx;
|
|
|
|
}
|
|
|
|
alt (cx.parent) {
|
|
|
|
case (parent_some(?b)) {
|
|
|
|
be find_scope_cx(b);
|
|
|
|
}
|
|
|
|
case (parent_none) {
|
|
|
|
fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-31 21:20:10 -04:00
|
|
|
fn find_outer_scope_cx(@block_ctxt cx) -> @block_ctxt {
|
|
|
|
auto scope_cx = find_scope_cx(cx);
|
|
|
|
alt (cx.parent) {
|
|
|
|
case (parent_some(?b)) {
|
|
|
|
be find_scope_cx(b);
|
|
|
|
}
|
|
|
|
case (parent_none) {
|
|
|
|
fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-18 15:38:35 -08:00
|
|
|
fn umax(@block_ctxt cx, ValueRef a, ValueRef b) -> ValueRef {
|
|
|
|
auto cond = cx.build.ICmp(lib.llvm.LLVMIntULT, a, b);
|
|
|
|
ret cx.build.Select(cond, b, a);
|
|
|
|
}
|
|
|
|
|
2011-03-09 20:14:19 -08:00
|
|
|
fn umin(@block_ctxt cx, ValueRef a, ValueRef b) -> ValueRef {
|
|
|
|
auto cond = cx.build.ICmp(lib.llvm.LLVMIntULT, a, b);
|
|
|
|
ret cx.build.Select(cond, a, b);
|
|
|
|
}
|
|
|
|
|
2011-01-18 15:38:35 -08:00
|
|
|
fn align_to(@block_ctxt cx, ValueRef off, ValueRef align) -> ValueRef {
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2011-03-04 15:08:33 -08:00
|
|
|
// Returns the real size of the given type for the current target.
|
|
|
|
fn llsize_of_real(@crate_ctxt cx, TypeRef t) -> uint {
|
|
|
|
ret llvm.LLVMStoreSizeOfType(cx.td.lltd, t);
|
|
|
|
}
|
|
|
|
|
2011-01-18 15:38:35 -08:00
|
|
|
fn llsize_of(TypeRef t) -> ValueRef {
|
2010-12-20 12:54:50 -08:00
|
|
|
ret llvm.LLVMConstIntCast(lib.llvm.llvm.LLVMSizeOf(t), T_int(), False);
|
|
|
|
}
|
|
|
|
|
2011-01-18 15:38:35 -08:00
|
|
|
fn llalign_of(TypeRef t) -> ValueRef {
|
2010-12-20 12:54:50 -08:00
|
|
|
ret llvm.LLVMConstIntCast(lib.llvm.llvm.LLVMAlignOf(t), T_int(), False);
|
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn size_of(@block_ctxt cx, ty.t t) -> result {
|
2011-04-22 17:00:46 -07:00
|
|
|
if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
ret res(cx, llsize_of(type_of(cx.fcx.lcx.ccx, t)));
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
|
|
|
ret dynamic_size_of(cx, t);
|
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn align_of(@block_ctxt cx, ty.t t) -> result {
|
2011-04-22 17:00:46 -07:00
|
|
|
if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
ret res(cx, llalign_of(type_of(cx.fcx.lcx.ccx, t)));
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
|
|
|
ret dynamic_align_of(cx, t);
|
|
|
|
}
|
|
|
|
|
2011-03-28 18:04:52 -07:00
|
|
|
fn alloca(@block_ctxt cx, TypeRef t) -> ValueRef {
|
|
|
|
ret new_builder(cx.fcx.llallocas).Alloca(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn array_alloca(@block_ctxt cx, TypeRef t, ValueRef n) -> ValueRef {
|
|
|
|
ret new_builder(cx.fcx.llallocas).ArrayAlloca(t, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-04-15 10:18:23 -07:00
|
|
|
// 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.
|
2011-04-22 12:27:28 -07:00
|
|
|
fn simplify_type(@crate_ctxt ccx, ty.t typ) -> ty.t {
|
|
|
|
fn simplifier(@crate_ctxt ccx, ty.t typ) -> ty.t {
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(ccx.tystore, typ)) {
|
2011-04-15 10:18:23 -07:00
|
|
|
case (ty.ty_box(_)) {
|
2011-04-20 18:52:04 -07:00
|
|
|
ret ty.mk_imm_box(ccx.tystore, ty.mk_nil(ccx.tystore));
|
2011-04-15 10:18:23 -07:00
|
|
|
}
|
|
|
|
case (_) { ret typ; }
|
|
|
|
}
|
|
|
|
}
|
2011-04-20 18:52:04 -07:00
|
|
|
auto f = bind simplifier(ccx, _);
|
|
|
|
ret ty.fold_ty(ccx.tystore, f, typ);
|
2011-04-15 10:18:23 -07:00
|
|
|
}
|
|
|
|
|
2011-03-04 15:08:33 -08:00
|
|
|
// Computes the size of the data part of a non-dynamically-sized tag.
|
2011-04-22 12:27:28 -07:00
|
|
|
fn static_size_of_tag(@crate_ctxt cx, ty.t t) -> uint {
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_has_dynamic_size(cx.tystore, t)) {
|
2011-04-19 12:02:06 +02:00
|
|
|
log_err "dynamically sized type passed to static_size_of_tag()";
|
2011-03-04 15:08:33 -08:00
|
|
|
fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cx.tag_sizes.contains_key(t)) {
|
|
|
|
ret cx.tag_sizes.get(t);
|
|
|
|
}
|
|
|
|
|
2011-03-06 13:56:38 -05:00
|
|
|
auto tid;
|
2011-04-22 12:27:28 -07:00
|
|
|
let vec[ty.t] subtys;
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.tystore, t)) {
|
2011-03-04 15:08:33 -08:00
|
|
|
case (ty.ty_tag(?tid_, ?subtys_)) {
|
|
|
|
tid = tid_;
|
|
|
|
subtys = subtys_;
|
|
|
|
}
|
|
|
|
case (_) {
|
2011-04-19 12:02:06 +02:00
|
|
|
log_err "non-tag passed to static_size_of_tag()";
|
2011-03-04 15:08:33 -08:00
|
|
|
fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compute max(variant sizes).
|
|
|
|
auto max_size = 0u;
|
|
|
|
auto variants = tag_variants(cx, tid);
|
2011-04-01 11:36:52 -07:00
|
|
|
for (variant_info variant in variants) {
|
2011-04-20 18:52:04 -07:00
|
|
|
auto tup_ty = simplify_type(cx,
|
|
|
|
ty.mk_imm_tup(cx.tystore, variant.args));
|
2011-03-04 15:08:33 -08:00
|
|
|
|
2011-03-09 12:22:08 -08:00
|
|
|
// Perform any type parameter substitutions.
|
2011-04-20 18:52:04 -07:00
|
|
|
tup_ty = ty.bind_params_in_type(cx.tystore, tup_ty);
|
|
|
|
tup_ty = ty.substitute_type_params(cx.tystore, subtys, tup_ty);
|
2011-03-09 12:22:08 -08:00
|
|
|
|
2011-03-04 15:08:33 -08:00
|
|
|
// Here we possibly do a recursive call.
|
|
|
|
auto this_size = llsize_of_real(cx, type_of(cx, tup_ty));
|
|
|
|
|
|
|
|
if (max_size < this_size) {
|
|
|
|
max_size = this_size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cx.tag_sizes.insert(t, max_size);
|
|
|
|
ret max_size;
|
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn dynamic_size_of(@block_ctxt cx, ty.t t) -> result {
|
|
|
|
fn align_elements(@block_ctxt cx, vec[ty.t] elts) -> result {
|
2011-03-01 16:01:33 -08:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
auto off = C_int(0);
|
|
|
|
auto max_align = C_int(1);
|
|
|
|
auto bcx = cx;
|
2011-04-22 12:27:28 -07:00
|
|
|
for (ty.t e in elts) {
|
2011-03-01 16:01:33 -08:00
|
|
|
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);
|
|
|
|
off = cx.build.Add(aligned_off, elt_size.val);
|
|
|
|
max_align = umax(bcx, max_align, elt_align.val);
|
|
|
|
}
|
|
|
|
off = align_to(bcx, off, max_align);
|
|
|
|
ret res(bcx, off);
|
|
|
|
}
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-01-18 15:38:35 -08:00
|
|
|
case (ty.ty_param(?p)) {
|
|
|
|
auto szptr = field_of_tydesc(cx, t, abi.tydesc_field_size);
|
2011-01-31 15:03:05 -08:00
|
|
|
ret res(szptr.bcx, szptr.bcx.build.Load(szptr.val));
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
|
|
|
case (ty.ty_tup(?elts)) {
|
2011-04-22 12:27:28 -07:00
|
|
|
let vec[ty.t] tys = vec();
|
2011-03-17 17:39:47 -07:00
|
|
|
for (ty.mt mt in elts) {
|
|
|
|
tys += vec(mt.ty);
|
|
|
|
}
|
|
|
|
ret align_elements(cx, tys);
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
|
|
|
case (ty.ty_rec(?flds)) {
|
2011-04-22 12:27:28 -07:00
|
|
|
let vec[ty.t] tys = vec();
|
2011-01-18 15:38:35 -08:00
|
|
|
for (ty.field f in flds) {
|
2011-03-17 17:39:47 -07:00
|
|
|
tys += vec(f.mt.ty);
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
2011-03-01 16:01:33 -08:00
|
|
|
ret align_elements(cx, tys);
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
2011-03-01 16:37:17 -08:00
|
|
|
case (ty.ty_tag(?tid, ?tps)) {
|
|
|
|
auto bcx = cx;
|
|
|
|
|
|
|
|
// Compute max(variant sizes).
|
2011-03-28 18:04:52 -07:00
|
|
|
let ValueRef max_size = alloca(bcx, T_int());
|
2011-03-01 16:37:17 -08:00
|
|
|
bcx.build.Store(C_int(0), max_size);
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
auto variants = tag_variants(bcx.fcx.lcx.ccx, tid);
|
2011-04-01 11:36:52 -07:00
|
|
|
for (variant_info variant in variants) {
|
|
|
|
// Perform type substitution on the raw argument types.
|
2011-04-22 12:27:28 -07:00
|
|
|
let vec[ty.t] raw_tys = variant.args;
|
|
|
|
let vec[ty.t] tys = vec();
|
|
|
|
for (ty.t raw_ty in raw_tys) {
|
2011-04-20 18:52:04 -07:00
|
|
|
auto t = ty.bind_params_in_type(cx.fcx.lcx.ccx.tystore,
|
|
|
|
raw_ty);
|
|
|
|
t = ty.substitute_type_params(cx.fcx.lcx.ccx.tystore, tps,
|
|
|
|
t);
|
2011-03-09 16:07:55 -08:00
|
|
|
tys += vec(t);
|
|
|
|
}
|
|
|
|
|
2011-03-01 16:37:17 -08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2011-03-01 16:49:05 -08:00
|
|
|
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);
|
2011-03-01 16:37:17 -08:00
|
|
|
}
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn dynamic_align_of(@block_ctxt cx, ty.t t) -> result {
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-01-18 15:38:35 -08:00
|
|
|
case (ty.ty_param(?p)) {
|
|
|
|
auto aptr = field_of_tydesc(cx, t, abi.tydesc_field_align);
|
2011-01-31 15:03:05 -08:00
|
|
|
ret res(aptr.bcx, aptr.bcx.build.Load(aptr.val));
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
|
|
|
case (ty.ty_tup(?elts)) {
|
|
|
|
auto a = C_int(1);
|
2011-01-31 15:03:05 -08:00
|
|
|
auto bcx = cx;
|
2011-03-17 17:39:47 -07:00
|
|
|
for (ty.mt e in elts) {
|
|
|
|
auto align = align_of(bcx, e.ty);
|
2011-01-31 15:03:05 -08:00
|
|
|
bcx = align.bcx;
|
|
|
|
a = umax(bcx, a, align.val);
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
2011-01-31 15:03:05 -08:00
|
|
|
ret res(bcx, a);
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
|
|
|
case (ty.ty_rec(?flds)) {
|
|
|
|
auto a = C_int(1);
|
2011-01-31 15:03:05 -08:00
|
|
|
auto bcx = cx;
|
2011-01-18 15:38:35 -08:00
|
|
|
for (ty.field f in flds) {
|
2011-03-17 17:39:47 -07:00
|
|
|
auto align = align_of(bcx, f.mt.ty);
|
2011-01-31 15:03:05 -08:00
|
|
|
bcx = align.bcx;
|
|
|
|
a = umax(bcx, a, align.val);
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
2011-01-31 15:03:05 -08:00
|
|
|
ret res(bcx, a);
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
2011-03-07 18:03:33 -08:00
|
|
|
case (ty.ty_tag(_, _)) {
|
|
|
|
ret res(cx, C_int(1)); // FIXME: stub
|
|
|
|
}
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-19 16:29:14 -08:00
|
|
|
// Replacement for the LLVM 'GEP' instruction when field-indexing into a
|
2011-03-04 15:08:33 -08:00
|
|
|
// tuple-like structure (tup, rec) with a static index. This one is driven off
|
|
|
|
// ty.struct and knows what to do when it runs into a ty_param stuck in the
|
|
|
|
// middle of the thing it's GEP'ing into. Much like size_of and align_of,
|
|
|
|
// above.
|
2011-01-19 16:29:14 -08:00
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn GEP_tup_like(@block_ctxt cx, ty.t t,
|
2011-01-31 15:03:05 -08:00
|
|
|
ValueRef base, vec[int] ixs) -> result {
|
2011-01-19 16:29:14 -08:00
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
check (ty.type_is_tup_like(cx.fcx.lcx.ccx.tystore, t));
|
2011-01-19 16:29:14 -08:00
|
|
|
|
|
|
|
// It might be a static-known type. Handle this.
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
if (! ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-01-19 16:29:14 -08:00
|
|
|
let vec[ValueRef] v = vec();
|
|
|
|
for (int i in ixs) {
|
2011-03-16 14:58:02 -07:00
|
|
|
v += vec(C_int(i));
|
2011-01-19 16:29:14 -08:00
|
|
|
}
|
2011-01-31 15:03:05 -08:00
|
|
|
ret res(cx, cx.build.GEP(base, v));
|
2011-01-19 16:29:14 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
fn split_type(@crate_ctxt ccx, ty.t t, vec[int] ixs, uint n)
|
2011-04-22 12:27:28 -07:00
|
|
|
-> rec(vec[ty.t] prefix, ty.t target) {
|
2011-01-19 16:29:14 -08:00
|
|
|
|
|
|
|
let uint len = _vec.len[int](ixs);
|
|
|
|
|
|
|
|
// We don't support 0-index or 1-index GEPs. The former is nonsense
|
|
|
|
// and the latter would only be meaningful if we supported non-0
|
|
|
|
// values for the 0th index (we don't).
|
|
|
|
|
|
|
|
check (len > 1u);
|
|
|
|
|
|
|
|
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.
|
|
|
|
check (ixs.(n) == 0);
|
2011-04-22 17:00:46 -07:00
|
|
|
ret split_type(ccx, t, ixs, n+1u);
|
2011-01-19 16:29:14 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
check (n < len);
|
|
|
|
|
|
|
|
let int ix = ixs.(n);
|
2011-04-22 12:27:28 -07:00
|
|
|
let vec[ty.t] prefix = vec();
|
2011-01-19 16:29:14 -08:00
|
|
|
let int i = 0;
|
|
|
|
while (i < ix) {
|
2011-04-22 17:00:46 -07:00
|
|
|
_vec.push[ty.t](prefix,
|
|
|
|
ty.get_element_type(ccx.tystore, t, i as uint));
|
2011-03-16 14:58:02 -07:00
|
|
|
i += 1 ;
|
2011-01-19 16:29:14 -08:00
|
|
|
}
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
auto selected = ty.get_element_type(ccx.tystore, t, i as uint);
|
2011-01-19 16:29:14 -08:00
|
|
|
|
|
|
|
if (n == len-1u) {
|
|
|
|
// We are at the innermost index.
|
|
|
|
ret rec(prefix=prefix, target=selected);
|
|
|
|
|
|
|
|
} 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.
|
2011-04-22 17:00:46 -07:00
|
|
|
auto inner = split_type(ccx, selected, ixs, n+1u);
|
2011-01-19 16:29:14 -08:00
|
|
|
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.
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
auto s = split_type(cx.fcx.lcx.ccx, t, ixs, 0u);
|
2011-04-20 18:52:04 -07:00
|
|
|
auto prefix_ty = ty.mk_imm_tup(cx.fcx.lcx.ccx.tystore, s.prefix);
|
2011-01-31 15:03:05 -08:00
|
|
|
auto bcx = cx;
|
|
|
|
auto sz = size_of(bcx, prefix_ty);
|
|
|
|
bcx = sz.bcx;
|
|
|
|
auto raw = bcx.build.PointerCast(base, T_ptr(T_i8()));
|
|
|
|
auto bumped = bcx.build.GEP(raw, vec(sz.val));
|
2011-03-03 14:02:29 -08:00
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tystore, s.target)) {
|
2011-03-03 14:02:29 -08:00
|
|
|
ret res(bcx, bumped);
|
2011-01-19 16:29:14 -08:00
|
|
|
}
|
2011-03-03 14:02:29 -08:00
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
auto typ = T_ptr(type_of(bcx.fcx.lcx.ccx, s.target));
|
2011-03-03 14:02:29 -08:00
|
|
|
ret res(bcx, bcx.build.PointerCast(bumped, typ));
|
2011-01-19 16:29:14 -08:00
|
|
|
}
|
|
|
|
|
2011-03-04 15:08:33 -08:00
|
|
|
// 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.
|
2011-03-09 17:48:07 -08:00
|
|
|
fn GEP_tag(@block_ctxt cx,
|
|
|
|
ValueRef llblobptr,
|
|
|
|
&ast.def_id tag_id,
|
|
|
|
&ast.def_id variant_id,
|
2011-04-22 12:27:28 -07:00
|
|
|
vec[ty.t] ty_substs,
|
2011-03-09 17:48:07 -08:00
|
|
|
int ix)
|
2011-04-01 16:04:22 -07:00
|
|
|
-> result {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto variant = tag_variant_with_id(cx.fcx.lcx.ccx, tag_id, variant_id);
|
2011-03-09 17:48:07 -08:00
|
|
|
|
2011-03-04 15:08:33 -08:00
|
|
|
// Synthesize a tuple type so that GEP_tup_like() can work its magic.
|
|
|
|
// Separately, store the type of the element we're interested in.
|
2011-04-01 11:36:52 -07:00
|
|
|
auto arg_tys = variant.args;
|
2011-04-20 18:52:04 -07:00
|
|
|
auto elem_ty = ty.mk_nil(cx.fcx.lcx.ccx.tystore); // typestate infelicity
|
2011-03-04 15:08:33 -08:00
|
|
|
auto i = 0;
|
2011-04-22 12:27:28 -07:00
|
|
|
let vec[ty.t] true_arg_tys = vec();
|
|
|
|
for (ty.t aty in arg_tys) {
|
2011-04-20 18:52:04 -07:00
|
|
|
auto arg_ty = ty.bind_params_in_type(cx.fcx.lcx.ccx.tystore, aty);
|
|
|
|
arg_ty = ty.substitute_type_params(cx.fcx.lcx.ccx.tystore, ty_substs,
|
|
|
|
arg_ty);
|
2011-03-09 17:48:07 -08:00
|
|
|
true_arg_tys += vec(arg_ty);
|
2011-03-04 15:08:33 -08:00
|
|
|
if (i == ix) {
|
2011-03-09 17:48:07 -08:00
|
|
|
elem_ty = arg_ty;
|
2011-03-04 15:08:33 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
i += 1;
|
|
|
|
}
|
2011-03-17 17:39:47 -07:00
|
|
|
|
2011-04-20 18:52:04 -07:00
|
|
|
auto tup_ty = ty.mk_imm_tup(cx.fcx.lcx.ccx.tystore, true_arg_tys);
|
2011-03-04 15:08:33 -08:00
|
|
|
|
|
|
|
// Cast the blob pointer to the appropriate type, if we need to (i.e. if
|
|
|
|
// the blob pointer isn't dynamically sized).
|
|
|
|
let ValueRef llunionptr;
|
2011-04-22 17:00:46 -07:00
|
|
|
if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tystore, tup_ty)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llty = type_of(cx.fcx.lcx.ccx, tup_ty);
|
2011-03-04 15:08:33 -08:00
|
|
|
llunionptr = cx.build.TruncOrBitCast(llblobptr, T_ptr(llty));
|
|
|
|
} else {
|
|
|
|
llunionptr = llblobptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do the GEP_tup_like().
|
|
|
|
auto rslt = GEP_tup_like(cx, tup_ty, llunionptr, vec(0, ix));
|
|
|
|
|
|
|
|
// Cast the result to the appropriate type, if necessary.
|
|
|
|
auto val;
|
2011-04-22 17:00:46 -07:00
|
|
|
if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tystore, elem_ty)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llelemty = type_of(rslt.bcx.fcx.lcx.ccx, elem_ty);
|
2011-03-04 15:08:33 -08:00
|
|
|
val = rslt.bcx.build.PointerCast(rslt.val, T_ptr(llelemty));
|
|
|
|
} else {
|
|
|
|
val = rslt.val;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret res(rslt.bcx, val);
|
|
|
|
}
|
|
|
|
|
2011-01-19 16:29:14 -08:00
|
|
|
|
2011-03-02 17:24:22 -08:00
|
|
|
fn trans_raw_malloc(@block_ctxt cx, TypeRef llptr_ty, ValueRef llsize)
|
2011-04-01 16:04:22 -07:00
|
|
|
-> result {
|
2010-12-02 17:43:05 -08:00
|
|
|
// FIXME: need a table to collect tydesc globals.
|
|
|
|
auto tydesc = C_int(0);
|
2011-03-02 17:24:22 -08:00
|
|
|
auto rslt = trans_upcall(cx, "upcall_malloc", vec(llsize, tydesc));
|
|
|
|
rslt = res(rslt.bcx, vi2p(cx, rslt.val, llptr_ty));
|
|
|
|
ret rslt;
|
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn trans_malloc_boxed(@block_ctxt cx, ty.t t) -> result {
|
2011-03-07 14:05:16 -08:00
|
|
|
// Synthesize a fake box type structurally so we have something
|
|
|
|
// to measure the size of.
|
2011-04-20 18:52:04 -07:00
|
|
|
auto boxed_body = ty.mk_imm_tup(cx.fcx.lcx.ccx.tystore,
|
|
|
|
vec(ty.mk_int(cx.fcx.lcx.ccx.tystore),
|
|
|
|
t));
|
|
|
|
auto box_ptr = ty.mk_imm_box(cx.fcx.lcx.ccx.tystore, t);
|
2011-03-07 14:05:16 -08:00
|
|
|
auto sz = size_of(cx, boxed_body);
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llty = type_of(cx.fcx.lcx.ccx, box_ptr);
|
2011-03-07 14:05:16 -08:00
|
|
|
ret trans_raw_malloc(sz.bcx, llty, sz.val);
|
2010-12-02 17:43:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-20 10:23:37 -08:00
|
|
|
// 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.
|
2011-04-22 12:27:28 -07:00
|
|
|
fn field_of_tydesc(@block_ctxt cx, ty.t t, int field) -> result {
|
2010-12-21 12:13:51 -08:00
|
|
|
auto tydesc = get_tydesc(cx, t);
|
2011-01-31 15:03:05 -08:00
|
|
|
ret res(tydesc.bcx,
|
|
|
|
tydesc.bcx.build.GEP(tydesc.val, vec(C_int(0), C_int(field))));
|
2010-12-20 10:23:37 -08:00
|
|
|
}
|
2010-12-10 15:02:23 -08:00
|
|
|
|
2011-01-27 17:07:52 -08:00
|
|
|
// Given a type containing ty params, build a vector containing a ValueRef for
|
2011-04-12 15:09:50 -07:00
|
|
|
// 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
|
2011-01-27 17:07:52 -08:00
|
|
|
// constructing derived tydescs.
|
2011-04-22 12:27:28 -07:00
|
|
|
fn linearize_ty_params(@block_ctxt cx, ty.t t) ->
|
2011-04-12 15:09:50 -07:00
|
|
|
tup(vec[uint], vec[ValueRef]) {
|
2011-01-27 17:07:52 -08:00
|
|
|
let vec[ValueRef] param_vals = vec();
|
2011-04-12 15:09:50 -07:00
|
|
|
let vec[uint] param_defs = vec();
|
2011-01-27 17:07:52 -08:00
|
|
|
type rr = rec(@block_ctxt cx,
|
2011-01-28 15:45:13 -08:00
|
|
|
mutable vec[ValueRef] vals,
|
2011-04-12 15:09:50 -07:00
|
|
|
mutable vec[uint] defs);
|
2011-01-27 17:07:52 -08:00
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn linearizer(@rr r, ty.t t) {
|
2011-04-22 17:00:46 -07:00
|
|
|
alt(ty.struct(r.cx.fcx.lcx.ccx.tystore, t)) {
|
2011-04-15 12:23:00 -07:00
|
|
|
case (ty.ty_param(?pid)) {
|
|
|
|
let bool seen = false;
|
|
|
|
for (uint d in r.defs) {
|
|
|
|
if (d == pid) {
|
|
|
|
seen = true;
|
2011-01-27 17:07:52 -08:00
|
|
|
}
|
|
|
|
}
|
2011-04-15 12:23:00 -07:00
|
|
|
if (!seen) {
|
2011-04-15 17:45:37 -07:00
|
|
|
r.vals += vec(r.cx.fcx.lltydescs.(pid));
|
2011-04-15 12:23:00 -07:00
|
|
|
r.defs += vec(pid);
|
|
|
|
}
|
2011-01-27 17:07:52 -08:00
|
|
|
}
|
2011-04-15 12:23:00 -07:00
|
|
|
case (_) { }
|
2011-01-27 17:07:52 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
auto x = @rec(cx = cx,
|
|
|
|
mutable vals = param_vals,
|
|
|
|
mutable defs = param_defs);
|
|
|
|
|
2011-04-15 12:23:00 -07:00
|
|
|
auto f = bind linearizer(x, _);
|
2011-04-22 17:00:46 -07:00
|
|
|
ty.walk_ty(cx.fcx.lcx.ccx.tystore, f, t);
|
2011-01-27 17:07:52 -08:00
|
|
|
|
|
|
|
ret tup(x.defs, x.vals);
|
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn get_tydesc(&@block_ctxt cx, ty.t t) -> result {
|
2010-12-20 15:23:24 -08:00
|
|
|
// Is the supplied type a type param? If so, return the passed-in tydesc.
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.type_param(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-04-15 17:45:37 -07:00
|
|
|
case (some[uint](?id)) { ret res(cx, cx.fcx.lltydescs.(id)); }
|
2011-04-12 15:09:50 -07:00
|
|
|
case (none[uint]) { /* fall through */ }
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
2010-12-20 15:23:24 -08:00
|
|
|
|
|
|
|
// Does it contain a type param? If so, generate a derived tydesc.
|
2011-04-22 17:00:46 -07:00
|
|
|
let uint n_params = ty.count_ty_params(cx.fcx.lcx.ccx.tystore, t);
|
2011-01-28 15:28:20 -08:00
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.count_ty_params(cx.fcx.lcx.ccx.tystore, t) > 0u) {
|
2011-01-27 17:07:52 -08:00
|
|
|
auto tys = linearize_ty_params(cx, t);
|
2011-01-28 15:28:20 -08:00
|
|
|
|
2011-04-12 15:09:50 -07:00
|
|
|
check (n_params == _vec.len[uint](tys._0));
|
2011-01-31 15:03:05 -08:00
|
|
|
check (n_params == _vec.len[ValueRef](tys._1));
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
if (!cx.fcx.lcx.ccx.tydescs.contains_key(t)) {
|
|
|
|
declare_tydesc(cx.fcx.lcx, t);
|
|
|
|
define_tydesc(cx.fcx.lcx, t, tys._0);
|
2011-01-28 15:28:20 -08:00
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
auto root = cx.fcx.lcx.ccx.tydescs.get(t).tydesc;
|
2011-01-28 15:45:13 -08:00
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
auto tydescs = alloca(cx, T_array(T_ptr(T_tydesc(cx.fcx.lcx.ccx.tn)),
|
2011-03-28 18:04:52 -07:00
|
|
|
1u /* for root*/ + n_params));
|
2011-02-01 18:02:57 -08:00
|
|
|
|
2011-01-31 15:03:05 -08:00
|
|
|
auto i = 0;
|
2011-02-01 18:02:57 -08:00
|
|
|
auto tdp = cx.build.GEP(tydescs, vec(C_int(0), C_int(i)));
|
|
|
|
cx.build.Store(root, tdp);
|
|
|
|
i += 1;
|
2011-01-31 15:03:05 -08:00
|
|
|
for (ValueRef td in tys._1) {
|
|
|
|
auto tdp = cx.build.GEP(tydescs, vec(C_int(0), C_int(i)));
|
2011-02-01 18:02:57 -08:00
|
|
|
cx.build.Store(td, tdp);
|
2011-02-01 14:57:03 -08:00
|
|
|
i += 1;
|
2011-01-31 15:03:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
auto bcx = cx;
|
|
|
|
auto sz = size_of(bcx, t);
|
|
|
|
bcx = sz.bcx;
|
|
|
|
auto align = align_of(bcx, t);
|
|
|
|
bcx = align.bcx;
|
|
|
|
|
|
|
|
auto v = trans_upcall(bcx, "upcall_get_type_desc",
|
2011-04-17 14:24:45 +02:00
|
|
|
vec(p2i(bcx.fcx.lcx.ccx.crate_ptr),
|
2011-01-31 15:03:05 -08:00
|
|
|
sz.val,
|
|
|
|
align.val,
|
2011-01-31 18:06:35 -08:00
|
|
|
C_int((1u + n_params) as int),
|
2011-03-02 16:42:09 -08:00
|
|
|
vp2i(bcx, tydescs)));
|
2011-01-31 15:03:05 -08:00
|
|
|
|
2011-03-02 16:42:09 -08:00
|
|
|
ret res(v.bcx, vi2p(v.bcx, v.val,
|
2011-04-17 14:24:45 +02:00
|
|
|
T_ptr(T_tydesc(cx.fcx.lcx.ccx.tn))));
|
2010-12-20 15:23:24 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, generate a tydesc if necessary, and return it.
|
2011-04-17 14:24:45 +02:00
|
|
|
if (!cx.fcx.lcx.ccx.tydescs.contains_key(t)) {
|
2011-04-12 15:09:50 -07:00
|
|
|
let vec[uint] tps = vec();
|
2011-04-17 14:24:45 +02:00
|
|
|
declare_tydesc(cx.fcx.lcx, t);
|
|
|
|
define_tydesc(cx.fcx.lcx, t, tps);
|
2010-12-20 15:23:24 -08:00
|
|
|
}
|
2011-04-17 14:24:45 +02:00
|
|
|
ret res(cx, cx.fcx.lcx.ccx.tydescs.get(t).tydesc);
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
|
|
|
|
2011-03-04 17:22:43 -08:00
|
|
|
// Generates the declaration for (but doesn't fill in) a type descriptor. This
|
|
|
|
// needs to be separate from make_tydesc() below, because sometimes type glue
|
|
|
|
// functions needs to refer to their own type descriptors.
|
2011-04-22 12:27:28 -07:00
|
|
|
fn declare_tydesc(@local_ctxt cx, ty.t t) {
|
2011-04-18 10:56:52 -07:00
|
|
|
auto take_glue = declare_generic_glue(cx, t, T_glue_fn(cx.ccx.tn),
|
|
|
|
"take");
|
|
|
|
auto drop_glue = declare_generic_glue(cx, t, T_glue_fn(cx.ccx.tn),
|
|
|
|
"drop");
|
|
|
|
auto cmp_glue = declare_generic_glue(cx, t, T_cmp_glue_fn(cx.ccx.tn),
|
|
|
|
"cmp");
|
2011-04-17 14:24:45 +02:00
|
|
|
auto ccx = cx.ccx;
|
2010-12-20 10:23:37 -08:00
|
|
|
|
2011-03-02 16:23:14 -08:00
|
|
|
auto llsize;
|
|
|
|
auto llalign;
|
2011-04-22 17:00:46 -07:00
|
|
|
if (!ty.type_has_dynamic_size(ccx.tystore, t)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llty = type_of(ccx, t);
|
2011-03-02 16:23:14 -08:00
|
|
|
llsize = llsize_of(llty);
|
|
|
|
llalign = llalign_of(llty);
|
|
|
|
} else {
|
|
|
|
// These will be overwritten as the derived tydesc is generated, so
|
|
|
|
// we create placeholder values.
|
|
|
|
llsize = C_int(0);
|
|
|
|
llalign = C_int(0);
|
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
auto glue_fn_ty = T_ptr(T_glue_fn(ccx.tn));
|
2011-04-12 12:06:20 -07:00
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
auto name = sanitize(ccx.names.next("tydesc_" +
|
|
|
|
ty.ty_to_str(cx.ccx.tystore, t)));
|
2011-04-17 14:24:45 +02:00
|
|
|
auto gvar = llvm.LLVMAddGlobal(ccx.llmod, T_tydesc(ccx.tn),
|
2011-02-17 18:16:51 -08:00
|
|
|
_str.buf(name));
|
2011-04-17 14:24:45 +02:00
|
|
|
auto tydesc = C_struct(vec(C_null(T_ptr(T_ptr(T_tydesc(ccx.tn)))),
|
2011-03-02 16:23:14 -08:00
|
|
|
llsize,
|
|
|
|
llalign,
|
2011-04-09 00:54:46 +00:00
|
|
|
take_glue, // take_glue
|
|
|
|
drop_glue, // drop_glue
|
|
|
|
C_null(glue_fn_ty), // free_glue
|
|
|
|
C_null(glue_fn_ty), // sever_glue
|
|
|
|
C_null(glue_fn_ty), // mark_glue
|
|
|
|
C_null(glue_fn_ty), // obj_drop_glue
|
2011-04-18 10:56:52 -07:00
|
|
|
C_null(glue_fn_ty), // is_stateful
|
|
|
|
cmp_glue)); // cmp_glue
|
2010-12-20 10:23:37 -08:00
|
|
|
|
|
|
|
llvm.LLVMSetInitializer(gvar, tydesc);
|
|
|
|
llvm.LLVMSetGlobalConstant(gvar, True);
|
2011-04-01 15:01:46 -07:00
|
|
|
llvm.LLVMSetLinkage(gvar, lib.llvm.LLVMInternalLinkage
|
2011-01-05 15:31:35 -08:00
|
|
|
as llvm.Linkage);
|
2011-03-04 17:22:43 -08:00
|
|
|
|
|
|
|
auto info = rec(
|
2011-04-01 16:04:22 -07:00
|
|
|
tydesc=gvar,
|
|
|
|
take_glue=take_glue,
|
2011-04-18 10:56:52 -07:00
|
|
|
drop_glue=drop_glue,
|
|
|
|
cmp_glue=cmp_glue
|
2011-04-01 16:04:22 -07:00
|
|
|
);
|
2011-03-04 17:22:43 -08:00
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
ccx.tydescs.insert(t, @info);
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
|
|
|
|
2011-04-18 10:56:52 -07:00
|
|
|
tag make_generic_glue_helper_fn {
|
2011-04-22 12:27:28 -07:00
|
|
|
mgghf_single(fn(@block_ctxt cx, ValueRef v, ty.t t));
|
2011-04-18 12:44:50 -07:00
|
|
|
mgghf_cmp;
|
2011-04-18 10:56:52 -07:00
|
|
|
}
|
|
|
|
|
2011-03-04 17:22:43 -08:00
|
|
|
// declare_tydesc() above must have been called first.
|
2011-04-22 12:27:28 -07:00
|
|
|
fn define_tydesc(@local_ctxt cx, ty.t t, vec[uint] ty_params) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto info = cx.ccx.tydescs.get(t);
|
2011-03-04 17:22:43 -08:00
|
|
|
auto gvar = info.tydesc;
|
|
|
|
|
|
|
|
auto tg = make_take_glue;
|
2011-04-18 10:56:52 -07:00
|
|
|
make_generic_glue(cx, t, info.take_glue, mgghf_single(tg), ty_params);
|
2011-03-04 17:22:43 -08:00
|
|
|
auto dg = make_drop_glue;
|
2011-04-18 10:56:52 -07:00
|
|
|
make_generic_glue(cx, t, info.drop_glue, mgghf_single(dg), ty_params);
|
2011-04-18 12:44:50 -07:00
|
|
|
make_generic_glue(cx, t, info.cmp_glue, mgghf_cmp, ty_params);
|
2011-03-04 17:22:43 -08:00
|
|
|
}
|
|
|
|
|
2011-04-18 10:56:52 -07:00
|
|
|
fn declare_generic_glue(@local_ctxt cx,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t t,
|
2011-04-18 10:56:52 -07:00
|
|
|
TypeRef llfnty,
|
|
|
|
str name) -> ValueRef {
|
2011-03-26 17:36:47 -07:00
|
|
|
auto gcx = @rec(path=vec("glue", name) with *cx);
|
2011-04-20 17:23:45 +02:00
|
|
|
auto fn_nm = mangle_name_by_type(cx.ccx, cx.path + vec("glue", name), t);
|
|
|
|
fn_nm = sanitize(fn_nm);
|
|
|
|
auto llfn = decl_internal_fastcall_fn(cx.ccx.llmod, fn_nm, llfnty);
|
2011-03-20 15:05:13 -07:00
|
|
|
ret llfn;
|
2011-03-04 17:22:43 -08:00
|
|
|
}
|
2010-12-10 15:02:23 -08:00
|
|
|
|
2011-04-18 10:56:52 -07:00
|
|
|
fn make_generic_glue(@local_ctxt cx,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t t,
|
2011-04-18 10:56:52 -07:00
|
|
|
ValueRef llfn,
|
|
|
|
make_generic_glue_helper_fn helper,
|
|
|
|
vec[uint] ty_params) -> ValueRef {
|
2011-03-04 14:53:52 -05:00
|
|
|
auto fcx = new_fn_ctxt(cx, llfn);
|
2010-12-10 15:02:23 -08:00
|
|
|
auto bcx = new_top_block_ctxt(fcx);
|
2011-03-28 18:04:52 -07:00
|
|
|
auto lltop = bcx.llbb;
|
2010-12-10 15:02:23 -08:00
|
|
|
|
2011-04-19 11:25:40 -07:00
|
|
|
// 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.
|
2011-04-12 12:06:20 -07:00
|
|
|
|
2011-04-19 11:25:40 -07:00
|
|
|
auto llty;
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_has_dynamic_size(cx.ccx.tystore, t)) {
|
2011-04-19 11:25:40 -07:00
|
|
|
llty = T_ptr(T_i8());
|
|
|
|
} else {
|
|
|
|
llty = T_ptr(type_of(cx.ccx, t));
|
|
|
|
}
|
2010-12-10 15:02:23 -08:00
|
|
|
|
2011-04-19 11:25:40 -07:00
|
|
|
auto ty_param_count = _vec.len[uint](ty_params);
|
2011-04-12 15:09:50 -07:00
|
|
|
|
2011-04-19 11:25:40 -07:00
|
|
|
auto lltyparams = llvm.LLVMGetParam(llfn, 3u);
|
2011-04-15 17:45:37 -07:00
|
|
|
|
2011-04-19 11:25:40 -07:00
|
|
|
auto lltydescs = _vec.empty_mut[ValueRef]();
|
|
|
|
auto p = 0u;
|
|
|
|
while (p < ty_param_count) {
|
|
|
|
auto llparam = bcx.build.GEP(lltyparams, vec(C_int(p as int)));
|
|
|
|
llparam = bcx.build.Load(llparam);
|
|
|
|
_vec.grow_set[ValueRef](lltydescs, ty_params.(p), 0 as ValueRef,
|
|
|
|
llparam);
|
|
|
|
p += 1u;
|
|
|
|
}
|
|
|
|
bcx.fcx.lltydescs = _vec.freeze[ValueRef](lltydescs);
|
2011-01-28 15:28:20 -08:00
|
|
|
|
2011-04-19 11:25:40 -07:00
|
|
|
auto llrawptr0 = llvm.LLVMGetParam(llfn, 4u);
|
|
|
|
auto llval0 = bcx.build.BitCast(llrawptr0, llty);
|
2010-12-20 11:40:33 -08:00
|
|
|
|
2011-04-19 11:25:40 -07:00
|
|
|
alt (helper) {
|
|
|
|
case (mgghf_single(?single_fn)) {
|
|
|
|
single_fn(bcx, llval0, t);
|
|
|
|
}
|
|
|
|
case (mgghf_cmp) {
|
|
|
|
auto llrawptr1 = llvm.LLVMGetParam(llfn, 5u);
|
2011-04-19 15:22:57 -07:00
|
|
|
auto llval1 = bcx.build.BitCast(llrawptr1, llty);
|
2011-04-18 12:44:50 -07:00
|
|
|
|
2011-04-19 11:25:40 -07:00
|
|
|
auto llcmpval = llvm.LLVMGetParam(llfn, 6u);
|
2011-04-18 12:44:50 -07:00
|
|
|
|
2011-04-19 11:25:40 -07:00
|
|
|
make_cmp_glue(bcx, llval0, llval1, t, llcmpval);
|
2011-04-18 10:56:52 -07:00
|
|
|
}
|
2010-12-17 18:20:10 -08:00
|
|
|
}
|
2010-12-10 15:02:23 -08:00
|
|
|
|
2011-03-28 18:04:52 -07:00
|
|
|
// Tie up the llallocas -> lltop edge.
|
|
|
|
new_builder(fcx.llallocas).Br(lltop);
|
|
|
|
|
2010-12-10 15:02:23 -08:00
|
|
|
ret llfn;
|
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn make_take_glue(@block_ctxt cx, ValueRef v, ty.t t) {
|
2011-04-12 12:06:20 -07:00
|
|
|
// NB: v is an *alias* of type t here, not a direct value.
|
2011-04-19 11:17:01 -07:00
|
|
|
auto bcx;
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_is_boxed(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-04-19 11:17:01 -07:00
|
|
|
bcx = incr_refcnt_of_boxed(cx, cx.build.Load(v)).bcx;
|
2010-12-10 16:13:52 -08:00
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
} else if (ty.type_is_structural(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-04-19 11:17:01 -07:00
|
|
|
bcx = iter_structural_ty(cx, v, t,
|
|
|
|
bind take_ty(_, _, _)).bcx;
|
|
|
|
} else {
|
|
|
|
bcx = cx;
|
2010-12-10 16:13:52 -08:00
|
|
|
}
|
2011-04-19 11:17:01 -07:00
|
|
|
bcx.build.RetVoid();
|
2010-12-10 16:13:52 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn incr_refcnt_of_boxed(@block_ctxt cx, ValueRef box_ptr) -> result {
|
|
|
|
auto rc_ptr = cx.build.GEP(box_ptr, vec(C_int(0),
|
|
|
|
C_int(abi.box_rc_field_refcnt)));
|
|
|
|
auto rc = cx.build.Load(rc_ptr);
|
|
|
|
|
|
|
|
auto rc_adj_cx = new_sub_block_ctxt(cx, "rc++");
|
|
|
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
|
|
|
|
|
|
|
auto const_test = cx.build.ICmp(lib.llvm.LLVMIntEQ,
|
|
|
|
C_int(abi.const_refcount as int), rc);
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn make_drop_glue(@block_ctxt cx, ValueRef v0, ty.t t) {
|
2011-04-12 12:06:20 -07:00
|
|
|
// NB: v0 is an *alias* of type t here, not a direct value.
|
2011-04-19 11:17:01 -07:00
|
|
|
auto rslt;
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.fcx.lcx.ccx.tystore, t)) {
|
2010-12-21 12:13:51 -08:00
|
|
|
case (ty.ty_str) {
|
2011-04-12 12:06:20 -07:00
|
|
|
auto v = cx.build.Load(v0);
|
2011-04-19 11:17:01 -07:00
|
|
|
rslt = decr_refcnt_and_if_zero
|
2011-01-21 07:50:02 -08:00
|
|
|
(cx, v, bind trans_non_gc_free(_, v),
|
|
|
|
"free string",
|
|
|
|
T_int(), C_int(0));
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
|
|
|
|
2010-12-21 12:13:51 -08:00
|
|
|
case (ty.ty_vec(_)) {
|
2011-01-21 07:50:02 -08:00
|
|
|
fn hit_zero(@block_ctxt cx, ValueRef v,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t t) -> result {
|
2011-01-21 07:50:02 -08:00
|
|
|
auto res = iter_sequence(cx, v, t,
|
|
|
|
bind drop_ty(_,_,_));
|
2010-12-10 15:02:23 -08:00
|
|
|
// FIXME: switch gc/non-gc on layer of the type.
|
|
|
|
ret trans_non_gc_free(res.bcx, v);
|
|
|
|
}
|
2011-04-12 12:06:20 -07:00
|
|
|
auto v = cx.build.Load(v0);
|
2011-04-19 11:17:01 -07:00
|
|
|
rslt = decr_refcnt_and_if_zero(cx, v,
|
|
|
|
bind hit_zero(_, v, t),
|
|
|
|
"free vector",
|
|
|
|
T_int(), C_int(0));
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
|
|
|
|
2011-03-17 17:39:47 -07:00
|
|
|
case (ty.ty_box(?body_mt)) {
|
2011-01-21 07:50:02 -08:00
|
|
|
fn hit_zero(@block_ctxt cx, ValueRef v,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t body_ty) -> result {
|
2010-12-10 15:02:23 -08:00
|
|
|
auto body = cx.build.GEP(v,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.box_rc_field_body)));
|
|
|
|
|
2011-04-12 12:06:20 -07:00
|
|
|
auto body_val = load_if_immediate(cx, body, body_ty);
|
2010-12-10 15:02:23 -08:00
|
|
|
auto res = drop_ty(cx, body_val, body_ty);
|
|
|
|
// FIXME: switch gc/non-gc on layer of the type.
|
|
|
|
ret trans_non_gc_free(res.bcx, v);
|
|
|
|
}
|
2011-04-12 12:06:20 -07:00
|
|
|
auto v = cx.build.Load(v0);
|
2011-04-19 11:17:01 -07:00
|
|
|
rslt = decr_refcnt_and_if_zero(cx, v,
|
|
|
|
bind hit_zero(_, v, body_mt.ty),
|
|
|
|
"free box",
|
|
|
|
T_int(), C_int(0));
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
|
|
|
|
2011-03-16 21:49:15 -04:00
|
|
|
case (ty.ty_port(_)) {
|
|
|
|
fn hit_zero(@block_ctxt cx, ValueRef v) -> result {
|
|
|
|
ret trans_upcall(cx, "upcall_del_port",
|
|
|
|
vec(vp2i(cx, v)));
|
|
|
|
}
|
2011-04-12 12:06:20 -07:00
|
|
|
auto v = cx.build.Load(v0);
|
2011-04-19 11:17:01 -07:00
|
|
|
rslt = decr_refcnt_and_if_zero(cx, v,
|
|
|
|
bind hit_zero(_, v),
|
|
|
|
"free port",
|
|
|
|
T_int(), C_int(0));
|
2011-03-16 21:49:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
case (ty.ty_chan(_)) {
|
|
|
|
fn hit_zero(@block_ctxt cx, ValueRef v) -> result {
|
|
|
|
ret trans_upcall(cx, "upcall_del_chan",
|
|
|
|
vec(vp2i(cx, v)));
|
|
|
|
}
|
2011-04-12 12:06:20 -07:00
|
|
|
auto v = cx.build.Load(v0);
|
2011-04-19 11:17:01 -07:00
|
|
|
rslt = decr_refcnt_and_if_zero(cx, v,
|
|
|
|
bind hit_zero(_, v),
|
|
|
|
"free chan",
|
|
|
|
T_int(), C_int(0));
|
2011-03-16 21:49:15 -04:00
|
|
|
}
|
|
|
|
|
2010-12-31 13:01:45 -08:00
|
|
|
case (ty.ty_obj(_)) {
|
|
|
|
fn hit_zero(@block_ctxt cx, ValueRef v) -> result {
|
|
|
|
|
|
|
|
// Call through the obj's own fields-drop glue first.
|
|
|
|
auto body =
|
|
|
|
cx.build.GEP(v,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.box_rc_field_body)));
|
|
|
|
|
|
|
|
auto tydescptr =
|
|
|
|
cx.build.GEP(body,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.obj_body_elt_tydesc)));
|
2011-01-28 14:34:25 -08:00
|
|
|
|
2011-02-02 15:28:11 -08:00
|
|
|
call_tydesc_glue_full(cx, body, cx.build.Load(tydescptr),
|
2011-04-09 00:54:46 +00:00
|
|
|
abi.tydesc_field_drop_glue);
|
2010-12-31 13:01:45 -08:00
|
|
|
|
|
|
|
// Then free the body.
|
|
|
|
// FIXME: switch gc/non-gc on layer of the type.
|
|
|
|
ret trans_non_gc_free(cx, v);
|
|
|
|
}
|
|
|
|
auto box_cell =
|
2011-04-12 12:06:20 -07:00
|
|
|
cx.build.GEP(v0,
|
2010-12-31 13:01:45 -08:00
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.obj_field_box)));
|
|
|
|
|
|
|
|
auto boxptr = cx.build.Load(box_cell);
|
|
|
|
|
2011-04-19 11:17:01 -07:00
|
|
|
rslt = decr_refcnt_and_if_zero(cx, boxptr,
|
|
|
|
bind hit_zero(_, boxptr),
|
|
|
|
"free obj",
|
|
|
|
T_int(), C_int(0));
|
2010-12-31 13:01:45 -08:00
|
|
|
}
|
|
|
|
|
2011-02-18 17:30:57 -08:00
|
|
|
case (ty.ty_fn(_,_,_)) {
|
2011-01-07 16:26:30 -08:00
|
|
|
fn hit_zero(@block_ctxt cx, ValueRef v) -> result {
|
|
|
|
|
|
|
|
// Call through the closure's own fields-drop glue first.
|
|
|
|
auto body =
|
|
|
|
cx.build.GEP(v,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.box_rc_field_body)));
|
2011-02-02 17:49:15 -08:00
|
|
|
auto bindings =
|
|
|
|
cx.build.GEP(body,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.closure_elt_bindings)));
|
2011-01-07 16:26:30 -08:00
|
|
|
|
|
|
|
auto tydescptr =
|
|
|
|
cx.build.GEP(body,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.closure_elt_tydesc)));
|
2011-01-28 14:34:25 -08:00
|
|
|
|
2011-02-02 17:49:15 -08:00
|
|
|
call_tydesc_glue_full(cx, bindings, cx.build.Load(tydescptr),
|
2011-04-09 00:54:46 +00:00
|
|
|
abi.tydesc_field_drop_glue);
|
2011-01-28 14:34:25 -08:00
|
|
|
|
2011-01-07 16:26:30 -08:00
|
|
|
|
|
|
|
// Then free the body.
|
|
|
|
// FIXME: switch gc/non-gc on layer of the type.
|
|
|
|
ret trans_non_gc_free(cx, v);
|
|
|
|
}
|
|
|
|
auto box_cell =
|
2011-04-12 12:06:20 -07:00
|
|
|
cx.build.GEP(v0,
|
2011-01-07 16:26:30 -08:00
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.fn_field_box)));
|
|
|
|
|
|
|
|
auto boxptr = cx.build.Load(box_cell);
|
|
|
|
|
2011-04-19 11:17:01 -07:00
|
|
|
rslt = decr_refcnt_and_if_zero(cx, boxptr,
|
|
|
|
bind hit_zero(_, boxptr),
|
|
|
|
"free fn",
|
|
|
|
T_int(), C_int(0));
|
2011-01-07 16:26:30 -08:00
|
|
|
}
|
|
|
|
|
2010-12-10 15:02:23 -08:00
|
|
|
case (_) {
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_is_structural(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-04-19 11:17:01 -07:00
|
|
|
rslt = iter_structural_ty(cx, v0, t,
|
|
|
|
bind drop_ty(_, _, _));
|
2010-12-10 15:02:23 -08:00
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
} else if (ty.type_is_scalar(cx.fcx.lcx.ccx.tystore, t) ||
|
|
|
|
ty.type_is_native(cx.fcx.lcx.ccx.tystore, t) ||
|
|
|
|
ty.type_is_nil(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-04-19 11:17:01 -07:00
|
|
|
rslt = res(cx, C_nil());
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-04-19 11:17:01 -07:00
|
|
|
|
|
|
|
rslt.bcx.build.RetVoid();
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
|
|
|
|
2010-10-01 18:25:42 -07:00
|
|
|
fn decr_refcnt_and_if_zero(@block_ctxt cx,
|
|
|
|
ValueRef box_ptr,
|
2010-10-04 15:55:12 -07:00
|
|
|
fn(@block_ctxt cx) -> result inner,
|
2010-11-10 17:46:49 -08:00
|
|
|
str inner_name,
|
2010-10-04 15:55:12 -07:00
|
|
|
TypeRef t_else, ValueRef v_else) -> result {
|
2010-11-10 17:46:49 -08:00
|
|
|
|
2010-12-06 17:46:35 -08:00
|
|
|
auto load_rc_cx = new_sub_block_ctxt(cx, "load rc");
|
2010-11-10 17:46:49 -08:00
|
|
|
auto rc_adj_cx = new_sub_block_ctxt(cx, "rc--");
|
|
|
|
auto inner_cx = new_sub_block_ctxt(cx, inner_name);
|
|
|
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
|
|
|
|
2010-12-06 17:46:35 -08:00
|
|
|
auto null_test = cx.build.IsNull(box_ptr);
|
|
|
|
cx.build.CondBr(null_test, next_cx.llbb, load_rc_cx.llbb);
|
2010-11-09 17:49:20 -08:00
|
|
|
|
2010-12-06 17:46:35 -08:00
|
|
|
|
|
|
|
auto rc_ptr = load_rc_cx.build.GEP(box_ptr,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.box_rc_field_refcnt)));
|
|
|
|
|
|
|
|
auto rc = load_rc_cx.build.Load(rc_ptr);
|
|
|
|
auto const_test =
|
|
|
|
load_rc_cx.build.ICmp(lib.llvm.LLVMIntEQ,
|
|
|
|
C_int(abi.const_refcount as int), rc);
|
|
|
|
load_rc_cx.build.CondBr(const_test, next_cx.llbb, rc_adj_cx.llbb);
|
2010-11-09 17:49:20 -08:00
|
|
|
|
|
|
|
rc = rc_adj_cx.build.Sub(rc, C_int(1));
|
|
|
|
rc_adj_cx.build.Store(rc, rc_ptr);
|
|
|
|
auto zero_test = rc_adj_cx.build.ICmp(lib.llvm.LLVMIntEQ, C_int(0), rc);
|
2010-11-10 17:46:49 -08:00
|
|
|
rc_adj_cx.build.CondBr(zero_test, inner_cx.llbb, next_cx.llbb);
|
|
|
|
|
|
|
|
auto inner_res = inner(inner_cx);
|
|
|
|
inner_res.bcx.build.Br(next_cx.llbb);
|
2010-11-09 17:49:20 -08:00
|
|
|
|
2010-10-04 15:55:12 -07:00
|
|
|
auto phi = next_cx.build.Phi(t_else,
|
2010-12-06 17:46:35 -08:00
|
|
|
vec(v_else, v_else, v_else, inner_res.val),
|
2010-11-09 17:49:20 -08:00
|
|
|
vec(cx.llbb,
|
2010-12-06 17:46:35 -08:00
|
|
|
load_rc_cx.llbb,
|
2010-11-09 17:49:20 -08:00
|
|
|
rc_adj_cx.llbb,
|
2010-11-10 17:46:49 -08:00
|
|
|
inner_res.bcx.llbb));
|
|
|
|
|
2010-10-04 15:55:12 -07:00
|
|
|
ret res(next_cx, phi);
|
2010-10-01 18:25:42 -07:00
|
|
|
}
|
|
|
|
|
2011-04-19 15:22:57 -07:00
|
|
|
// Structural comparison: a rather involved form of glue.
|
|
|
|
|
|
|
|
fn make_cmp_glue(@block_ctxt cx,
|
|
|
|
ValueRef lhs0,
|
|
|
|
ValueRef rhs0,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t t,
|
2011-04-19 15:22:57 -07:00
|
|
|
ValueRef llop) {
|
|
|
|
auto lhs = load_if_immediate(cx, lhs0, t);
|
|
|
|
auto rhs = load_if_immediate(cx, rhs0, t);
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_is_scalar(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-04-19 15:22:57 -07:00
|
|
|
make_scalar_cmp_glue(cx, lhs, rhs, t, llop);
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
} else if (ty.type_is_box(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-04-19 15:22:57 -07:00
|
|
|
lhs = cx.build.GEP(lhs, vec(C_int(0), C_int(abi.box_rc_field_body)));
|
|
|
|
rhs = cx.build.GEP(rhs, vec(C_int(0), C_int(abi.box_rc_field_body)));
|
|
|
|
auto rslt = call_cmp_glue(cx, lhs, rhs, t, llop);
|
|
|
|
|
|
|
|
rslt.bcx.build.Store(rslt.val, cx.fcx.llretptr);
|
|
|
|
rslt.bcx.build.RetVoid();
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
} else if (ty.type_is_structural(cx.fcx.lcx.ccx.tystore, t)
|
|
|
|
|| ty.type_is_sequence(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-04-19 15:22:57 -07:00
|
|
|
|
|
|
|
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
|
|
|
|
* for pairwise element equality. If we have equality, our assumption
|
|
|
|
* 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());
|
|
|
|
llvm.LLVMSetValueName(flag, _str.buf("flag"));
|
|
|
|
|
|
|
|
auto r;
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_is_sequence(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-04-19 15:22:57 -07:00
|
|
|
|
|
|
|
// If we hit == all the way through the minimum-shared-length
|
|
|
|
// section, default to judging the relative sequence lengths.
|
|
|
|
r = compare_integral_values(scx,
|
|
|
|
vec_fill(scx, lhs),
|
|
|
|
vec_fill(scx, rhs),
|
|
|
|
false,
|
|
|
|
llop);
|
|
|
|
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.
|
|
|
|
auto result_if_equal = scx.build.ICmp(lib.llvm.LLVMIntNE, llop,
|
|
|
|
C_i8(abi.cmp_glue_op_lt));
|
|
|
|
scx.build.Store(result_if_equal, flag);
|
|
|
|
r = res(scx, C_nil());
|
|
|
|
}
|
|
|
|
|
|
|
|
fn inner(@block_ctxt last_cx,
|
|
|
|
bool load_inner,
|
|
|
|
ValueRef flag,
|
|
|
|
ValueRef llop,
|
|
|
|
@block_ctxt cx,
|
|
|
|
ValueRef av0,
|
|
|
|
ValueRef bv0,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t t) -> result {
|
2011-04-19 15:22:57 -07:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
if (!ty.type_has_dynamic_size(last_cx.fcx.lcx.ccx.tystore,
|
|
|
|
t)) {
|
2011-04-19 15:22:57 -07:00
|
|
|
auto llelemty = T_ptr(type_of(last_cx.fcx.lcx.ccx, t));
|
|
|
|
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.
|
|
|
|
auto eq_r = call_cmp_glue(cx, av, bv, t,
|
|
|
|
C_i8(abi.cmp_glue_op_eq));
|
|
|
|
eq_r.bcx.build.CondBr(eq_r.val, cnt_cx.llbb, stop_cx.llbb);
|
|
|
|
|
|
|
|
// Second 'op' comparison: find out how this elt-pair decides.
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_is_structural(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-04-19 15:22:57 -07:00
|
|
|
r = iter_structural_ty_full(r.bcx, lhs, rhs, t,
|
|
|
|
bind inner(next, false, flag, llop,
|
|
|
|
_, _, _, _));
|
|
|
|
} else {
|
|
|
|
auto lhs_p0 = vec_p0(r.bcx, lhs);
|
|
|
|
auto rhs_p0 = vec_p0(r.bcx, rhs);
|
|
|
|
auto min_len = umin(r.bcx, vec_fill(r.bcx, lhs),
|
|
|
|
vec_fill(r.bcx, rhs));
|
|
|
|
auto rhs_lim = r.bcx.build.GEP(rhs_p0, vec(min_len));
|
2011-04-20 18:52:04 -07:00
|
|
|
auto elt_ty = ty.sequence_element_type(cx.fcx.lcx.ccx.tystore, t);
|
2011-04-19 15:22:57 -07:00
|
|
|
r = size_of(r.bcx, elt_ty);
|
|
|
|
r = iter_sequence_raw(r.bcx, lhs_p0, rhs_p0, rhs_lim, r.val,
|
|
|
|
bind inner(next, true, flag, llop,
|
|
|
|
_, _, _, elt_ty));
|
|
|
|
}
|
|
|
|
|
|
|
|
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?
|
|
|
|
trans_fail(cx, none[common.span],
|
2011-04-22 17:00:46 -07:00
|
|
|
"attempt to compare values of type " +
|
|
|
|
ty.ty_to_str(cx.fcx.lcx.ccx.tystore, t));
|
2011-04-19 15:22:57 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// A helper function to create scalar comparison glue.
|
2011-04-22 12:27:28 -07:00
|
|
|
fn make_scalar_cmp_glue(@block_ctxt cx, ValueRef lhs, ValueRef rhs, ty.t t,
|
2011-04-19 15:22:57 -07:00
|
|
|
ValueRef llop) {
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_is_fp(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-04-19 15:22:57 -07:00
|
|
|
make_fp_cmp_glue(cx, lhs, rhs, t, llop);
|
|
|
|
ret;
|
|
|
|
}
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_is_integral(cx.fcx.lcx.ccx.tystore, t) ||
|
|
|
|
ty.type_is_bool(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-04-19 15:22:57 -07:00
|
|
|
make_integral_cmp_glue(cx, lhs, rhs, t, llop);
|
|
|
|
ret;
|
|
|
|
}
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_is_nil(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-04-19 15:22:57 -07:00
|
|
|
cx.build.Store(C_bool(true), cx.fcx.llretptr);
|
|
|
|
cx.build.RetVoid();
|
|
|
|
ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
trans_fail(cx, none[common.span],
|
2011-04-22 17:00:46 -07:00
|
|
|
"attempt to compare values of type " +
|
|
|
|
ty.ty_to_str(cx.fcx.lcx.ccx.tystore, t));
|
2011-04-19 15:22:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// A helper function to create floating point comparison glue.
|
2011-04-22 12:27:28 -07:00
|
|
|
fn make_fp_cmp_glue(@block_ctxt cx, ValueRef lhs, ValueRef rhs, ty.t fptype,
|
2011-04-19 15:22:57 -07:00
|
|
|
ValueRef llop) {
|
|
|
|
auto last_cx = new_sub_block_ctxt(cx, "last");
|
|
|
|
|
|
|
|
auto eq_cx = new_sub_block_ctxt(cx, "eq");
|
|
|
|
auto eq_result = eq_cx.build.FCmp(lib.llvm.LLVMRealUEQ, lhs, rhs);
|
|
|
|
eq_cx.build.Br(last_cx.llbb);
|
|
|
|
|
|
|
|
auto lt_cx = new_sub_block_ctxt(cx, "lt");
|
|
|
|
auto lt_result = lt_cx.build.FCmp(lib.llvm.LLVMRealULT, lhs, rhs);
|
|
|
|
lt_cx.build.Br(last_cx.llbb);
|
|
|
|
|
|
|
|
auto le_cx = new_sub_block_ctxt(cx, "le");
|
|
|
|
auto le_result = le_cx.build.FCmp(lib.llvm.LLVMRealULE, lhs, rhs);
|
|
|
|
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);
|
|
|
|
llvm.LLVMAddCase(llswitch, C_i8(abi.cmp_glue_op_eq), eq_cx.llbb);
|
|
|
|
llvm.LLVMAddCase(llswitch, C_i8(abi.cmp_glue_op_lt), lt_cx.llbb);
|
|
|
|
llvm.LLVMAddCase(llswitch, C_i8(abi.cmp_glue_op_le), le_cx.llbb);
|
|
|
|
|
|
|
|
auto last_result =
|
|
|
|
last_cx.build.Phi(T_i1(), vec(eq_result, lt_result, le_result),
|
|
|
|
vec(eq_cx.llbb, lt_cx.llbb, le_cx.llbb));
|
|
|
|
last_cx.build.Store(last_result, cx.fcx.llretptr);
|
|
|
|
last_cx.build.RetVoid();
|
|
|
|
}
|
|
|
|
|
|
|
|
// A helper function to compare integral values. This is used by both
|
|
|
|
// `make_integral_cmp_glue` and `make_cmp_glue`.
|
|
|
|
fn compare_integral_values(@block_ctxt cx, ValueRef lhs, ValueRef rhs,
|
|
|
|
bool signed, ValueRef llop) -> result {
|
|
|
|
auto lt_cmp; auto le_cmp;
|
|
|
|
if (signed) {
|
|
|
|
lt_cmp = lib.llvm.LLVMIntSLT;
|
|
|
|
le_cmp = lib.llvm.LLVMIntSLE;
|
|
|
|
} else {
|
|
|
|
lt_cmp = lib.llvm.LLVMIntULT;
|
|
|
|
le_cmp = lib.llvm.LLVMIntULE;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto last_cx = new_sub_block_ctxt(cx, "last");
|
|
|
|
|
|
|
|
auto eq_cx = new_sub_block_ctxt(cx, "eq");
|
|
|
|
auto eq_result = eq_cx.build.ICmp(lib.llvm.LLVMIntEQ, lhs, rhs);
|
|
|
|
eq_cx.build.Br(last_cx.llbb);
|
|
|
|
|
|
|
|
auto lt_cx = new_sub_block_ctxt(cx, "lt");
|
|
|
|
auto lt_result = lt_cx.build.ICmp(lt_cmp, lhs, rhs);
|
|
|
|
lt_cx.build.Br(last_cx.llbb);
|
|
|
|
|
|
|
|
auto le_cx = new_sub_block_ctxt(cx, "le");
|
|
|
|
auto le_result = le_cx.build.ICmp(le_cmp, lhs, rhs);
|
|
|
|
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);
|
|
|
|
llvm.LLVMAddCase(llswitch, C_i8(abi.cmp_glue_op_eq), eq_cx.llbb);
|
|
|
|
llvm.LLVMAddCase(llswitch, C_i8(abi.cmp_glue_op_lt), lt_cx.llbb);
|
|
|
|
llvm.LLVMAddCase(llswitch, C_i8(abi.cmp_glue_op_le), le_cx.llbb);
|
|
|
|
|
|
|
|
auto last_result =
|
|
|
|
last_cx.build.Phi(T_i1(), vec(eq_result, lt_result, le_result),
|
|
|
|
vec(eq_cx.llbb, lt_cx.llbb, le_cx.llbb));
|
|
|
|
ret res(last_cx, last_result);
|
|
|
|
}
|
|
|
|
|
|
|
|
// A helper function to create integral comparison glue.
|
|
|
|
fn make_integral_cmp_glue(@block_ctxt cx, ValueRef lhs, ValueRef rhs,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t intype, ValueRef llop) {
|
2011-04-22 17:00:46 -07:00
|
|
|
auto r = compare_integral_values(cx, lhs, rhs,
|
|
|
|
ty.type_is_signed(cx.fcx.lcx.ccx.tystore, intype), llop);
|
2011-04-19 15:22:57 -07:00
|
|
|
r.bcx.build.Store(r.val, r.bcx.fcx.llretptr);
|
|
|
|
r.bcx.build.RetVoid();
|
2011-04-18 10:56:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-25 16:45:43 -08:00
|
|
|
// Tag information
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
type variant_info = rec(vec[ty.t] args, ty.t ctor_ty, ast.def_id id);
|
2011-04-01 11:36:52 -07:00
|
|
|
|
|
|
|
// Returns information about the variants in a tag.
|
|
|
|
fn tag_variants(@crate_ctxt cx, ast.def_id id) -> vec[variant_info] {
|
2011-04-01 13:02:44 -07:00
|
|
|
if (cx.sess.get_targ_crate_num() != id._0) {
|
2011-04-20 18:52:04 -07:00
|
|
|
ret creader.get_tag_variants(cx.sess, cx.tystore, id);
|
2011-04-01 13:02:44 -07:00
|
|
|
}
|
|
|
|
|
2011-02-25 16:45:43 -08:00
|
|
|
check (cx.items.contains_key(id));
|
|
|
|
alt (cx.items.get(id).node) {
|
2011-04-01 11:36:52 -07:00
|
|
|
case (ast.item_tag(_, ?variants, _, _, _)) {
|
|
|
|
let vec[variant_info] result = vec();
|
|
|
|
for (ast.variant variant in variants) {
|
|
|
|
auto ctor_ty = node_ann_type(cx, variant.node.ann);
|
2011-04-22 12:27:28 -07:00
|
|
|
let vec[ty.t] arg_tys = vec();
|
2011-04-01 11:36:52 -07:00
|
|
|
if (_vec.len[ast.variant_arg](variant.node.args) > 0u) {
|
2011-04-22 17:00:46 -07:00
|
|
|
for (ty.arg a in ty.ty_fn_args(cx.tystore, ctor_ty)) {
|
2011-04-01 11:36:52 -07:00
|
|
|
arg_tys += vec(a.ty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
auto did = variant.node.id;
|
|
|
|
result += vec(rec(args=arg_tys, ctor_ty=ctor_ty, id=did));
|
|
|
|
}
|
|
|
|
ret result;
|
|
|
|
}
|
2011-02-25 16:45:43 -08:00
|
|
|
}
|
|
|
|
fail; // not reached
|
|
|
|
}
|
|
|
|
|
2011-04-01 11:36:52 -07:00
|
|
|
// Returns information about the tag variant with the given ID.
|
2011-03-09 15:17:06 -08:00
|
|
|
fn tag_variant_with_id(@crate_ctxt cx,
|
|
|
|
&ast.def_id tag_id,
|
2011-04-01 11:36:52 -07:00
|
|
|
&ast.def_id variant_id) -> variant_info {
|
2011-03-09 15:17:06 -08:00
|
|
|
auto variants = tag_variants(cx, tag_id);
|
|
|
|
|
|
|
|
auto i = 0u;
|
2011-04-01 11:36:52 -07:00
|
|
|
while (i < _vec.len[variant_info](variants)) {
|
2011-03-09 15:17:06 -08:00
|
|
|
auto variant = variants.(i);
|
2011-04-01 11:36:52 -07:00
|
|
|
if (common.def_eq(variant.id, variant_id)) {
|
2011-03-09 15:17:06 -08:00
|
|
|
ret variant;
|
|
|
|
}
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
|
2011-04-19 12:02:06 +02:00
|
|
|
log_err "tag_variant_with_id(): no variant exists with that ID";
|
2011-03-09 15:17:06 -08:00
|
|
|
fail;
|
|
|
|
}
|
|
|
|
|
2011-02-25 19:42:26 -08:00
|
|
|
|
2011-03-09 20:14:19 -08:00
|
|
|
type val_pair_fn = fn(@block_ctxt cx, ValueRef dst, ValueRef src) -> result;
|
2011-03-06 22:37:14 -08:00
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
type val_and_ty_fn = fn(@block_ctxt cx, ValueRef v, ty.t t) -> result;
|
2010-11-24 16:55:45 -08:00
|
|
|
|
2011-02-28 17:49:26 -08:00
|
|
|
type val_pair_and_ty_fn =
|
2011-04-22 12:27:28 -07:00
|
|
|
fn(@block_ctxt cx, ValueRef av, ValueRef bv, ty.t t) -> result;
|
2011-02-28 17:49:26 -08:00
|
|
|
|
2010-12-20 16:23:49 -08:00
|
|
|
// Iterates through the elements of a structural type.
|
2010-11-24 16:55:45 -08:00
|
|
|
fn iter_structural_ty(@block_ctxt cx,
|
|
|
|
ValueRef v,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t t,
|
2010-11-24 16:55:45 -08:00
|
|
|
val_and_ty_fn f)
|
|
|
|
-> result {
|
2011-02-28 17:49:26 -08:00
|
|
|
fn adaptor_fn(val_and_ty_fn f,
|
|
|
|
@block_ctxt cx,
|
|
|
|
ValueRef av,
|
|
|
|
ValueRef bv,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t t) -> result {
|
2011-02-28 17:49:26 -08:00
|
|
|
ret f(cx, av, t);
|
|
|
|
}
|
|
|
|
be iter_structural_ty_full(cx, v, v, t,
|
|
|
|
bind adaptor_fn(f, _, _, _, _));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn iter_structural_ty_full(@block_ctxt cx,
|
|
|
|
ValueRef av,
|
|
|
|
ValueRef bv,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t t,
|
2011-02-28 17:49:26 -08:00
|
|
|
val_pair_and_ty_fn f)
|
|
|
|
-> result {
|
2010-11-24 16:55:45 -08:00
|
|
|
let result r = res(cx, C_nil());
|
2010-12-20 16:23:49 -08:00
|
|
|
|
2010-12-20 17:28:07 -08:00
|
|
|
fn iter_boxpp(@block_ctxt cx,
|
2011-02-28 17:49:26 -08:00
|
|
|
ValueRef box_a_cell,
|
|
|
|
ValueRef box_b_cell,
|
|
|
|
val_pair_and_ty_fn f) -> result {
|
|
|
|
auto box_a_ptr = cx.build.Load(box_a_cell);
|
|
|
|
auto box_b_ptr = cx.build.Load(box_b_cell);
|
2011-04-20 18:52:04 -07:00
|
|
|
auto tnil = ty.mk_nil(cx.fcx.lcx.ccx.tystore);
|
|
|
|
auto tbox = ty.mk_imm_box(cx.fcx.lcx.ccx.tystore, tnil);
|
2010-12-20 17:28:07 -08:00
|
|
|
|
|
|
|
auto inner_cx = new_sub_block_ctxt(cx, "iter box");
|
|
|
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
2011-02-28 17:49:26 -08:00
|
|
|
auto null_test = cx.build.IsNull(box_a_ptr);
|
2010-12-20 17:28:07 -08:00
|
|
|
cx.build.CondBr(null_test, next_cx.llbb, inner_cx.llbb);
|
|
|
|
|
2011-02-28 17:49:26 -08:00
|
|
|
auto r = f(inner_cx, box_a_ptr, box_b_ptr, tbox);
|
2010-12-20 17:28:07 -08:00
|
|
|
r.bcx.build.Br(next_cx.llbb);
|
|
|
|
ret res(next_cx, r.val);
|
|
|
|
}
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.fcx.lcx.ccx.tystore, t)) {
|
2010-12-21 12:13:51 -08:00
|
|
|
case (ty.ty_tup(?args)) {
|
2010-11-24 16:55:45 -08:00
|
|
|
let int i = 0;
|
2011-03-17 17:39:47 -07:00
|
|
|
for (ty.mt arg in args) {
|
2011-03-02 16:31:20 -08:00
|
|
|
r = GEP_tup_like(r.bcx, t, av, vec(0, i));
|
|
|
|
auto elt_a = r.val;
|
|
|
|
r = GEP_tup_like(r.bcx, t, bv, vec(0, i));
|
|
|
|
auto elt_b = r.val;
|
2010-12-03 13:03:07 -08:00
|
|
|
r = f(r.bcx,
|
2011-04-12 12:06:20 -07:00
|
|
|
load_if_immediate(r.bcx, elt_a, arg.ty),
|
|
|
|
load_if_immediate(r.bcx, elt_b, arg.ty),
|
2011-03-17 17:39:47 -07:00
|
|
|
arg.ty);
|
2010-11-24 16:55:45 -08:00
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
}
|
2010-12-21 12:13:51 -08:00
|
|
|
case (ty.ty_rec(?fields)) {
|
2010-12-01 17:08:46 -08:00
|
|
|
let int i = 0;
|
2010-12-21 12:13:51 -08:00
|
|
|
for (ty.field fld in fields) {
|
2011-03-02 16:31:20 -08:00
|
|
|
r = GEP_tup_like(r.bcx, t, av, vec(0, i));
|
|
|
|
auto llfld_a = r.val;
|
|
|
|
r = GEP_tup_like(r.bcx, t, bv, vec(0, i));
|
|
|
|
auto llfld_b = r.val;
|
2010-12-03 13:03:07 -08:00
|
|
|
r = f(r.bcx,
|
2011-04-12 12:06:20 -07:00
|
|
|
load_if_immediate(r.bcx, llfld_a, fld.mt.ty),
|
|
|
|
load_if_immediate(r.bcx, llfld_b, fld.mt.ty),
|
2011-03-17 17:39:47 -07:00
|
|
|
fld.mt.ty);
|
2010-12-01 17:08:46 -08:00
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
}
|
2011-02-24 19:24:12 -08:00
|
|
|
case (ty.ty_tag(?tid, ?tps)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto variants = tag_variants(cx.fcx.lcx.ccx, tid);
|
2011-04-01 11:36:52 -07:00
|
|
|
auto n_variants = _vec.len[variant_info](variants);
|
2010-12-02 19:30:06 -08:00
|
|
|
|
2011-03-07 18:03:33 -08:00
|
|
|
// Cast the tags to types we can GEP into.
|
2011-04-17 14:24:45 +02:00
|
|
|
auto lltagty = T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn);
|
2011-03-07 18:03:33 -08:00
|
|
|
auto av_tag = cx.build.PointerCast(av, lltagty);
|
|
|
|
auto bv_tag = cx.build.PointerCast(bv, lltagty);
|
|
|
|
|
|
|
|
auto lldiscrim_a_ptr = cx.build.GEP(av_tag,
|
|
|
|
vec(C_int(0), C_int(0)));
|
|
|
|
auto llunion_a_ptr = cx.build.GEP(av_tag,
|
|
|
|
vec(C_int(0), C_int(1)));
|
2011-02-28 17:49:26 -08:00
|
|
|
auto lldiscrim_a = cx.build.Load(lldiscrim_a_ptr);
|
|
|
|
|
2011-03-07 18:03:33 -08:00
|
|
|
auto lldiscrim_b_ptr = cx.build.GEP(bv_tag,
|
|
|
|
vec(C_int(0), C_int(0)));
|
|
|
|
auto llunion_b_ptr = cx.build.GEP(bv_tag,
|
|
|
|
vec(C_int(0), C_int(1)));
|
2011-02-28 17:49:26 -08:00
|
|
|
auto lldiscrim_b = cx.build.Load(lldiscrim_b_ptr);
|
2010-12-03 12:26:27 -08:00
|
|
|
|
2011-03-01 13:00:50 -08:00
|
|
|
// NB: we must hit the discriminant first so that structural
|
|
|
|
// comparison know not to proceed when the discriminants differ.
|
|
|
|
auto bcx = cx;
|
2011-04-20 18:52:04 -07:00
|
|
|
bcx = f(bcx, lldiscrim_a, lldiscrim_b,
|
|
|
|
ty.mk_int(cx.fcx.lcx.ccx.tystore)).bcx;
|
2011-03-01 13:00:50 -08:00
|
|
|
|
|
|
|
auto unr_cx = new_sub_block_ctxt(bcx, "tag-iter-unr");
|
2010-12-02 19:30:06 -08:00
|
|
|
unr_cx.build.Unreachable();
|
|
|
|
|
2011-03-01 13:00:50 -08:00
|
|
|
auto llswitch = bcx.build.Switch(lldiscrim_a, unr_cx.llbb,
|
2011-02-28 17:49:26 -08:00
|
|
|
n_variants);
|
2010-12-03 12:26:27 -08:00
|
|
|
|
2011-03-01 13:00:50 -08:00
|
|
|
auto next_cx = new_sub_block_ctxt(bcx, "tag-iter-next");
|
2010-12-02 19:30:06 -08:00
|
|
|
|
|
|
|
auto i = 0u;
|
2011-04-01 11:36:52 -07:00
|
|
|
for (variant_info variant in variants) {
|
2011-03-01 13:00:50 -08:00
|
|
|
auto variant_cx = new_sub_block_ctxt(bcx,
|
2011-02-28 17:49:26 -08:00
|
|
|
"tag-iter-variant-" +
|
2010-12-02 19:30:06 -08:00
|
|
|
_uint.to_str(i, 10u));
|
|
|
|
llvm.LLVMAddCase(llswitch, C_int(i as int), variant_cx.llbb);
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
if (_vec.len[ty.t](variant.args) > 0u) {
|
2011-02-25 17:14:48 -08:00
|
|
|
// N-ary variant.
|
2011-04-01 11:36:52 -07:00
|
|
|
auto fn_ty = variant.ctor_ty;
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(bcx.fcx.lcx.ccx.tystore, fn_ty)) {
|
2011-02-25 17:14:48 -08:00
|
|
|
case (ty.ty_fn(_, ?args, _)) {
|
2011-03-18 18:33:21 -07:00
|
|
|
auto j = 0;
|
2011-02-25 17:14:48 -08:00
|
|
|
for (ty.arg a in args) {
|
|
|
|
auto v = vec(C_int(0), C_int(j as int));
|
2011-02-28 17:49:26 -08:00
|
|
|
|
2011-03-18 18:33:21 -07:00
|
|
|
auto rslt = GEP_tag(variant_cx, llunion_a_ptr,
|
2011-04-01 16:04:22 -07:00
|
|
|
tid, variant.id, tps, j);
|
2011-03-18 18:33:21 -07:00
|
|
|
auto llfldp_a = rslt.val;
|
|
|
|
variant_cx = rslt.bcx;
|
2011-02-28 17:49:26 -08:00
|
|
|
|
2011-03-18 18:33:21 -07:00
|
|
|
rslt = GEP_tag(variant_cx, llunion_b_ptr, tid,
|
2011-04-01 16:04:22 -07:00
|
|
|
variant.id, tps, j);
|
2011-03-18 18:33:21 -07:00
|
|
|
auto llfldp_b = rslt.val;
|
|
|
|
variant_cx = rslt.bcx;
|
2011-02-25 17:14:48 -08:00
|
|
|
|
2011-04-20 18:52:04 -07:00
|
|
|
auto ty_subst = ty.bind_params_in_type(
|
|
|
|
cx.fcx.lcx.ccx.tystore, a.ty);
|
|
|
|
ty_subst = ty.substitute_type_params(
|
|
|
|
cx.fcx.lcx.ccx.tystore, tps, ty_subst);
|
2011-02-25 17:14:48 -08:00
|
|
|
|
2011-02-28 17:49:26 -08:00
|
|
|
auto llfld_a =
|
2011-04-12 12:06:20 -07:00
|
|
|
load_if_immediate(variant_cx,
|
2011-02-28 17:49:26 -08:00
|
|
|
llfldp_a,
|
2011-02-25 17:14:48 -08:00
|
|
|
ty_subst);
|
|
|
|
|
2011-02-28 17:49:26 -08:00
|
|
|
auto llfld_b =
|
2011-04-12 12:06:20 -07:00
|
|
|
load_if_immediate(variant_cx,
|
2011-02-28 17:49:26 -08:00
|
|
|
llfldp_b,
|
|
|
|
ty_subst);
|
|
|
|
|
|
|
|
auto res = f(variant_cx,
|
|
|
|
llfld_a, llfld_b, ty_subst);
|
2011-02-25 17:14:48 -08:00
|
|
|
variant_cx = res.bcx;
|
2011-03-18 18:33:21 -07:00
|
|
|
j += 1;
|
2010-12-03 12:31:25 -08:00
|
|
|
}
|
|
|
|
}
|
2011-03-22 14:02:52 -07:00
|
|
|
case (_) { fail; }
|
2010-12-02 19:30:06 -08:00
|
|
|
}
|
2011-02-25 17:14:48 -08:00
|
|
|
|
|
|
|
variant_cx.build.Br(next_cx.llbb);
|
|
|
|
} else {
|
|
|
|
// Nullary variant; nothing to do.
|
|
|
|
variant_cx.build.Br(next_cx.llbb);
|
2010-12-02 19:30:06 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret res(next_cx, C_nil());
|
|
|
|
}
|
2011-02-18 17:30:57 -08:00
|
|
|
case (ty.ty_fn(_,_,_)) {
|
2011-02-28 17:49:26 -08:00
|
|
|
auto box_cell_a =
|
|
|
|
cx.build.GEP(av,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.fn_field_box)));
|
|
|
|
auto box_cell_b =
|
|
|
|
cx.build.GEP(bv,
|
2010-12-20 16:23:49 -08:00
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.fn_field_box)));
|
2011-02-28 17:49:26 -08:00
|
|
|
ret iter_boxpp(cx, box_cell_a, box_cell_b, f);
|
2010-12-20 16:23:49 -08:00
|
|
|
}
|
2010-12-21 12:13:51 -08:00
|
|
|
case (ty.ty_obj(_)) {
|
2011-02-28 17:49:26 -08:00
|
|
|
auto box_cell_a =
|
|
|
|
cx.build.GEP(av,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.obj_field_box)));
|
|
|
|
auto box_cell_b =
|
|
|
|
cx.build.GEP(bv,
|
2010-12-20 16:23:49 -08:00
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.obj_field_box)));
|
2011-02-28 17:49:26 -08:00
|
|
|
ret iter_boxpp(cx, box_cell_a, box_cell_b, f);
|
2010-12-20 16:23:49 -08:00
|
|
|
}
|
2010-12-01 17:08:46 -08:00
|
|
|
case (_) {
|
2011-04-17 14:24:45 +02:00
|
|
|
cx.fcx.lcx.ccx.sess.unimpl("type in iter_structural_ty_full");
|
2010-12-01 17:08:46 -08:00
|
|
|
}
|
2010-11-09 17:49:20 -08:00
|
|
|
}
|
2010-11-24 16:55:45 -08:00
|
|
|
ret r;
|
2010-11-09 17:49:20 -08:00
|
|
|
}
|
|
|
|
|
2011-03-06 22:37:14 -08:00
|
|
|
// Iterates through a pointer range, until the src* hits the src_lim*.
|
|
|
|
fn iter_sequence_raw(@block_ctxt cx,
|
2011-03-09 20:14:19 -08:00
|
|
|
ValueRef dst, // elt*
|
2011-03-06 22:37:14 -08:00
|
|
|
ValueRef src, // elt*
|
|
|
|
ValueRef src_lim, // elt*
|
|
|
|
ValueRef elt_sz,
|
2011-03-09 20:14:19 -08:00
|
|
|
val_pair_fn f) -> result {
|
2011-03-03 17:27:35 -08:00
|
|
|
|
|
|
|
auto bcx = cx;
|
|
|
|
|
2011-03-09 20:14:19 -08:00
|
|
|
let ValueRef dst_int = vp2i(bcx, dst);
|
2011-03-03 17:27:35 -08:00
|
|
|
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);
|
|
|
|
|
2011-03-09 20:14:19 -08:00
|
|
|
let ValueRef dst_curr = cond_cx.build.Phi(T_int(),
|
|
|
|
vec(dst_int), vec(bcx.llbb));
|
2011-03-03 17:27:35 -08:00
|
|
|
let ValueRef src_curr = cond_cx.build.Phi(T_int(),
|
|
|
|
vec(src_int), vec(bcx.llbb));
|
|
|
|
|
2011-03-06 22:37:14 -08:00
|
|
|
auto end_test = cond_cx.build.ICmp(lib.llvm.LLVMIntULT,
|
2011-03-03 17:27:35 -08:00
|
|
|
src_curr, src_lim_int);
|
|
|
|
|
|
|
|
cond_cx.build.CondBr(end_test, body_cx.llbb, next_cx.llbb);
|
|
|
|
|
2011-03-09 20:14:19 -08:00
|
|
|
auto dst_curr_ptr = vi2p(body_cx, dst_curr, T_ptr(T_i8()));
|
2011-03-06 22:37:14 -08:00
|
|
|
auto src_curr_ptr = vi2p(body_cx, src_curr, T_ptr(T_i8()));
|
2011-03-03 17:27:35 -08:00
|
|
|
|
2011-03-09 20:14:19 -08:00
|
|
|
auto body_res = f(body_cx, dst_curr_ptr, src_curr_ptr);
|
2011-03-03 17:27:35 -08:00
|
|
|
body_cx = body_res.bcx;
|
|
|
|
|
2011-03-09 20:14:19 -08:00
|
|
|
auto dst_next = body_cx.build.Add(dst_curr, elt_sz);
|
2011-03-06 22:37:14 -08:00
|
|
|
auto src_next = body_cx.build.Add(src_curr, elt_sz);
|
2011-03-03 17:27:35 -08:00
|
|
|
body_cx.build.Br(cond_cx.llbb);
|
|
|
|
|
2011-03-09 20:14:19 -08:00
|
|
|
cond_cx.build.AddIncomingToPhi(dst_curr, vec(dst_next),
|
|
|
|
vec(body_cx.llbb));
|
2011-03-03 17:27:35 -08:00
|
|
|
cond_cx.build.AddIncomingToPhi(src_curr, vec(src_next),
|
|
|
|
vec(body_cx.llbb));
|
|
|
|
|
|
|
|
ret res(next_cx, C_nil());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn iter_sequence_inner(@block_ctxt cx,
|
|
|
|
ValueRef src, // elt*
|
|
|
|
ValueRef src_lim, // elt*
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t elt_ty,
|
2011-03-03 17:27:35 -08:00
|
|
|
val_and_ty_fn f) -> result {
|
|
|
|
fn adaptor_fn(val_and_ty_fn f,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t elt_ty,
|
2011-03-03 17:27:35 -08:00
|
|
|
@block_ctxt cx,
|
2011-03-09 20:14:19 -08:00
|
|
|
ValueRef dst,
|
|
|
|
ValueRef src) -> result {
|
2011-03-18 16:04:16 -07:00
|
|
|
auto llptrty;
|
2011-04-22 17:00:46 -07:00
|
|
|
if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tystore, elt_ty)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llty = type_of(cx.fcx.lcx.ccx, elt_ty);
|
2011-03-18 16:04:16 -07:00
|
|
|
llptrty = T_ptr(llty);
|
|
|
|
} else {
|
|
|
|
llptrty = T_ptr(T_ptr(T_i8()));
|
|
|
|
}
|
|
|
|
|
|
|
|
auto p = cx.build.PointerCast(src, llptrty);
|
2011-04-12 12:06:20 -07:00
|
|
|
ret f(cx, load_if_immediate(cx, p, elt_ty), elt_ty);
|
2011-03-03 17:27:35 -08:00
|
|
|
}
|
|
|
|
|
2011-03-06 22:37:14 -08:00
|
|
|
auto elt_sz = size_of(cx, elt_ty);
|
2011-03-09 20:14:19 -08:00
|
|
|
be iter_sequence_raw(elt_sz.bcx, src, src, src_lim, elt_sz.val,
|
|
|
|
bind adaptor_fn(f, elt_ty, _, _, _));
|
2011-03-03 17:27:35 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-24 16:55:45 -08:00
|
|
|
// Iterates through the elements of a vec or str.
|
|
|
|
fn iter_sequence(@block_ctxt cx,
|
|
|
|
ValueRef v,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t t,
|
2010-11-24 16:55:45 -08:00
|
|
|
val_and_ty_fn f) -> result {
|
|
|
|
|
|
|
|
fn iter_sequence_body(@block_ctxt cx,
|
|
|
|
ValueRef v,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t elt_ty,
|
2010-11-24 16:55:45 -08:00
|
|
|
val_and_ty_fn f,
|
|
|
|
bool trailing_null) -> result {
|
|
|
|
|
|
|
|
auto p0 = cx.build.GEP(v, vec(C_int(0),
|
|
|
|
C_int(abi.vec_elt_data)));
|
|
|
|
auto lenptr = cx.build.GEP(v, vec(C_int(0),
|
|
|
|
C_int(abi.vec_elt_fill)));
|
2010-12-13 17:48:33 -08:00
|
|
|
|
2011-03-18 16:04:16 -07:00
|
|
|
auto llunit_ty;
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tystore, elt_ty)) {
|
2011-03-18 16:04:16 -07:00
|
|
|
llunit_ty = T_i8();
|
|
|
|
} else {
|
2011-04-17 14:24:45 +02:00
|
|
|
llunit_ty = type_of(cx.fcx.lcx.ccx, elt_ty);
|
2011-03-18 16:04:16 -07:00
|
|
|
}
|
|
|
|
|
2011-01-31 15:03:05 -08:00
|
|
|
auto bcx = cx;
|
2010-12-13 17:48:33 -08:00
|
|
|
|
2011-01-31 15:03:05 -08:00
|
|
|
auto len = bcx.build.Load(lenptr);
|
2010-11-24 16:55:45 -08:00
|
|
|
if (trailing_null) {
|
2011-03-03 17:27:35 -08:00
|
|
|
auto unit_sz = size_of(bcx, elt_ty);
|
|
|
|
bcx = unit_sz.bcx;
|
2011-01-31 15:03:05 -08:00
|
|
|
len = bcx.build.Sub(len, unit_sz.val);
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
|
|
|
|
2011-03-03 17:27:35 -08:00
|
|
|
auto p1 = vi2p(bcx, bcx.build.Add(vp2i(bcx, p0), len),
|
|
|
|
T_ptr(llunit_ty));
|
2010-12-13 17:48:33 -08:00
|
|
|
|
2011-03-03 17:27:35 -08:00
|
|
|
ret iter_sequence_inner(cx, p0, p1, elt_ty, f);
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-03-17 17:39:47 -07:00
|
|
|
case (ty.ty_vec(?elt)) {
|
|
|
|
ret iter_sequence_body(cx, v, elt.ty, f, false);
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
2010-12-21 12:13:51 -08:00
|
|
|
case (ty.ty_str) {
|
2011-04-20 18:52:04 -07:00
|
|
|
auto et = ty.mk_mach(cx.fcx.lcx.ccx.tystore, common.ty_u8);
|
2010-12-13 17:48:33 -08:00
|
|
|
ret iter_sequence_body(cx, v, et, f, true);
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
2011-03-22 14:02:52 -07:00
|
|
|
case (_) { fail; }
|
2010-11-09 17:49:20 -08:00
|
|
|
}
|
2011-04-17 14:24:45 +02:00
|
|
|
cx.fcx.lcx.ccx.sess.bug("bad type in trans.iter_sequence");
|
2010-11-24 16:55:45 -08:00
|
|
|
fail;
|
|
|
|
}
|
|
|
|
|
2011-01-28 14:34:25 -08:00
|
|
|
fn call_tydesc_glue_full(@block_ctxt cx, ValueRef v,
|
|
|
|
ValueRef tydesc, int field) {
|
|
|
|
auto llrawptr = cx.build.BitCast(v, T_ptr(T_i8()));
|
|
|
|
auto lltydescs = cx.build.GEP(tydesc,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.tydesc_field_first_param)));
|
|
|
|
lltydescs = cx.build.Load(lltydescs);
|
|
|
|
auto llfnptr = cx.build.GEP(tydesc, vec(C_int(0), C_int(field)));
|
|
|
|
auto llfn = cx.build.Load(llfnptr);
|
2011-02-01 14:57:03 -08:00
|
|
|
|
2011-02-08 11:47:53 -08:00
|
|
|
cx.build.FastCall(llfn, vec(C_null(T_ptr(T_nil())),
|
|
|
|
cx.fcx.lltaskptr,
|
|
|
|
C_null(T_ptr(T_nil())),
|
|
|
|
lltydescs,
|
|
|
|
llrawptr));
|
2011-01-28 14:34:25 -08:00
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn call_tydesc_glue(@block_ctxt cx, ValueRef v, ty.t t, int field) {
|
2011-01-31 15:03:05 -08:00
|
|
|
auto td = get_tydesc(cx, t);
|
2011-04-12 12:06:20 -07:00
|
|
|
call_tydesc_glue_full(td.bcx,
|
|
|
|
spill_if_immediate(td.bcx, v, t),
|
|
|
|
td.val, field);
|
2011-01-28 14:34:25 -08:00
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn call_cmp_glue(@block_ctxt cx, ValueRef lhs, ValueRef rhs, ty.t t,
|
2011-04-19 15:22:57 -07:00
|
|
|
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()));
|
|
|
|
|
|
|
|
auto r = get_tydesc(cx, t);
|
|
|
|
auto lltydescs =
|
|
|
|
r.bcx.build.GEP(r.val, vec(C_int(0),
|
|
|
|
C_int(abi.tydesc_field_first_param)));
|
|
|
|
lltydescs = r.bcx.build.Load(lltydescs);
|
|
|
|
auto llfnptr =
|
|
|
|
r.bcx.build.GEP(r.val, vec(C_int(0),
|
|
|
|
C_int(abi.tydesc_field_cmp_glue)));
|
|
|
|
auto llfn = r.bcx.build.Load(llfnptr);
|
|
|
|
|
|
|
|
auto llcmpresultptr = r.bcx.build.Alloca(T_i1());
|
|
|
|
|
|
|
|
let vec[ValueRef] llargs = vec(llcmpresultptr,
|
|
|
|
r.bcx.fcx.lltaskptr,
|
|
|
|
C_null(T_ptr(T_nil())),
|
|
|
|
lltydescs,
|
|
|
|
llrawlhsptr,
|
|
|
|
llrawrhsptr,
|
|
|
|
llop);
|
|
|
|
|
|
|
|
r.bcx.build.FastCall(llfn, llargs);
|
|
|
|
|
|
|
|
ret res(r.bcx, r.bcx.build.Load(llcmpresultptr));
|
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn take_ty(@block_ctxt cx, ValueRef v, ty.t t) -> result {
|
2011-04-22 17:00:46 -07:00
|
|
|
if (!ty.type_is_scalar(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-04-09 00:54:46 +00:00
|
|
|
call_tydesc_glue(cx, v, t, abi.tydesc_field_take_glue);
|
2010-12-17 18:20:10 -08:00
|
|
|
}
|
2010-11-26 13:03:56 -08:00
|
|
|
ret res(cx, C_nil());
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
|
|
|
|
2010-12-02 19:44:24 -08:00
|
|
|
fn drop_slot(@block_ctxt cx,
|
|
|
|
ValueRef slot,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t t) -> result {
|
2011-04-12 12:06:20 -07:00
|
|
|
auto llptr = load_if_immediate(cx, slot, t);
|
2010-12-17 17:21:56 -08:00
|
|
|
auto re = drop_ty(cx, llptr, t);
|
|
|
|
|
|
|
|
auto llty = val_ty(slot);
|
|
|
|
auto llelemty = lib.llvm.llvm.LLVMGetElementType(llty);
|
|
|
|
re.bcx.build.Store(C_null(llelemty), slot);
|
|
|
|
ret re;
|
2010-12-02 19:44:24 -08:00
|
|
|
}
|
|
|
|
|
2010-11-24 16:55:45 -08:00
|
|
|
fn drop_ty(@block_ctxt cx,
|
|
|
|
ValueRef v,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t t) -> result {
|
2010-12-20 16:23:49 -08:00
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
if (!ty.type_is_scalar(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-04-09 00:54:46 +00:00
|
|
|
call_tydesc_glue(cx, v, t, abi.tydesc_field_drop_glue);
|
2010-12-17 18:20:10 -08:00
|
|
|
}
|
2010-12-10 15:02:23 -08:00
|
|
|
ret res(cx, C_nil());
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
|
|
|
|
2011-01-17 17:24:33 -08:00
|
|
|
fn call_memcpy(@block_ctxt cx,
|
|
|
|
ValueRef dst,
|
|
|
|
ValueRef src,
|
|
|
|
ValueRef n_bytes) -> result {
|
2010-11-24 16:55:45 -08:00
|
|
|
auto src_ptr = cx.build.PointerCast(src, T_ptr(T_i8()));
|
|
|
|
auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
|
2011-01-17 17:24:33 -08:00
|
|
|
auto size = cx.build.IntCast(n_bytes, T_int());
|
2011-04-17 14:24:45 +02:00
|
|
|
ret res(cx, cx.build.FastCall(cx.fcx.lcx.ccx.glues.memcpy_glue,
|
2011-01-17 17:24:33 -08:00
|
|
|
vec(dst_ptr, src_ptr, size)));
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
|
|
|
|
2011-01-18 15:38:35 -08:00
|
|
|
fn call_bzero(@block_ctxt cx,
|
|
|
|
ValueRef dst,
|
|
|
|
ValueRef n_bytes) -> result {
|
|
|
|
auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
|
|
|
|
auto size = cx.build.IntCast(n_bytes, T_int());
|
2011-04-17 14:24:45 +02:00
|
|
|
ret res(cx, cx.build.FastCall(cx.fcx.lcx.ccx.glues.bzero_glue,
|
2011-01-18 15:38:35 -08:00
|
|
|
vec(dst_ptr, size)));
|
|
|
|
}
|
|
|
|
|
2011-01-17 13:30:29 -08:00
|
|
|
fn memcpy_ty(@block_ctxt cx,
|
|
|
|
ValueRef dst,
|
|
|
|
ValueRef src,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t t) -> result {
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-01-17 13:30:29 -08:00
|
|
|
auto llszptr = field_of_tydesc(cx, t, abi.tydesc_field_size);
|
2011-01-31 15:03:05 -08:00
|
|
|
auto llsz = llszptr.bcx.build.Load(llszptr.val);
|
|
|
|
ret call_memcpy(llszptr.bcx, dst, src, llsz);
|
2011-01-17 13:30:29 -08:00
|
|
|
|
|
|
|
} else {
|
|
|
|
ret res(cx, cx.build.Store(cx.build.Load(src), dst));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-24 15:26:10 -08:00
|
|
|
tag copy_action {
|
|
|
|
INIT;
|
|
|
|
DROP_EXISTING;
|
|
|
|
}
|
|
|
|
|
2010-11-24 16:55:45 -08:00
|
|
|
fn copy_ty(@block_ctxt cx,
|
2011-01-24 15:26:10 -08:00
|
|
|
copy_action action,
|
2010-11-24 16:55:45 -08:00
|
|
|
ValueRef dst,
|
|
|
|
ValueRef src,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t t) -> result {
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_is_scalar(cx.fcx.lcx.ccx.tystore, t) ||
|
|
|
|
ty.type_is_native(cx.fcx.lcx.ccx.tystore, t)) {
|
2010-11-24 16:55:45 -08:00
|
|
|
ret res(cx, cx.build.Store(src, dst));
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
} else if (ty.type_is_nil(cx.fcx.lcx.ccx.tystore, t)) {
|
2010-11-24 16:55:45 -08:00
|
|
|
ret res(cx, C_nil());
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
} else if (ty.type_is_boxed(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-03-31 02:07:25 -04:00
|
|
|
auto r = take_ty(cx, src, t);
|
2011-01-24 15:26:10 -08:00
|
|
|
if (action == DROP_EXISTING) {
|
2010-12-06 17:46:35 -08:00
|
|
|
r = drop_ty(r.bcx, r.bcx.build.Load(dst), t);
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
|
|
|
ret res(r.bcx, r.bcx.build.Store(src, dst));
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
} else if (ty.type_is_structural(cx.fcx.lcx.ccx.tystore, t) ||
|
|
|
|
ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-03-31 02:07:25 -04:00
|
|
|
auto r = take_ty(cx, src, t);
|
2011-01-24 15:26:10 -08:00
|
|
|
if (action == DROP_EXISTING) {
|
2010-11-24 16:55:45 -08:00
|
|
|
r = drop_ty(r.bcx, dst, t);
|
|
|
|
}
|
2011-01-17 13:30:29 -08:00
|
|
|
ret memcpy_ty(r.bcx, dst, src, t);
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
cx.fcx.lcx.ccx.sess.bug("unexpected type in trans.copy_ty: " +
|
2011-04-22 17:00:46 -07:00
|
|
|
ty.ty_to_str(cx.fcx.lcx.ccx.tystore, t));
|
2010-11-09 17:49:20 -08:00
|
|
|
fail;
|
|
|
|
}
|
|
|
|
|
2011-01-21 12:09:25 -08:00
|
|
|
fn trans_lit(@crate_ctxt cx, &ast.lit lit, &ast.ann ann) -> ValueRef {
|
2010-10-05 18:21:44 -07:00
|
|
|
alt (lit.node) {
|
2010-09-28 14:01:21 -07:00
|
|
|
case (ast.lit_int(?i)) {
|
2011-01-21 12:09:25 -08:00
|
|
|
ret C_int(i);
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
|
|
|
case (ast.lit_uint(?u)) {
|
2011-01-21 12:09:25 -08:00
|
|
|
ret C_int(u as int);
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
2010-11-22 17:41:26 -08:00
|
|
|
case (ast.lit_mach_int(?tm, ?i)) {
|
|
|
|
// 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.
|
|
|
|
auto t = T_int();
|
|
|
|
alt (tm) {
|
2011-01-17 14:35:57 -08:00
|
|
|
case (common.ty_u8) { t = T_i8(); }
|
|
|
|
case (common.ty_u16) { t = T_i16(); }
|
|
|
|
case (common.ty_u32) { t = T_i32(); }
|
|
|
|
case (common.ty_u64) { t = T_i64(); }
|
|
|
|
|
|
|
|
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(); }
|
2010-11-22 17:41:26 -08:00
|
|
|
}
|
2011-01-21 12:09:25 -08:00
|
|
|
ret C_integral(i, t);
|
2010-11-22 17:41:26 -08:00
|
|
|
}
|
2011-03-21 17:12:05 -07:00
|
|
|
case(ast.lit_float(?fs)) {
|
|
|
|
ret C_float(fs);
|
|
|
|
}
|
2011-03-22 17:25:40 -07:00
|
|
|
case(ast.lit_mach_float(?tm, ?s)) {
|
|
|
|
auto t = T_float();
|
|
|
|
alt(tm) {
|
|
|
|
case(common.ty_f32) { t = T_f32(); }
|
|
|
|
case(common.ty_f64) { t = T_f64(); }
|
|
|
|
}
|
|
|
|
ret C_floating(s, t);
|
|
|
|
}
|
2010-09-28 14:01:21 -07:00
|
|
|
case (ast.lit_char(?c)) {
|
2011-01-21 12:09:25 -08:00
|
|
|
ret C_integral(c as int, T_char());
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
|
|
|
case (ast.lit_bool(?b)) {
|
2011-01-21 12:09:25 -08:00
|
|
|
ret C_bool(b);
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
|
|
|
case (ast.lit_nil) {
|
2011-01-21 12:09:25 -08:00
|
|
|
ret C_nil();
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
|
|
|
case (ast.lit_str(?s)) {
|
2011-01-21 12:09:25 -08:00
|
|
|
ret C_str(cx, s);
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn target_type(@crate_ctxt cx, ty.t t) -> ty.t {
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.tystore, t)) {
|
2010-12-21 12:13:51 -08:00
|
|
|
case (ty.ty_int) {
|
2011-04-20 18:52:04 -07:00
|
|
|
auto struct_ty = ty.mk_mach(cx.tystore,
|
|
|
|
cx.sess.get_targ_cfg().int_type);
|
2011-04-21 19:30:53 -07:00
|
|
|
ret ty.copy_cname(cx.tystore, struct_ty, t);
|
2010-11-22 16:27:00 -08:00
|
|
|
}
|
2010-12-21 12:13:51 -08:00
|
|
|
case (ty.ty_uint) {
|
2011-04-20 18:52:04 -07:00
|
|
|
auto struct_ty = ty.mk_mach(cx.tystore,
|
|
|
|
cx.sess.get_targ_cfg().uint_type);
|
2011-04-21 19:30:53 -07:00
|
|
|
ret ty.copy_cname(cx.tystore, struct_ty, t);
|
2010-11-22 16:27:00 -08:00
|
|
|
}
|
2010-12-01 17:08:46 -08:00
|
|
|
case (_) { /* fall through */ }
|
2010-11-22 16:27:00 -08:00
|
|
|
}
|
|
|
|
ret t;
|
|
|
|
}
|
|
|
|
|
2011-04-08 21:27:54 -07:00
|
|
|
|
|
|
|
// Converts an annotation to a type
|
2011-04-22 12:27:28 -07:00
|
|
|
fn node_ann_type(@crate_ctxt cx, &ast.ann a) -> ty.t {
|
2011-04-20 18:52:04 -07:00
|
|
|
ret target_type(cx, ty.ann_to_monotype(cx.tystore, a));
|
2010-11-05 18:31:02 -07:00
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn node_ann_ty_params(&ast.ann a) -> vec[ty.t] {
|
2011-03-09 17:48:07 -08:00
|
|
|
alt (a) {
|
|
|
|
case (ast.ann_none) {
|
2011-04-19 12:02:06 +02:00
|
|
|
log_err "missing type annotation";
|
2011-03-09 17:48:07 -08:00
|
|
|
fail;
|
|
|
|
}
|
2011-03-24 12:12:04 -07:00
|
|
|
case (ast.ann_type(_, ?tps_opt, _)) {
|
2011-03-09 17:48:07 -08:00
|
|
|
alt (tps_opt) {
|
2011-04-22 12:27:28 -07:00
|
|
|
case (none[vec[ty.t]]) {
|
2011-04-19 12:02:06 +02:00
|
|
|
log_err "type annotation has no ty params";
|
2011-03-09 17:48:07 -08:00
|
|
|
fail;
|
|
|
|
}
|
2011-04-22 12:27:28 -07:00
|
|
|
case (some[vec[ty.t]](?tps)) { ret tps; }
|
2011-03-09 17:48:07 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-22 16:27:00 -08:00
|
|
|
fn node_type(@crate_ctxt cx, &ast.ann a) -> TypeRef {
|
|
|
|
ret type_of(cx, node_ann_type(cx, a));
|
|
|
|
}
|
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
fn trans_unary(@block_ctxt cx, ast.unop op,
|
|
|
|
@ast.expr e, &ast.ann a) -> result {
|
2010-10-04 15:55:12 -07:00
|
|
|
|
|
|
|
auto sub = trans_expr(cx, e);
|
2011-04-20 18:52:04 -07:00
|
|
|
auto e_ty = ty.expr_ty(cx.fcx.lcx.ccx.tystore, e);
|
2010-10-04 15:55:12 -07:00
|
|
|
|
2010-09-28 14:01:21 -07:00
|
|
|
alt (op) {
|
|
|
|
case (ast.bitnot) {
|
2011-04-20 18:52:04 -07:00
|
|
|
sub = autoderef(sub.bcx, sub.val,
|
|
|
|
ty.expr_ty(cx.fcx.lcx.ccx.tystore, e));
|
2011-03-19 15:03:21 -07:00
|
|
|
ret res(sub.bcx, sub.bcx.build.Not(sub.val));
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
|
|
|
case (ast.not) {
|
2011-04-20 18:52:04 -07:00
|
|
|
sub = autoderef(sub.bcx, sub.val,
|
|
|
|
ty.expr_ty(cx.fcx.lcx.ccx.tystore, e));
|
2011-03-19 15:03:21 -07:00
|
|
|
ret res(sub.bcx, sub.bcx.build.Not(sub.val));
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
|
|
|
case (ast.neg) {
|
2011-04-20 18:52:04 -07:00
|
|
|
sub = autoderef(sub.bcx, sub.val,
|
|
|
|
ty.expr_ty(cx.fcx.lcx.ccx.tystore, e));
|
2011-04-22 17:00:46 -07:00
|
|
|
if(ty.struct(cx.fcx.lcx.ccx.tystore, e_ty) == ty.ty_float) {
|
2011-03-21 16:21:54 -07:00
|
|
|
ret res(sub.bcx, sub.bcx.build.FNeg(sub.val));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ret res(sub.bcx, sub.bcx.build.Neg(sub.val));
|
|
|
|
}
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
2011-04-04 15:44:15 -07:00
|
|
|
case (ast.box(_)) {
|
2011-04-20 18:52:04 -07:00
|
|
|
auto e_ty = ty.expr_ty(cx.fcx.lcx.ccx.tystore, e);
|
2010-12-02 17:43:05 -08:00
|
|
|
auto e_val = sub.val;
|
2011-04-17 14:24:45 +02:00
|
|
|
auto box_ty = node_ann_type(sub.bcx.fcx.lcx.ccx, a);
|
2011-03-07 14:05:16 -08:00
|
|
|
sub = trans_malloc_boxed(sub.bcx, e_ty);
|
|
|
|
find_scope_cx(cx).cleanups +=
|
2011-03-16 14:58:02 -07:00
|
|
|
vec(clean(bind drop_ty(_, sub.val, box_ty)));
|
2011-03-07 14:05:16 -08:00
|
|
|
|
2010-12-02 17:43:05 -08:00
|
|
|
auto box = sub.val;
|
|
|
|
auto rc = sub.bcx.build.GEP(box,
|
2010-11-05 18:31:02 -07:00
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.box_rc_field_refcnt)));
|
2010-12-02 17:43:05 -08:00
|
|
|
auto body = sub.bcx.build.GEP(box,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.box_rc_field_body)));
|
|
|
|
sub.bcx.build.Store(C_int(1), rc);
|
2011-03-07 16:35:00 -08:00
|
|
|
|
|
|
|
// 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.
|
2011-04-22 17:00:46 -07:00
|
|
|
if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tystore, e_ty)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llety = T_ptr(type_of(sub.bcx.fcx.lcx.ccx, e_ty));
|
2011-03-07 16:35:00 -08:00
|
|
|
body = sub.bcx.build.PointerCast(body, llety);
|
|
|
|
}
|
|
|
|
|
2011-01-24 15:26:10 -08:00
|
|
|
sub = copy_ty(sub.bcx, INIT, body, e_val, e_ty);
|
2010-12-02 17:43:05 -08:00
|
|
|
ret res(sub.bcx, box);
|
2010-11-05 18:31:02 -07:00
|
|
|
}
|
2010-12-02 19:12:09 -08:00
|
|
|
case (ast.deref) {
|
2011-04-19 12:02:06 +02:00
|
|
|
log_err "deref expressions should have been translated using " +
|
2011-04-07 12:50:37 -07:00
|
|
|
"trans_lval(), not trans_unary()";
|
|
|
|
fail;
|
2010-12-01 17:08:46 -08:00
|
|
|
}
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
|
|
|
fail;
|
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn trans_compare(@block_ctxt cx0, ast.binop op, ty.t t0,
|
2011-03-09 20:14:19 -08:00
|
|
|
ValueRef lhs0, ValueRef rhs0) -> result {
|
2011-04-19 15:22:57 -07:00
|
|
|
// Autoderef both sides.
|
2011-03-09 20:14:19 -08:00
|
|
|
auto cx = cx0;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
auto t = autoderefed_ty(cx.fcx.lcx.ccx, t0);
|
2011-02-28 16:36:08 -08:00
|
|
|
|
2011-04-19 15:22:57 -07:00
|
|
|
// Determine the operation we need.
|
|
|
|
// FIXME: Use or-patterns when we have them.
|
|
|
|
auto llop;
|
2011-02-28 16:36:08 -08:00
|
|
|
alt (op) {
|
2011-04-19 15:22:57 -07:00
|
|
|
case (ast.eq) { llop = C_i8(abi.cmp_glue_op_eq); }
|
|
|
|
case (ast.lt) { llop = C_i8(abi.cmp_glue_op_lt); }
|
|
|
|
case (ast.le) { llop = C_i8(abi.cmp_glue_op_le); }
|
|
|
|
case (ast.ne) { llop = C_i8(abi.cmp_glue_op_eq); }
|
|
|
|
case (ast.ge) { llop = C_i8(abi.cmp_glue_op_lt); }
|
|
|
|
case (ast.gt) { llop = C_i8(abi.cmp_glue_op_le); }
|
2011-02-28 16:36:08 -08:00
|
|
|
}
|
|
|
|
|
2011-04-19 15:22:57 -07:00
|
|
|
auto rslt = call_cmp_glue(cx, lhs, rhs, t, llop);
|
2011-02-28 16:36:08 -08:00
|
|
|
|
2011-04-19 15:22:57 -07:00
|
|
|
// Invert the result if necessary.
|
|
|
|
// FIXME: Use or-patterns when we have them.
|
2011-02-10 19:40:02 -08:00
|
|
|
alt (op) {
|
2011-04-19 15:22:57 -07:00
|
|
|
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); }
|
|
|
|
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)); }
|
2011-02-10 19:40:02 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn trans_vec_append(@block_ctxt cx, ty.t t,
|
2011-03-03 18:18:51 -08:00
|
|
|
ValueRef lhs, ValueRef rhs) -> result {
|
|
|
|
|
2011-04-20 18:52:04 -07:00
|
|
|
auto elt_ty = ty.sequence_element_type(cx.fcx.lcx.ccx.tystore, t);
|
2011-03-03 18:18:51 -08:00
|
|
|
|
|
|
|
auto skip_null = C_bool(false);
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-03-03 18:18:51 -08:00
|
|
|
case (ty.ty_str) { skip_null = C_bool(true); }
|
|
|
|
case (_) { }
|
|
|
|
}
|
|
|
|
|
|
|
|
auto bcx = cx;
|
|
|
|
|
|
|
|
auto llvec_tydesc = get_tydesc(bcx, t);
|
|
|
|
bcx = llvec_tydesc.bcx;
|
|
|
|
|
|
|
|
auto llelt_tydesc = get_tydesc(bcx, elt_ty);
|
|
|
|
bcx = llelt_tydesc.bcx;
|
|
|
|
|
2011-03-06 12:46:33 -08:00
|
|
|
auto dst = bcx.build.PointerCast(lhs, T_ptr(T_opaque_vec_ptr()));
|
|
|
|
auto src = bcx.build.PointerCast(rhs, T_opaque_vec_ptr());
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
ret res(bcx, bcx.build.FastCall(cx.fcx.lcx.ccx.glues.vec_append_glue,
|
2011-03-06 12:46:33 -08:00
|
|
|
vec(cx.fcx.lltaskptr,
|
|
|
|
llvec_tydesc.val,
|
|
|
|
llelt_tydesc.val,
|
|
|
|
dst, src, skip_null)));
|
2011-03-02 16:42:09 -08:00
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn trans_vec_add(@block_ctxt cx, ty.t t,
|
2011-03-03 18:18:51 -08:00
|
|
|
ValueRef lhs, ValueRef rhs) -> result {
|
2011-03-02 16:42:09 -08:00
|
|
|
auto r = alloc_ty(cx, t);
|
2011-03-06 12:46:33 -08:00
|
|
|
auto tmp = r.val;
|
|
|
|
r = copy_ty(r.bcx, INIT, tmp, lhs, t);
|
2011-03-06 15:12:33 -08:00
|
|
|
auto bcx = trans_vec_append(r.bcx, t, tmp, rhs).bcx;
|
2011-04-12 12:06:20 -07:00
|
|
|
tmp = load_if_immediate(bcx, tmp, t);
|
2011-03-16 14:58:02 -07:00
|
|
|
find_scope_cx(cx).cleanups +=
|
|
|
|
vec(clean(bind drop_ty(_, tmp, t)));
|
2011-03-07 00:13:56 -08:00
|
|
|
ret res(bcx, tmp);
|
2011-03-02 16:42:09 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn trans_eager_binop(@block_ctxt cx, ast.binop op, ty.t intype,
|
2011-02-28 16:36:08 -08:00
|
|
|
ValueRef lhs, ValueRef rhs) -> result {
|
2010-12-08 14:50:47 -08:00
|
|
|
|
2011-03-21 16:21:54 -07:00
|
|
|
auto is_float = false;
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.fcx.lcx.ccx.tystore, intype)) {
|
2011-03-21 16:21:54 -07:00
|
|
|
case (ty.ty_float) {
|
|
|
|
is_float = true;
|
|
|
|
}
|
|
|
|
case (_) {
|
|
|
|
is_float = false;
|
|
|
|
}
|
|
|
|
}
|
2011-03-22 17:25:40 -07:00
|
|
|
|
2010-12-08 14:50:47 -08:00
|
|
|
alt (op) {
|
2011-03-02 16:42:09 -08:00
|
|
|
case (ast.add) {
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_is_sequence(cx.fcx.lcx.ccx.tystore, intype)) {
|
2011-03-03 18:18:51 -08:00
|
|
|
ret trans_vec_add(cx, intype, lhs, rhs);
|
2011-03-02 16:42:09 -08:00
|
|
|
}
|
2011-03-21 16:21:54 -07:00
|
|
|
if (is_float) {
|
|
|
|
ret res(cx, cx.build.FAdd(lhs, rhs));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ret res(cx, cx.build.Add(lhs, rhs));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case (ast.sub) {
|
|
|
|
if (is_float) {
|
|
|
|
ret res(cx, cx.build.FSub(lhs, rhs));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ret res(cx, cx.build.Sub(lhs, rhs));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-22 17:25:40 -07:00
|
|
|
case (ast.mul) {
|
2011-03-21 16:21:54 -07:00
|
|
|
if (is_float) {
|
|
|
|
ret res(cx, cx.build.FMul(lhs, rhs));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ret res(cx, cx.build.Mul(lhs, rhs));
|
|
|
|
}
|
2011-03-02 16:42:09 -08:00
|
|
|
}
|
2010-12-08 14:50:47 -08:00
|
|
|
|
2011-02-13 00:49:04 -05:00
|
|
|
case (ast.div) {
|
2011-03-21 16:21:54 -07:00
|
|
|
if (is_float) {
|
|
|
|
ret res(cx, cx.build.FDiv(lhs, rhs));
|
|
|
|
}
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_is_signed(cx.fcx.lcx.ccx.tystore, intype)) {
|
2011-02-28 16:36:08 -08:00
|
|
|
ret res(cx, cx.build.SDiv(lhs, rhs));
|
2011-02-13 00:49:04 -05:00
|
|
|
} else {
|
2011-02-28 16:36:08 -08:00
|
|
|
ret res(cx, cx.build.UDiv(lhs, rhs));
|
2011-02-13 00:49:04 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
case (ast.rem) {
|
2011-03-21 16:21:54 -07:00
|
|
|
if (is_float) {
|
|
|
|
ret res(cx, cx.build.FRem(lhs, rhs));
|
|
|
|
}
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_is_signed(cx.fcx.lcx.ccx.tystore, intype)) {
|
2011-02-28 16:36:08 -08:00
|
|
|
ret res(cx, cx.build.SRem(lhs, rhs));
|
2011-02-13 00:49:04 -05:00
|
|
|
} else {
|
2011-02-28 16:36:08 -08:00
|
|
|
ret res(cx, cx.build.URem(lhs, rhs));
|
2011-02-13 00:49:04 -05:00
|
|
|
}
|
|
|
|
}
|
2010-12-08 14:50:47 -08:00
|
|
|
|
2011-02-28 16:36:08 -08:00
|
|
|
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)); }
|
2010-12-08 14:50:47 -08:00
|
|
|
case (_) {
|
2011-02-13 00:49:04 -05:00
|
|
|
ret trans_compare(cx, op, intype, lhs, rhs);
|
2010-12-08 14:50:47 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
fail;
|
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn autoderef(@block_ctxt cx, ValueRef v, ty.t t) -> result {
|
2011-01-24 18:03:31 -08:00
|
|
|
let ValueRef v1 = v;
|
2011-04-22 12:27:28 -07:00
|
|
|
let ty.t t1 = t;
|
2011-01-24 18:03:31 -08:00
|
|
|
|
|
|
|
while (true) {
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.fcx.lcx.ccx.tystore, t1)) {
|
2011-03-17 17:39:47 -07:00
|
|
|
case (ty.ty_box(?mt)) {
|
2011-01-24 18:03:31 -08:00
|
|
|
auto body = cx.build.GEP(v1,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.box_rc_field_body)));
|
2011-03-17 17:39:47 -07:00
|
|
|
t1 = mt.ty;
|
2011-04-07 15:09:45 -07:00
|
|
|
|
|
|
|
// 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.
|
2011-04-22 17:00:46 -07:00
|
|
|
if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tystore,
|
|
|
|
mt.ty)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llty = type_of(cx.fcx.lcx.ccx, mt.ty);
|
2011-04-07 15:09:45 -07:00
|
|
|
v1 = cx.build.PointerCast(body, T_ptr(llty));
|
|
|
|
} else {
|
|
|
|
v1 = body;
|
|
|
|
}
|
|
|
|
|
2011-04-12 12:06:20 -07:00
|
|
|
v1 = load_if_immediate(cx, v1, t1);
|
2011-01-24 18:03:31 -08:00
|
|
|
}
|
|
|
|
case (_) {
|
|
|
|
ret res(cx, v1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
fn autoderefed_ty(@crate_ctxt ccx, ty.t t) -> ty.t {
|
2011-04-22 12:27:28 -07:00
|
|
|
let ty.t t1 = t;
|
2011-02-28 16:36:08 -08:00
|
|
|
|
|
|
|
while (true) {
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(ccx.tystore, t1)) {
|
2011-03-17 17:39:47 -07:00
|
|
|
case (ty.ty_box(?mt)) {
|
|
|
|
t1 = mt.ty;
|
2011-02-28 16:36:08 -08:00
|
|
|
}
|
|
|
|
case (_) {
|
|
|
|
ret t1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
fn trans_binary(@block_ctxt cx, ast.binop op,
|
|
|
|
@ast.expr a, @ast.expr b) -> result {
|
2010-10-04 15:55:12 -07:00
|
|
|
|
2010-10-19 17:24:15 -07:00
|
|
|
// First couple cases are lazy:
|
|
|
|
|
|
|
|
alt (op) {
|
|
|
|
case (ast.and) {
|
|
|
|
// Lazy-eval and
|
|
|
|
auto lhs_res = trans_expr(cx, a);
|
2011-04-20 18:52:04 -07:00
|
|
|
lhs_res = autoderef(lhs_res.bcx, lhs_res.val,
|
|
|
|
ty.expr_ty(cx.fcx.lcx.ccx.tystore, a));
|
2010-10-19 17:24:15 -07:00
|
|
|
|
2010-12-10 15:26:47 -08:00
|
|
|
auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
|
2010-10-19 17:24:15 -07:00
|
|
|
auto rhs_res = trans_expr(rhs_cx, b);
|
2011-04-20 18:52:04 -07:00
|
|
|
rhs_res = autoderef(rhs_res.bcx, rhs_res.val,
|
|
|
|
ty.expr_ty(cx.fcx.lcx.ccx.tystore, b));
|
2010-10-19 17:24:15 -07:00
|
|
|
|
2010-12-10 15:26:47 -08:00
|
|
|
auto lhs_false_cx = new_scope_block_ctxt(cx, "lhs false");
|
2010-11-12 14:51:11 -08:00
|
|
|
auto lhs_false_res = res(lhs_false_cx, C_bool(false));
|
2010-10-19 17:24:15 -07:00
|
|
|
|
|
|
|
lhs_res.bcx.build.CondBr(lhs_res.val,
|
|
|
|
rhs_cx.llbb,
|
2010-11-12 14:51:11 -08:00
|
|
|
lhs_false_cx.llbb);
|
|
|
|
|
|
|
|
ret join_results(cx, T_bool(),
|
|
|
|
vec(lhs_false_res, rhs_res));
|
2010-10-19 17:24:15 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
case (ast.or) {
|
|
|
|
// Lazy-eval or
|
|
|
|
auto lhs_res = trans_expr(cx, a);
|
2011-04-20 18:52:04 -07:00
|
|
|
lhs_res = autoderef(lhs_res.bcx, lhs_res.val,
|
|
|
|
ty.expr_ty(cx.fcx.lcx.ccx.tystore, a));
|
2010-10-19 17:24:15 -07:00
|
|
|
|
2010-12-10 15:26:47 -08:00
|
|
|
auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
|
2010-10-19 17:24:15 -07:00
|
|
|
auto rhs_res = trans_expr(rhs_cx, b);
|
2011-04-20 18:52:04 -07:00
|
|
|
rhs_res = autoderef(rhs_res.bcx, rhs_res.val,
|
|
|
|
ty.expr_ty(cx.fcx.lcx.ccx.tystore, b));
|
2010-10-19 17:24:15 -07:00
|
|
|
|
2010-12-10 15:26:47 -08:00
|
|
|
auto lhs_true_cx = new_scope_block_ctxt(cx, "lhs true");
|
2010-11-12 14:51:11 -08:00
|
|
|
auto lhs_true_res = res(lhs_true_cx, C_bool(true));
|
2010-10-19 17:24:15 -07:00
|
|
|
|
|
|
|
lhs_res.bcx.build.CondBr(lhs_res.val,
|
2010-11-12 14:51:11 -08:00
|
|
|
lhs_true_cx.llbb,
|
2010-10-19 17:24:15 -07:00
|
|
|
rhs_cx.llbb);
|
2010-11-12 14:51:11 -08:00
|
|
|
|
|
|
|
ret join_results(cx, T_bool(),
|
|
|
|
vec(lhs_true_res, rhs_res));
|
2010-10-19 17:24:15 -07:00
|
|
|
}
|
2010-12-01 17:08:46 -08:00
|
|
|
|
|
|
|
case (_) {
|
2010-12-08 14:50:47 -08:00
|
|
|
// Remaining cases are eager:
|
|
|
|
auto lhs = trans_expr(cx, a);
|
2011-04-20 18:52:04 -07:00
|
|
|
auto lhty = ty.expr_ty(cx.fcx.lcx.ccx.tystore, a);
|
2011-02-13 00:49:04 -05:00
|
|
|
lhs = autoderef(lhs.bcx, lhs.val, lhty);
|
2011-01-24 18:03:31 -08:00
|
|
|
auto rhs = trans_expr(lhs.bcx, b);
|
2011-04-20 18:52:04 -07:00
|
|
|
auto rhty = ty.expr_ty(cx.fcx.lcx.ccx.tystore, b);
|
2011-02-13 00:49:04 -05:00
|
|
|
rhs = autoderef(rhs.bcx, rhs.val, rhty);
|
2011-02-28 16:36:08 -08:00
|
|
|
ret trans_eager_binop(rhs.bcx, op,
|
2011-04-22 17:00:46 -07:00
|
|
|
autoderefed_ty(cx.fcx.lcx.ccx, lhty), lhs.val, rhs.val);
|
2010-12-01 17:08:46 -08:00
|
|
|
}
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
|
|
|
fail;
|
|
|
|
}
|
|
|
|
|
2010-11-12 14:51:11 -08:00
|
|
|
fn join_results(@block_ctxt parent_cx,
|
|
|
|
TypeRef t,
|
|
|
|
vec[result] ins)
|
|
|
|
-> result {
|
|
|
|
|
|
|
|
let vec[result] live = vec();
|
|
|
|
let vec[ValueRef] vals = vec();
|
|
|
|
let vec[BasicBlockRef] bbs = vec();
|
|
|
|
|
|
|
|
for (result r in ins) {
|
|
|
|
if (! is_terminated(r.bcx)) {
|
2011-03-16 14:58:02 -07:00
|
|
|
live += vec(r);
|
|
|
|
vals += vec(r.val);
|
|
|
|
bbs += vec(r.bcx.llbb);
|
2010-11-12 14:51:11 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
alt (_vec.len[result](live)) {
|
|
|
|
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.
|
|
|
|
check (_vec.len[result](ins) >= 1u);
|
|
|
|
ret ins.(0);
|
|
|
|
}
|
|
|
|
|
2010-12-01 17:08:46 -08:00
|
|
|
case (_) { /* fall through */ }
|
2010-11-12 14:51:11 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// We have >1 incoming edges. Make a join block and br+phi them into it.
|
|
|
|
auto join_cx = new_sub_block_ctxt(parent_cx, "join");
|
|
|
|
for (result r in live) {
|
|
|
|
r.bcx.build.Br(join_cx.llbb);
|
|
|
|
}
|
|
|
|
auto phi = join_cx.build.Phi(t, vals, bbs);
|
|
|
|
ret res(join_cx, phi);
|
|
|
|
}
|
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
fn trans_if(@block_ctxt cx, @ast.expr cond,
|
2011-01-31 23:06:02 -05:00
|
|
|
&ast.block thn, &option.t[@ast.expr] els) -> result {
|
2010-10-04 15:55:12 -07:00
|
|
|
|
|
|
|
auto cond_res = trans_expr(cx, cond);
|
|
|
|
|
2010-12-02 19:12:34 -08:00
|
|
|
auto then_cx = new_scope_block_ctxt(cx, "then");
|
2010-10-04 15:55:12 -07:00
|
|
|
auto then_res = trans_block(then_cx, thn);
|
|
|
|
|
2010-12-02 19:12:34 -08:00
|
|
|
auto else_cx = new_scope_block_ctxt(cx, "else");
|
2010-10-04 15:55:12 -07:00
|
|
|
|
2011-03-27 16:29:21 -04:00
|
|
|
auto else_res;
|
|
|
|
auto expr_llty;
|
2010-10-04 15:55:12 -07:00
|
|
|
alt (els) {
|
2011-01-31 23:06:02 -05:00
|
|
|
case (some[@ast.expr](?elexpr)) {
|
2011-03-31 00:46:26 -04:00
|
|
|
alt (elexpr.node) {
|
|
|
|
case (ast.expr_if(_, _, _, _)) {
|
|
|
|
else_res = trans_expr(else_cx, elexpr);
|
|
|
|
}
|
|
|
|
case (ast.expr_block(?blk, _)) {
|
|
|
|
// 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
|
|
|
|
else_res = trans_block(else_cx, blk);
|
|
|
|
}
|
|
|
|
}
|
2011-03-27 16:29:21 -04:00
|
|
|
|
|
|
|
// If we have an else expression, then the entire
|
|
|
|
// if expression can have a non-nil type.
|
2011-04-02 19:12:00 -04:00
|
|
|
// FIXME: This isn't quite right, particularly re: dynamic types
|
2011-04-20 18:52:04 -07:00
|
|
|
auto expr_ty = ty.expr_ty(cx.fcx.lcx.ccx.tystore, elexpr);
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tystore, expr_ty)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
expr_llty = T_typaram_ptr(cx.fcx.lcx.ccx.tn);
|
2011-03-27 20:20:12 -04:00
|
|
|
} else {
|
2011-04-17 14:24:45 +02:00
|
|
|
expr_llty = type_of(else_res.bcx.fcx.lcx.ccx, expr_ty);
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_is_structural(cx.fcx.lcx.ccx.tystore, expr_ty)) {
|
2011-03-27 20:20:12 -04:00
|
|
|
expr_llty = T_ptr(expr_llty);
|
|
|
|
}
|
2011-03-27 18:51:25 -04:00
|
|
|
}
|
2011-03-27 16:29:21 -04:00
|
|
|
}
|
|
|
|
case (_) {
|
|
|
|
else_res = res(else_cx, C_nil());
|
|
|
|
expr_llty = T_nil();
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-12 14:51:11 -08:00
|
|
|
cond_res.bcx.build.CondBr(cond_res.val,
|
2010-12-09 12:32:16 -08:00
|
|
|
then_cx.llbb,
|
|
|
|
else_cx.llbb);
|
2010-11-12 14:51:11 -08:00
|
|
|
|
2011-03-27 16:29:21 -04:00
|
|
|
ret join_results(cx, expr_llty,
|
2010-11-12 14:51:11 -08:00
|
|
|
vec(then_res, else_res));
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
|
|
|
|
2011-01-21 07:59:06 -08:00
|
|
|
fn trans_for(@block_ctxt cx,
|
|
|
|
@ast.decl decl,
|
|
|
|
@ast.expr seq,
|
|
|
|
&ast.block body) -> result {
|
|
|
|
fn inner(@block_ctxt cx,
|
|
|
|
@ast.local local, ValueRef curr,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t t, ast.block body,
|
2011-03-25 16:28:16 +01:00
|
|
|
@block_ctxt outer_next_cx) -> result {
|
2011-01-21 07:59:06 -08:00
|
|
|
|
|
|
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
2011-03-25 16:28:16 +01:00
|
|
|
auto scope_cx =
|
|
|
|
new_loop_scope_block_ctxt(cx, option.some[@block_ctxt](next_cx),
|
|
|
|
outer_next_cx, "for loop scope");
|
2011-01-21 07:59:06 -08:00
|
|
|
|
|
|
|
cx.build.Br(scope_cx.llbb);
|
|
|
|
auto local_res = alloc_local(scope_cx, local);
|
2011-01-24 15:26:10 -08:00
|
|
|
auto bcx = copy_ty(local_res.bcx, INIT, local_res.val, curr, t).bcx;
|
2011-03-16 14:58:02 -07:00
|
|
|
scope_cx.cleanups +=
|
|
|
|
vec(clean(bind drop_slot(_, local_res.val, t)));
|
2011-01-21 08:25:13 -08:00
|
|
|
bcx = trans_block(bcx, body).bcx;
|
2011-01-21 07:59:06 -08:00
|
|
|
bcx.build.Br(next_cx.llbb);
|
|
|
|
ret res(next_cx, C_nil());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let @ast.local local;
|
|
|
|
alt (decl.node) {
|
|
|
|
case (ast.decl_local(?loc)) {
|
|
|
|
local = loc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-25 16:28:16 +01:00
|
|
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
2011-04-20 18:52:04 -07:00
|
|
|
auto seq_ty = ty.expr_ty(cx.fcx.lcx.ccx.tystore, seq);
|
2011-01-21 07:59:06 -08:00
|
|
|
auto seq_res = trans_expr(cx, seq);
|
2011-03-25 16:28:16 +01:00
|
|
|
auto it = iter_sequence(seq_res.bcx, seq_res.val, seq_ty,
|
|
|
|
bind inner(_, local, _, _, body, next_cx));
|
|
|
|
it.bcx.build.Br(next_cx.llbb);
|
|
|
|
ret res(next_cx, it.val);
|
2011-01-21 07:59:06 -08:00
|
|
|
}
|
|
|
|
|
2011-03-10 16:49:00 -08:00
|
|
|
|
|
|
|
// 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.
|
|
|
|
fn collect_upvars(@block_ctxt cx, &ast.block bloc, &ast.def_id initial_decl)
|
2011-04-01 16:04:22 -07:00
|
|
|
-> vec[ast.def_id] {
|
2011-03-10 16:49:00 -08:00
|
|
|
type env = @rec(
|
2011-04-01 16:04:22 -07:00
|
|
|
mutable vec[ast.def_id] refs,
|
|
|
|
hashmap[ast.def_id,()] decls
|
|
|
|
);
|
2011-03-10 16:49:00 -08:00
|
|
|
|
2011-04-20 12:35:07 +02:00
|
|
|
fn walk_expr(env e, @ast.expr expr) {
|
|
|
|
alt (expr.node) {
|
|
|
|
case (ast.expr_path(?path, ?d, _)) {
|
|
|
|
alt (option.get[ast.def](d)) {
|
|
|
|
case (ast.def_arg(?did)) {
|
|
|
|
_vec.push[ast.def_id](e.refs, did);
|
|
|
|
}
|
|
|
|
case (ast.def_local(?did)) {
|
|
|
|
_vec.push[ast.def_id](e.refs, did);
|
|
|
|
}
|
|
|
|
case (ast.def_upvar(?did)) {
|
|
|
|
_vec.push[ast.def_id](e.refs, did);
|
|
|
|
}
|
|
|
|
case (_) {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case (_) {}
|
2011-03-10 16:49:00 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-20 12:35:07 +02:00
|
|
|
fn walk_decl(env e, @ast.decl decl) {
|
|
|
|
alt (decl.node) {
|
|
|
|
case (ast.decl_local(?local)) {
|
|
|
|
e.decls.insert(local.id, ());
|
|
|
|
}
|
|
|
|
case (_) {}
|
|
|
|
}
|
2011-03-10 16:49:00 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
let vec[ast.def_id] refs = vec();
|
|
|
|
let hashmap[ast.def_id,()] decls = new_def_hash[()]();
|
|
|
|
decls.insert(initial_decl, ());
|
|
|
|
let env e = @rec(mutable refs=refs, decls=decls);
|
|
|
|
|
2011-04-20 12:35:07 +02:00
|
|
|
auto visitor = @rec(visit_decl_pre = bind walk_decl(e, _),
|
|
|
|
visit_expr_pre = bind walk_expr(e, _)
|
|
|
|
with walk.default_visitor());
|
|
|
|
walk.walk_block(*visitor, bloc);
|
2011-03-10 16:49:00 -08:00
|
|
|
|
|
|
|
// Calculate (refs - decls). This is the set of captured upvars.
|
|
|
|
let vec[ast.def_id] result = vec();
|
|
|
|
for (ast.def_id ref_id in e.refs) {
|
|
|
|
if (!decls.contains_key(ref_id)) {
|
|
|
|
result += vec(ref_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret result;
|
|
|
|
}
|
|
|
|
|
2011-02-14 18:17:31 -08:00
|
|
|
fn trans_for_each(@block_ctxt cx,
|
|
|
|
@ast.decl decl,
|
|
|
|
@ast.expr seq,
|
|
|
|
&ast.block body) -> result {
|
2011-02-17 12:20:55 -08:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
|
2011-04-20 17:23:45 +02:00
|
|
|
auto lcx = cx.fcx.lcx;
|
2011-02-17 12:20:55 -08:00
|
|
|
// FIXME: possibly support alias-mode here?
|
2011-04-20 18:52:04 -07:00
|
|
|
auto decl_ty = ty.mk_nil(lcx.ccx.tystore);
|
2011-03-10 16:49:00 -08:00
|
|
|
auto decl_id;
|
2011-02-17 12:20:55 -08:00
|
|
|
alt (decl.node) {
|
|
|
|
case (ast.decl_local(?local)) {
|
2011-04-20 17:23:45 +02:00
|
|
|
decl_ty = node_ann_type(lcx.ccx, local.ann);
|
2011-03-10 16:49:00 -08:00
|
|
|
decl_id = local.id;
|
2011-02-17 12:20:55 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-10 16:49:00 -08:00
|
|
|
auto upvars = collect_upvars(cx, body, decl_id);
|
2011-03-11 12:02:51 -08:00
|
|
|
auto upvar_count = _vec.len[ast.def_id](upvars);
|
|
|
|
|
|
|
|
auto llbindingsptr;
|
|
|
|
if (upvar_count > 0u) {
|
|
|
|
// Gather up the upvars.
|
|
|
|
let vec[ValueRef] llbindings = vec();
|
|
|
|
let vec[TypeRef] llbindingtys = vec();
|
|
|
|
for (ast.def_id did in upvars) {
|
|
|
|
auto llbinding;
|
|
|
|
alt (cx.fcx.lllocals.find(did)) {
|
|
|
|
case (none[ValueRef]) {
|
2011-03-19 14:26:12 -07:00
|
|
|
alt (cx.fcx.llupvars.find(did)) {
|
|
|
|
case (none[ValueRef]) {
|
|
|
|
llbinding = cx.fcx.llargs.get(did);
|
|
|
|
}
|
|
|
|
case (some[ValueRef](?llval)) { llbinding = llval; }
|
|
|
|
}
|
2011-03-11 12:02:51 -08:00
|
|
|
}
|
|
|
|
case (some[ValueRef](?llval)) { llbinding = llval; }
|
|
|
|
}
|
|
|
|
llbindings += vec(llbinding);
|
|
|
|
llbindingtys += vec(val_ty(llbinding));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create an array of bindings and copy in aliases to the upvars.
|
2011-03-28 18:04:52 -07:00
|
|
|
llbindingsptr = alloca(cx, T_struct(llbindingtys));
|
2011-03-11 12:02:51 -08:00
|
|
|
auto i = 0u;
|
|
|
|
while (i < upvar_count) {
|
|
|
|
auto llbindingptr = cx.build.GEP(llbindingsptr,
|
|
|
|
vec(C_int(0), C_int(i as int)));
|
|
|
|
cx.build.Store(llbindings.(i), llbindingptr);
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Null bindings.
|
|
|
|
llbindingsptr = C_null(T_ptr(T_i8()));
|
2011-03-10 16:49:00 -08:00
|
|
|
}
|
|
|
|
|
2011-03-11 12:02:51 -08:00
|
|
|
// Create an environment and populate it with the bindings.
|
2011-04-15 18:14:29 -07:00
|
|
|
auto tydesc_count = _vec.len[ValueRef](cx.fcx.lltydescs);
|
2011-04-20 17:23:45 +02:00
|
|
|
auto llenvptrty = T_closure_ptr(lcx.ccx.tn, T_ptr(T_nil()),
|
2011-04-15 18:14:29 -07:00
|
|
|
val_ty(llbindingsptr), tydesc_count);
|
2011-03-28 18:04:52 -07:00
|
|
|
auto llenvptr = alloca(cx, llvm.LLVMGetElementType(llenvptrty));
|
2011-03-11 12:02:51 -08:00
|
|
|
|
|
|
|
auto llbindingsptrptr = cx.build.GEP(llenvptr,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.box_rc_field_body),
|
|
|
|
C_int(2)));
|
|
|
|
cx.build.Store(llbindingsptr, llbindingsptrptr);
|
2011-03-10 16:49:00 -08:00
|
|
|
|
2011-04-15 18:14:29 -07:00
|
|
|
// Copy in our type descriptors, in case the iterator body needs to refer
|
|
|
|
// to them.
|
|
|
|
auto lltydescsptr = cx.build.GEP(llenvptr,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.box_rc_field_body),
|
|
|
|
C_int(3)));
|
|
|
|
auto i = 0u;
|
|
|
|
while (i < tydesc_count) {
|
|
|
|
auto lltydescptr = cx.build.GEP(lltydescsptr,
|
|
|
|
vec(C_int(0), C_int(i as int)));
|
|
|
|
cx.build.Store(cx.fcx.lltydescs.(i), lltydescptr);
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
|
2011-03-10 16:49:00 -08:00
|
|
|
// Step 2: Declare foreach body function.
|
|
|
|
|
2011-04-20 17:23:45 +02:00
|
|
|
let str s = mangle_name_by_seq(lcx.ccx, lcx.path, "foreach");
|
2011-02-17 12:20:55 -08:00
|
|
|
|
|
|
|
// 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.
|
|
|
|
|
2011-04-23 14:17:44 -07:00
|
|
|
auto iter_body_llty =
|
|
|
|
type_of_fn_full(lcx.ccx, ast.proto_fn,
|
|
|
|
none[TypeRef],
|
|
|
|
vec(rec(mode=ast.alias, ty=decl_ty)),
|
|
|
|
ty.mk_nil(lcx.ccx.tystore), 0u);
|
2011-02-17 12:20:55 -08:00
|
|
|
|
2011-04-20 17:23:45 +02:00
|
|
|
let ValueRef lliterbody = decl_internal_fastcall_fn(lcx.ccx.llmod,
|
2011-04-01 16:04:22 -07:00
|
|
|
s, iter_body_llty);
|
2011-02-17 12:20:55 -08:00
|
|
|
|
2011-04-20 17:23:45 +02:00
|
|
|
auto fcx = new_fn_ctxt(lcx, lliterbody);
|
2011-02-17 12:20:55 -08:00
|
|
|
auto bcx = new_top_block_ctxt(fcx);
|
2011-03-28 18:04:52 -07:00
|
|
|
auto lltop = bcx.llbb;
|
2011-02-17 12:20:55 -08:00
|
|
|
|
2011-03-11 12:02:51 -08:00
|
|
|
// Populate the upvars from the environment.
|
|
|
|
auto llremoteenvptr = bcx.build.PointerCast(fcx.llenv, llenvptrty);
|
|
|
|
auto llremotebindingsptrptr = bcx.build.GEP(llremoteenvptr,
|
2011-04-01 16:04:22 -07:00
|
|
|
vec(C_int(0), C_int(abi.box_rc_field_body), C_int(2)));
|
2011-03-11 12:02:51 -08:00
|
|
|
auto llremotebindingsptr = bcx.build.Load(llremotebindingsptrptr);
|
|
|
|
|
2011-04-15 18:14:29 -07:00
|
|
|
i = 0u;
|
2011-03-11 12:02:51 -08:00
|
|
|
while (i < upvar_count) {
|
|
|
|
auto upvar_id = upvars.(i);
|
|
|
|
auto llupvarptrptr = bcx.build.GEP(llremotebindingsptr,
|
|
|
|
vec(C_int(0), C_int(i as int)));
|
|
|
|
auto llupvarptr = bcx.build.Load(llupvarptrptr);
|
|
|
|
fcx.llupvars.insert(upvar_id, llupvarptr);
|
|
|
|
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
|
2011-04-15 18:14:29 -07:00
|
|
|
// Populate the type parameters from the environment.
|
|
|
|
auto llremotetydescsptr = bcx.build.GEP(llremoteenvptr,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.box_rc_field_body),
|
|
|
|
C_int(3)));
|
|
|
|
|
|
|
|
i = 0u;
|
|
|
|
while (i < tydesc_count) {
|
|
|
|
auto llremotetydescptr = bcx.build.GEP(llremotetydescsptr,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(i as int)));
|
|
|
|
auto llremotetydesc = bcx.build.Load(llremotetydescptr);
|
|
|
|
fcx.lltydescs += vec(llremotetydesc);
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
|
2011-04-23 14:17:44 -07:00
|
|
|
// Add an upvar for the loop variable alias.
|
|
|
|
fcx.llupvars.insert(decl_id, llvm.LLVMGetParam(fcx.llfn, 3u));
|
2011-03-11 12:02:51 -08:00
|
|
|
|
2011-04-19 16:52:59 -07:00
|
|
|
auto r = trans_block(bcx, body);
|
2011-03-28 18:04:52 -07:00
|
|
|
|
|
|
|
// Tie up the llallocas -> lltop edge.
|
|
|
|
new_builder(fcx.llallocas).Br(lltop);
|
|
|
|
|
2011-04-19 16:52:59 -07:00
|
|
|
r.bcx.build.RetVoid();
|
2011-02-17 12:20:55 -08:00
|
|
|
|
|
|
|
|
2011-02-18 17:30:57 -08:00
|
|
|
// Step 3: Call iter passing [lliterbody, llenv], plus other args.
|
2011-02-17 12:20:55 -08:00
|
|
|
|
|
|
|
alt (seq.node) {
|
2011-02-18 18:04:37 -08:00
|
|
|
|
2011-02-17 12:20:55 -08:00
|
|
|
case (ast.expr_call(?f, ?args, ?ann)) {
|
2011-02-18 17:30:57 -08:00
|
|
|
|
2011-04-20 17:23:45 +02:00
|
|
|
auto pair = alloca(cx, T_fn_pair(lcx.ccx.tn,
|
2011-03-28 18:04:52 -07:00
|
|
|
iter_body_llty));
|
2011-02-18 18:04:37 -08:00
|
|
|
auto code_cell = cx.build.GEP(pair,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.fn_field_code)));
|
|
|
|
cx.build.Store(lliterbody, code_cell);
|
|
|
|
|
2011-03-11 12:02:51 -08:00
|
|
|
auto env_cell = cx.build.GEP(pair, vec(C_int(0),
|
|
|
|
C_int(abi.fn_field_box)));
|
|
|
|
auto llenvblobptr = cx.build.PointerCast(llenvptr,
|
2011-04-20 17:23:45 +02:00
|
|
|
T_opaque_closure_ptr(lcx.ccx.tn));
|
2011-03-11 12:02:51 -08:00
|
|
|
cx.build.Store(llenvblobptr, env_cell);
|
|
|
|
|
2011-04-20 17:23:45 +02:00
|
|
|
// log "lliterbody: " + val_str(lcx.ccx.tn, lliterbody);
|
2011-04-19 16:52:59 -07:00
|
|
|
r = trans_call(cx, f,
|
2011-02-18 18:04:37 -08:00
|
|
|
some[ValueRef](cx.build.Load(pair)),
|
2011-02-18 17:30:57 -08:00
|
|
|
args,
|
|
|
|
ann);
|
2011-04-19 16:52:59 -07:00
|
|
|
ret res(r.bcx, C_nil());
|
2011-02-17 12:20:55 -08:00
|
|
|
}
|
|
|
|
}
|
2011-02-14 18:17:31 -08:00
|
|
|
fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
fn trans_while(@block_ctxt cx, @ast.expr cond,
|
|
|
|
&ast.block body) -> result {
|
2010-11-03 11:05:15 -07:00
|
|
|
|
2010-12-02 19:12:34 -08:00
|
|
|
auto cond_cx = new_scope_block_ctxt(cx, "while cond");
|
2010-11-10 17:46:49 -08:00
|
|
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
2011-03-25 16:28:16 +01:00
|
|
|
auto body_cx = new_loop_scope_block_ctxt(cx, option.none[@block_ctxt],
|
|
|
|
next_cx, "while loop body");
|
2010-11-03 11:05:15 -07:00
|
|
|
|
|
|
|
auto body_res = trans_block(body_cx, body);
|
2010-11-04 07:55:33 -07:00
|
|
|
auto cond_res = trans_expr(cond_cx, cond);
|
|
|
|
|
|
|
|
body_res.bcx.build.Br(cond_cx.llbb);
|
2011-03-10 11:27:51 -08:00
|
|
|
|
|
|
|
auto cond_bcx = trans_block_cleanups(cond_res.bcx, cond_cx);
|
|
|
|
cond_bcx.build.CondBr(cond_res.val, body_cx.llbb, next_cx.llbb);
|
2010-11-04 07:55:33 -07:00
|
|
|
|
|
|
|
cx.build.Br(cond_cx.llbb);
|
2010-11-03 11:05:15 -07:00
|
|
|
ret res(next_cx, C_nil());
|
|
|
|
}
|
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
fn trans_do_while(@block_ctxt cx, &ast.block body,
|
|
|
|
@ast.expr cond) -> result {
|
2010-11-03 11:05:15 -07:00
|
|
|
|
2010-11-10 17:46:49 -08:00
|
|
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
2011-03-25 16:28:16 +01:00
|
|
|
auto body_cx = new_loop_scope_block_ctxt(cx, option.none[@block_ctxt],
|
|
|
|
next_cx, "do-while loop body");
|
2010-11-03 11:05:15 -07:00
|
|
|
|
|
|
|
auto body_res = trans_block(body_cx, body);
|
2010-11-04 07:55:33 -07:00
|
|
|
auto cond_res = trans_expr(body_res.bcx, cond);
|
|
|
|
|
|
|
|
cond_res.bcx.build.CondBr(cond_res.val,
|
|
|
|
body_cx.llbb,
|
|
|
|
next_cx.llbb);
|
|
|
|
cx.build.Br(body_cx.llbb);
|
2010-11-03 11:05:15 -07:00
|
|
|
ret res(next_cx, body_res.val);
|
|
|
|
}
|
|
|
|
|
2010-12-15 09:38:23 -08:00
|
|
|
// Pattern matching translation
|
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
fn trans_pat_match(@block_ctxt cx, @ast.pat pat, ValueRef llval,
|
|
|
|
@block_ctxt next_cx) -> result {
|
2010-12-15 09:38:23 -08:00
|
|
|
alt (pat.node) {
|
|
|
|
case (ast.pat_wild(_)) { ret res(cx, llval); }
|
|
|
|
case (ast.pat_bind(_, _, _)) { ret res(cx, llval); }
|
2011-02-10 19:40:02 -08:00
|
|
|
|
|
|
|
case (ast.pat_lit(?lt, ?ann)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto lllit = trans_lit(cx.fcx.lcx.ccx, *lt, ann);
|
2011-02-13 00:49:04 -05:00
|
|
|
auto lltype = ty.ann_to_type(ann);
|
|
|
|
auto lleq = trans_compare(cx, ast.eq, lltype, llval, lllit);
|
2011-02-10 19:40:02 -08:00
|
|
|
|
2011-02-28 16:36:08 -08:00
|
|
|
auto matched_cx = new_sub_block_ctxt(lleq.bcx, "matched_cx");
|
|
|
|
lleq.bcx.build.CondBr(lleq.val, matched_cx.llbb, next_cx.llbb);
|
2011-02-10 19:40:02 -08:00
|
|
|
ret res(matched_cx, llval);
|
|
|
|
}
|
|
|
|
|
2010-12-15 09:38:23 -08:00
|
|
|
case (ast.pat_tag(?id, ?subpats, ?vdef_opt, ?ann)) {
|
2011-03-09 15:17:06 -08:00
|
|
|
auto lltagptr = cx.build.PointerCast(llval,
|
2011-04-17 14:24:45 +02:00
|
|
|
T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn));
|
2011-03-09 15:17:06 -08:00
|
|
|
|
|
|
|
auto lldiscrimptr = cx.build.GEP(lltagptr,
|
|
|
|
vec(C_int(0), C_int(0)));
|
2011-03-09 14:29:00 -08:00
|
|
|
auto lldiscrim = cx.build.Load(lldiscrimptr);
|
2010-12-20 16:23:49 -08:00
|
|
|
|
2010-12-15 09:38:23 -08:00
|
|
|
auto vdef = option.get[ast.variant_def](vdef_opt);
|
|
|
|
auto variant_id = vdef._1;
|
|
|
|
auto variant_tag = 0;
|
2011-02-25 18:16:50 -08:00
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
auto variants = tag_variants(cx.fcx.lcx.ccx, vdef._0);
|
2010-12-15 09:38:23 -08:00
|
|
|
auto i = 0;
|
2011-04-01 11:36:52 -07:00
|
|
|
for (variant_info v in variants) {
|
|
|
|
auto this_variant_id = v.id;
|
2010-12-15 09:38:23 -08:00
|
|
|
if (variant_id._0 == this_variant_id._0 &&
|
2011-01-21 07:50:02 -08:00
|
|
|
variant_id._1 == this_variant_id._1) {
|
2010-12-15 09:38:23 -08:00
|
|
|
variant_tag = i;
|
|
|
|
}
|
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto matched_cx = new_sub_block_ctxt(cx, "matched_cx");
|
|
|
|
|
2011-03-09 14:29:00 -08:00
|
|
|
auto lleq = cx.build.ICmp(lib.llvm.LLVMIntEQ, lldiscrim,
|
2010-12-15 09:38:23 -08:00
|
|
|
C_int(variant_tag));
|
|
|
|
cx.build.CondBr(lleq, matched_cx.llbb, next_cx.llbb);
|
|
|
|
|
2011-03-09 17:48:07 -08:00
|
|
|
auto ty_params = node_ann_ty_params(ann);
|
|
|
|
|
2010-12-15 09:38:23 -08:00
|
|
|
if (_vec.len[@ast.pat](subpats) > 0u) {
|
2011-03-09 15:17:06 -08:00
|
|
|
auto llblobptr = matched_cx.build.GEP(lltagptr,
|
2011-04-01 16:04:22 -07:00
|
|
|
vec(C_int(0), C_int(1)));
|
2010-12-15 09:38:23 -08:00
|
|
|
auto i = 0;
|
|
|
|
for (@ast.pat subpat in subpats) {
|
2011-03-09 17:48:07 -08:00
|
|
|
auto rslt = GEP_tag(matched_cx, llblobptr, vdef._0,
|
|
|
|
vdef._1, ty_params, i);
|
2011-03-09 15:17:06 -08:00
|
|
|
auto llsubvalptr = rslt.val;
|
|
|
|
matched_cx = rslt.bcx;
|
|
|
|
|
2011-04-12 12:06:20 -07:00
|
|
|
auto llsubval = load_if_immediate(matched_cx,
|
2011-04-20 18:52:04 -07:00
|
|
|
llsubvalptr, pat_ty(cx.fcx.lcx.ccx.tystore, subpat));
|
2010-12-15 09:38:23 -08:00
|
|
|
auto subpat_res = trans_pat_match(matched_cx, subpat,
|
|
|
|
llsubval, next_cx);
|
|
|
|
matched_cx = subpat_res.bcx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret res(matched_cx, llval);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fail;
|
|
|
|
}
|
|
|
|
|
2011-04-25 03:59:35 +00:00
|
|
|
fn trans_pat_binding(@block_ctxt cx, @ast.pat pat,
|
|
|
|
ValueRef llval, bool bind_alias)
|
2011-01-21 07:58:16 -08:00
|
|
|
-> result {
|
2010-12-15 09:38:23 -08:00
|
|
|
alt (pat.node) {
|
|
|
|
case (ast.pat_wild(_)) { ret res(cx, llval); }
|
2011-02-10 19:40:02 -08:00
|
|
|
case (ast.pat_lit(_, _)) { ret res(cx, llval); }
|
2010-12-15 09:38:23 -08:00
|
|
|
case (ast.pat_bind(?id, ?def_id, ?ann)) {
|
2011-04-25 03:59:35 +00:00
|
|
|
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;
|
|
|
|
llvm.LLVMSetValueName(dst, _str.buf(id));
|
|
|
|
bcx.fcx.lllocals.insert(def_id, dst);
|
|
|
|
bcx.cleanups +=
|
|
|
|
vec(clean(bind drop_slot(_, dst, t)));
|
|
|
|
ret copy_ty(bcx, INIT, dst, llval, t);
|
|
|
|
}
|
2010-12-15 09:38:23 -08:00
|
|
|
}
|
2011-03-09 17:48:07 -08:00
|
|
|
case (ast.pat_tag(_, ?subpats, ?vdef_opt, ?ann)) {
|
2010-12-15 09:38:23 -08:00
|
|
|
if (_vec.len[@ast.pat](subpats) == 0u) { ret res(cx, llval); }
|
|
|
|
|
2011-03-09 15:17:06 -08:00
|
|
|
// Get the appropriate variant for this tag.
|
|
|
|
auto vdef = option.get[ast.variant_def](vdef_opt);
|
|
|
|
|
|
|
|
auto lltagptr = cx.build.PointerCast(llval,
|
2011-04-17 14:24:45 +02:00
|
|
|
T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn));
|
2011-03-09 15:17:06 -08:00
|
|
|
auto llblobptr = cx.build.GEP(lltagptr, vec(C_int(0), C_int(1)));
|
2010-12-15 09:38:23 -08:00
|
|
|
|
2011-03-09 17:48:07 -08:00
|
|
|
auto ty_param_substs = node_ann_ty_params(ann);
|
|
|
|
|
2010-12-15 09:38:23 -08:00
|
|
|
auto this_cx = cx;
|
|
|
|
auto i = 0;
|
|
|
|
for (@ast.pat subpat in subpats) {
|
2011-03-09 17:48:07 -08:00
|
|
|
auto rslt = GEP_tag(this_cx, llblobptr, vdef._0, vdef._1,
|
|
|
|
ty_param_substs, i);
|
2011-03-09 15:17:06 -08:00
|
|
|
this_cx = rslt.bcx;
|
2010-12-15 09:38:23 -08:00
|
|
|
auto subpat_res = trans_pat_binding(this_cx, subpat,
|
2011-04-25 03:59:35 +00:00
|
|
|
rslt.val, true);
|
2010-12-15 09:38:23 -08:00
|
|
|
this_cx = subpat_res.bcx;
|
2010-12-15 10:11:33 -08:00
|
|
|
i += 1;
|
2010-12-15 09:38:23 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
ret res(this_cx, llval);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-02 19:06:19 -04:00
|
|
|
fn trans_alt(@block_ctxt cx, @ast.expr expr,
|
|
|
|
vec[ast.arm] arms, ast.ann ann) -> result {
|
2010-12-15 09:38:23 -08:00
|
|
|
auto expr_res = trans_expr(cx, expr);
|
|
|
|
|
|
|
|
auto this_cx = expr_res.bcx;
|
2011-04-02 19:06:19 -04:00
|
|
|
let vec[result] arm_results = vec();
|
2010-12-15 09:38:23 -08:00
|
|
|
for (ast.arm arm in arms) {
|
|
|
|
auto next_cx = new_sub_block_ctxt(expr_res.bcx, "next");
|
|
|
|
auto match_res = trans_pat_match(this_cx, arm.pat, expr_res.val,
|
|
|
|
next_cx);
|
|
|
|
|
|
|
|
auto binding_cx = new_scope_block_ctxt(match_res.bcx, "binding");
|
|
|
|
match_res.bcx.build.Br(binding_cx.llbb);
|
|
|
|
|
|
|
|
auto binding_res = trans_pat_binding(binding_cx, arm.pat,
|
2011-04-25 03:59:35 +00:00
|
|
|
expr_res.val, false);
|
2010-12-15 09:38:23 -08:00
|
|
|
|
|
|
|
auto block_res = trans_block(binding_res.bcx, arm.block);
|
2011-04-02 19:06:19 -04:00
|
|
|
arm_results += vec(block_res);
|
2010-12-15 09:38:23 -08:00
|
|
|
|
|
|
|
this_cx = next_cx;
|
|
|
|
}
|
|
|
|
|
2011-04-02 14:12:19 -04:00
|
|
|
auto default_cx = this_cx;
|
2011-04-19 15:22:57 -07:00
|
|
|
auto default_res = trans_fail(default_cx, some[common.span](expr.span),
|
2011-04-02 14:12:19 -04:00
|
|
|
"non-exhaustive match failure");
|
2010-12-15 09:38:23 -08:00
|
|
|
|
2011-04-02 19:12:00 -04:00
|
|
|
// FIXME: This isn't quite right, particularly re: dynamic types
|
2011-04-02 19:06:19 -04:00
|
|
|
auto expr_ty = ty.ann_to_type(ann);
|
|
|
|
auto expr_llty;
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tystore, expr_ty)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
expr_llty = T_typaram_ptr(cx.fcx.lcx.ccx.tn);
|
2011-04-02 19:06:19 -04:00
|
|
|
} else {
|
2011-04-17 14:24:45 +02:00
|
|
|
expr_llty = type_of(cx.fcx.lcx.ccx, expr_ty);
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_is_structural(cx.fcx.lcx.ccx.tystore, expr_ty)) {
|
2011-04-02 19:06:19 -04:00
|
|
|
expr_llty = T_ptr(expr_llty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret join_results(cx, expr_llty, arm_results);
|
2010-12-15 09:38:23 -08:00
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
type generic_info = rec(ty.t item_type,
|
2011-01-14 14:17:57 -08:00
|
|
|
vec[ValueRef] tydescs);
|
|
|
|
|
2010-12-23 17:31:16 -08:00
|
|
|
type lval_result = rec(result res,
|
|
|
|
bool is_mem,
|
2011-01-14 14:17:57 -08:00
|
|
|
option.t[generic_info] generic,
|
2011-04-05 16:17:47 -07:00
|
|
|
option.t[ValueRef] llobj,
|
2011-04-22 12:27:28 -07:00
|
|
|
option.t[ty.t] method_ty);
|
2010-12-23 17:31:16 -08:00
|
|
|
|
|
|
|
fn lval_mem(@block_ctxt cx, ValueRef val) -> lval_result {
|
|
|
|
ret rec(res=res(cx, val),
|
|
|
|
is_mem=true,
|
2011-01-14 14:17:57 -08:00
|
|
|
generic=none[generic_info],
|
2011-04-05 16:17:47 -07:00
|
|
|
llobj=none[ValueRef],
|
2011-04-22 12:27:28 -07:00
|
|
|
method_ty=none[ty.t]);
|
2010-12-23 17:31:16 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn lval_val(@block_ctxt cx, ValueRef val) -> lval_result {
|
|
|
|
ret rec(res=res(cx, val),
|
|
|
|
is_mem=false,
|
2011-01-14 14:17:57 -08:00
|
|
|
generic=none[generic_info],
|
2011-04-05 16:17:47 -07:00
|
|
|
llobj=none[ValueRef],
|
2011-04-22 12:27:28 -07:00
|
|
|
method_ty=none[ty.t]);
|
2010-12-23 17:31:16 -08:00
|
|
|
}
|
2010-10-21 18:13:57 -07:00
|
|
|
|
2011-03-30 18:15:29 -07:00
|
|
|
fn trans_external_path(@block_ctxt cx, ast.def_id did,
|
2011-04-12 15:09:50 -07:00
|
|
|
ty.ty_param_count_and_ty tpt) -> lval_result {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto lcx = cx.fcx.lcx;
|
|
|
|
auto name = creader.get_symbol(lcx.ccx.sess, did);
|
|
|
|
auto v = get_extern_const(lcx.ccx.externs, lcx.ccx.llmod,
|
|
|
|
name, type_of_ty_param_count_and_ty(lcx, tpt));
|
2011-03-30 18:15:29 -07:00
|
|
|
ret lval_val(cx, v);
|
|
|
|
}
|
|
|
|
|
2011-01-31 18:06:35 -08:00
|
|
|
fn lval_generic_fn(@block_ctxt cx,
|
2011-04-12 15:09:50 -07:00
|
|
|
ty.ty_param_count_and_ty tpt,
|
2011-01-31 18:06:35 -08:00
|
|
|
ast.def_id fn_id,
|
|
|
|
&ast.ann ann)
|
2011-04-01 16:04:22 -07:00
|
|
|
-> lval_result {
|
2011-03-30 18:15:29 -07:00
|
|
|
auto lv;
|
2011-04-17 14:24:45 +02:00
|
|
|
if (cx.fcx.lcx.ccx.sess.get_targ_crate_num() == fn_id._0) {
|
2011-03-30 18:15:29 -07:00
|
|
|
// Internal reference.
|
2011-04-17 14:24:45 +02:00
|
|
|
check (cx.fcx.lcx.ccx.fn_pairs.contains_key(fn_id));
|
|
|
|
lv = lval_val(cx, cx.fcx.lcx.ccx.fn_pairs.get(fn_id));
|
2011-03-30 18:15:29 -07:00
|
|
|
} else {
|
|
|
|
// External reference.
|
2011-04-12 15:09:50 -07:00
|
|
|
lv = trans_external_path(cx, fn_id, tpt);
|
2011-03-30 18:15:29 -07:00
|
|
|
}
|
2011-03-08 14:55:39 -08:00
|
|
|
|
|
|
|
auto monoty;
|
2011-04-22 12:27:28 -07:00
|
|
|
let vec[ty.t] tys;
|
2011-03-08 14:55:39 -08:00
|
|
|
alt (ann) {
|
|
|
|
case (ast.ann_none) {
|
2011-04-17 14:24:45 +02:00
|
|
|
cx.fcx.lcx.ccx.sess.bug("no type annotation for path!");
|
2011-03-08 14:55:39 -08:00
|
|
|
fail;
|
|
|
|
}
|
2011-03-24 12:12:04 -07:00
|
|
|
case (ast.ann_type(?monoty_, ?tps, _)) {
|
2011-03-08 14:55:39 -08:00
|
|
|
monoty = monoty_;
|
2011-04-22 12:27:28 -07:00
|
|
|
tys = option.get[vec[ty.t]](tps);
|
2011-03-08 14:55:39 -08:00
|
|
|
}
|
|
|
|
}
|
2011-01-31 18:06:35 -08:00
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
if (_vec.len[ty.t](tys) != 0u) {
|
2011-01-31 18:06:35 -08:00
|
|
|
auto bcx = cx;
|
|
|
|
let vec[ValueRef] tydescs = vec();
|
2011-04-22 12:27:28 -07:00
|
|
|
for (ty.t t in tys) {
|
2011-01-31 18:06:35 -08:00
|
|
|
auto td = get_tydesc(bcx, t);
|
|
|
|
bcx = td.bcx;
|
2011-03-16 14:58:02 -07:00
|
|
|
_vec.push[ValueRef](tydescs, td.val);
|
2011-01-31 18:06:35 -08:00
|
|
|
}
|
|
|
|
auto gen = rec( item_type = tpt._1,
|
|
|
|
tydescs = tydescs );
|
|
|
|
lv = rec(res = res(bcx, lv.res.val),
|
|
|
|
generic = some[generic_info](gen)
|
|
|
|
with lv);
|
|
|
|
}
|
|
|
|
ret lv;
|
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
fn lookup_discriminant(@local_ctxt lcx, ast.def_id tid, ast.def_id vid)
|
2011-04-07 11:42:40 -07:00
|
|
|
-> ValueRef {
|
2011-04-17 14:24:45 +02:00
|
|
|
alt (lcx.ccx.discrims.find(vid)) {
|
2011-04-07 11:42:40 -07:00
|
|
|
case (none[ValueRef]) {
|
|
|
|
// It's an external discriminant that we haven't seen yet.
|
2011-04-17 14:24:45 +02:00
|
|
|
check (lcx.ccx.sess.get_targ_crate_num() != vid._0);
|
|
|
|
auto sym = creader.get_symbol(lcx.ccx.sess, vid);
|
|
|
|
auto gvar = llvm.LLVMAddGlobal(lcx.ccx.llmod, T_int(),
|
|
|
|
_str.buf(sym));
|
2011-04-07 11:42:40 -07:00
|
|
|
llvm.LLVMSetLinkage(gvar,
|
|
|
|
lib.llvm.LLVMExternalLinkage as llvm.Linkage);
|
|
|
|
llvm.LLVMSetGlobalConstant(gvar, True);
|
2011-04-17 14:24:45 +02:00
|
|
|
lcx.ccx.discrims.insert(vid, gvar);
|
2011-04-07 11:42:40 -07:00
|
|
|
ret gvar;
|
|
|
|
}
|
|
|
|
case (some[ValueRef](?llval)) { ret llval; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-13 17:42:28 -08:00
|
|
|
fn trans_path(@block_ctxt cx, &ast.path p, &option.t[ast.def] dopt,
|
2011-01-21 07:50:02 -08:00
|
|
|
&ast.ann ann) -> lval_result {
|
2010-11-26 15:54:04 -08:00
|
|
|
alt (dopt) {
|
|
|
|
case (some[ast.def](?def)) {
|
|
|
|
alt (def) {
|
|
|
|
case (ast.def_arg(?did)) {
|
2011-03-19 14:26:12 -07:00
|
|
|
alt (cx.fcx.llargs.find(did)) {
|
|
|
|
case (none[ValueRef]) {
|
|
|
|
check (cx.fcx.llupvars.contains_key(did));
|
|
|
|
ret lval_mem(cx, cx.fcx.llupvars.get(did));
|
|
|
|
}
|
|
|
|
case (some[ValueRef](?llval)) {
|
|
|
|
ret lval_mem(cx, llval);
|
|
|
|
}
|
|
|
|
}
|
2010-11-26 15:54:04 -08:00
|
|
|
}
|
|
|
|
case (ast.def_local(?did)) {
|
2011-03-11 10:38:55 -08:00
|
|
|
alt (cx.fcx.lllocals.find(did)) {
|
|
|
|
case (none[ValueRef]) {
|
|
|
|
check (cx.fcx.llupvars.contains_key(did));
|
|
|
|
ret lval_mem(cx, cx.fcx.llupvars.get(did));
|
|
|
|
}
|
|
|
|
case (some[ValueRef](?llval)) {
|
|
|
|
ret lval_mem(cx, llval);
|
|
|
|
}
|
|
|
|
}
|
2010-10-19 16:33:11 -07:00
|
|
|
}
|
2010-12-15 09:38:23 -08:00
|
|
|
case (ast.def_binding(?did)) {
|
|
|
|
check (cx.fcx.lllocals.contains_key(did));
|
2010-12-23 17:31:16 -08:00
|
|
|
ret lval_mem(cx, cx.fcx.lllocals.get(did));
|
2010-12-15 09:38:23 -08:00
|
|
|
}
|
2010-12-30 17:01:20 -08:00
|
|
|
case (ast.def_obj_field(?did)) {
|
|
|
|
check (cx.fcx.llobjfields.contains_key(did));
|
|
|
|
ret lval_mem(cx, cx.fcx.llobjfields.get(did));
|
|
|
|
}
|
2010-11-26 15:54:04 -08:00
|
|
|
case (ast.def_fn(?did)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto tyt = ty.lookup_item_type(cx.fcx.lcx.ccx.sess,
|
2011-04-20 18:52:04 -07:00
|
|
|
cx.fcx.lcx.ccx.tystore,
|
2011-04-17 14:24:45 +02:00
|
|
|
cx.fcx.lcx.ccx.type_cache, did);
|
2011-03-30 17:23:25 -07:00
|
|
|
ret lval_generic_fn(cx, tyt, did, ann);
|
2010-11-26 15:54:04 -08:00
|
|
|
}
|
2010-12-16 10:23:47 -08:00
|
|
|
case (ast.def_obj(?did)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto tyt = ty.lookup_item_type(cx.fcx.lcx.ccx.sess,
|
2011-04-20 18:52:04 -07:00
|
|
|
cx.fcx.lcx.ccx.tystore,
|
2011-04-17 14:24:45 +02:00
|
|
|
cx.fcx.lcx.ccx.type_cache, did);
|
2011-03-30 17:23:25 -07:00
|
|
|
ret lval_generic_fn(cx, tyt, did, ann);
|
2010-12-16 10:23:47 -08:00
|
|
|
}
|
2010-12-01 19:03:47 -08:00
|
|
|
case (ast.def_variant(?tid, ?vid)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto v_tyt = ty.lookup_item_type(cx.fcx.lcx.ccx.sess,
|
2011-04-20 18:52:04 -07:00
|
|
|
cx.fcx.lcx.ccx.tystore,
|
2011-04-17 14:24:45 +02:00
|
|
|
cx.fcx.lcx.ccx.type_cache, vid);
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.fcx.lcx.ccx.tystore, v_tyt._1)) {
|
2011-04-07 11:42:40 -07:00
|
|
|
case (ty.ty_fn(_, _, _)) {
|
|
|
|
// N-ary variant.
|
|
|
|
ret lval_generic_fn(cx, v_tyt, vid, ann);
|
2011-03-18 18:45:49 -07:00
|
|
|
}
|
2011-04-07 11:42:40 -07:00
|
|
|
case (_) {
|
|
|
|
// Nullary variant.
|
2011-04-17 14:24:45 +02:00
|
|
|
auto tag_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
|
2011-04-07 11:42:40 -07:00
|
|
|
auto lldiscrim_gv =
|
2011-04-17 14:24:45 +02:00
|
|
|
lookup_discriminant(cx.fcx.lcx, tid, vid);
|
2011-04-07 11:42:40 -07:00
|
|
|
auto lldiscrim = cx.build.Load(lldiscrim_gv);
|
|
|
|
|
|
|
|
auto alloc_result = alloc_ty(cx, tag_ty);
|
|
|
|
auto lltagblob = alloc_result.val;
|
|
|
|
|
|
|
|
auto lltagty;
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_has_dynamic_size(
|
|
|
|
cx.fcx.lcx.ccx.tystore, tag_ty)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
lltagty = T_opaque_tag(cx.fcx.lcx.ccx.tn);
|
2011-04-07 11:42:40 -07:00
|
|
|
} else {
|
2011-04-17 14:24:45 +02:00
|
|
|
lltagty = type_of(cx.fcx.lcx.ccx, tag_ty);
|
2011-04-07 11:42:40 -07:00
|
|
|
}
|
2011-04-07 12:01:48 -07:00
|
|
|
auto lltagptr = alloc_result.bcx.build.
|
|
|
|
PointerCast(lltagblob, T_ptr(lltagty));
|
2011-03-01 12:41:41 -08:00
|
|
|
|
2011-04-07 11:42:40 -07:00
|
|
|
auto lldiscrimptr = alloc_result.bcx.build.GEP(
|
|
|
|
lltagptr, vec(C_int(0), C_int(0)));
|
|
|
|
alloc_result.bcx.build.Store(lldiscrim,
|
|
|
|
lldiscrimptr);
|
2011-03-01 12:41:41 -08:00
|
|
|
|
2011-04-07 11:42:40 -07:00
|
|
|
ret lval_val(alloc_result.bcx, lltagptr);
|
|
|
|
}
|
2011-01-05 15:31:35 -08:00
|
|
|
}
|
2010-12-01 19:03:47 -08:00
|
|
|
}
|
2011-01-21 12:09:25 -08:00
|
|
|
case (ast.def_const(?did)) {
|
2011-03-30 17:23:25 -07:00
|
|
|
// TODO: externals
|
2011-04-17 14:24:45 +02:00
|
|
|
check (cx.fcx.lcx.ccx.consts.contains_key(did));
|
|
|
|
ret lval_mem(cx, cx.fcx.lcx.ccx.consts.get(did));
|
2011-01-21 12:09:25 -08:00
|
|
|
}
|
2011-02-16 14:02:02 -05:00
|
|
|
case (ast.def_native_fn(?did)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto tyt = ty.lookup_item_type(cx.fcx.lcx.ccx.sess,
|
2011-04-20 18:52:04 -07:00
|
|
|
cx.fcx.lcx.ccx.tystore,
|
2011-04-17 14:24:45 +02:00
|
|
|
cx.fcx.lcx.ccx.type_cache, did);
|
2011-03-30 17:23:25 -07:00
|
|
|
ret lval_generic_fn(cx, tyt, did, ann);
|
2011-02-16 14:02:02 -05:00
|
|
|
}
|
2010-11-26 15:54:04 -08:00
|
|
|
case (_) {
|
2011-04-17 14:24:45 +02:00
|
|
|
cx.fcx.lcx.ccx.sess.unimpl("def variant in trans");
|
2010-10-19 16:33:11 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-11-26 15:54:04 -08:00
|
|
|
case (none[ast.def]) {
|
2011-04-17 14:24:45 +02:00
|
|
|
cx.fcx.lcx.ccx.sess.err("unresolved expr_path in trans");
|
2010-11-26 15:54:04 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
fail;
|
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn trans_field(@block_ctxt cx, &ast.span sp, ValueRef v, ty.t t0,
|
2011-01-21 07:58:16 -08:00
|
|
|
&ast.ident field, &ast.ann ann) -> lval_result {
|
2011-04-05 14:18:44 -07:00
|
|
|
|
|
|
|
auto r = autoderef(cx, v, t0);
|
2011-04-22 17:00:46 -07:00
|
|
|
auto t = autoderefed_ty(cx.fcx.lcx.ccx, t0);
|
2011-04-05 14:18:44 -07:00
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-03-17 17:39:47 -07:00
|
|
|
case (ty.ty_tup(_)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
let uint ix = ty.field_num(cx.fcx.lcx.ccx.sess, sp, field);
|
2011-01-19 16:29:14 -08:00
|
|
|
auto v = GEP_tup_like(r.bcx, t, r.val, vec(0, ix as int));
|
2011-01-31 15:03:05 -08:00
|
|
|
ret lval_mem(v.bcx, v.val);
|
2010-11-26 15:54:04 -08:00
|
|
|
}
|
2010-12-21 12:13:51 -08:00
|
|
|
case (ty.ty_rec(?fields)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
let uint ix = ty.field_idx(cx.fcx.lcx.ccx.sess, sp, field,
|
|
|
|
fields);
|
2011-01-19 16:29:14 -08:00
|
|
|
auto v = GEP_tup_like(r.bcx, t, r.val, vec(0, ix as int));
|
2011-01-31 15:03:05 -08:00
|
|
|
ret lval_mem(v.bcx, v.val);
|
2010-12-20 16:48:28 -08:00
|
|
|
}
|
2010-12-21 12:13:51 -08:00
|
|
|
case (ty.ty_obj(?methods)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
let uint ix = ty.method_idx(cx.fcx.lcx.ccx.sess, sp, field,
|
|
|
|
methods);
|
2010-12-20 16:48:28 -08:00
|
|
|
auto vtbl = r.bcx.build.GEP(r.val,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.obj_field_vtbl)));
|
|
|
|
vtbl = r.bcx.build.Load(vtbl);
|
|
|
|
auto v = r.bcx.build.GEP(vtbl, vec(C_int(0),
|
|
|
|
C_int(ix as int)));
|
2010-12-23 17:31:16 -08:00
|
|
|
|
|
|
|
auto lvo = lval_mem(r.bcx, v);
|
2011-04-22 12:27:28 -07:00
|
|
|
let ty.t fn_ty = ty.method_ty_to_fn_ty(cx.fcx.lcx.ccx.tystore,
|
2011-04-20 18:52:04 -07:00
|
|
|
methods.(ix));
|
2011-04-05 16:17:47 -07:00
|
|
|
ret rec(llobj = some[ValueRef](r.val),
|
2011-04-22 12:27:28 -07:00
|
|
|
method_ty = some[ty.t](fn_ty)
|
2011-04-05 16:17:47 -07:00
|
|
|
with lvo);
|
2010-11-30 10:39:35 -08:00
|
|
|
}
|
2011-04-17 14:24:45 +02:00
|
|
|
case (_) {cx.fcx.lcx.ccx.sess.unimpl("field variant in trans_field");}
|
2010-11-26 15:54:04 -08:00
|
|
|
}
|
|
|
|
fail;
|
|
|
|
}
|
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
fn trans_index(@block_ctxt cx, &ast.span sp, @ast.expr base,
|
|
|
|
@ast.expr idx, &ast.ann ann) -> lval_result {
|
2010-12-10 16:10:35 -08:00
|
|
|
|
2010-12-10 17:24:35 -08:00
|
|
|
auto lv = trans_expr(cx, base);
|
2011-04-20 18:52:04 -07:00
|
|
|
lv = autoderef(lv.bcx, lv.val, ty.expr_ty(cx.fcx.lcx.ccx.tystore, base));
|
2010-12-10 17:24:35 -08:00
|
|
|
auto ix = trans_expr(lv.bcx, idx);
|
|
|
|
auto v = lv.val;
|
2011-01-31 15:03:05 -08:00
|
|
|
auto bcx = ix.bcx;
|
2010-12-10 16:10:35 -08:00
|
|
|
|
2011-03-07 15:43:55 -08:00
|
|
|
// Cast to an LLVM integer. Rust is less strict than LLVM in this regard.
|
|
|
|
auto ix_val;
|
2011-04-17 14:24:45 +02:00
|
|
|
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());
|
2011-03-07 15:43:55 -08:00
|
|
|
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());
|
|
|
|
} else {
|
|
|
|
ix_val = ix.val;
|
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
auto unit_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
|
2011-03-31 10:10:21 -07:00
|
|
|
auto unit_sz = size_of(bcx, unit_ty);
|
2011-01-31 15:03:05 -08:00
|
|
|
bcx = unit_sz.bcx;
|
2011-03-31 10:10:21 -07:00
|
|
|
llvm.LLVMSetValueName(unit_sz.val, _str.buf("unit_sz"));
|
2011-03-07 15:43:55 -08:00
|
|
|
|
|
|
|
auto scaled_ix = bcx.build.Mul(ix_val, unit_sz.val);
|
2011-03-31 10:10:21 -07:00
|
|
|
llvm.LLVMSetValueName(scaled_ix, _str.buf("scaled_ix"));
|
2010-12-10 16:10:35 -08:00
|
|
|
|
2011-01-31 15:03:05 -08:00
|
|
|
auto lim = bcx.build.GEP(v, vec(C_int(0), C_int(abi.vec_elt_fill)));
|
|
|
|
lim = bcx.build.Load(lim);
|
2010-12-13 11:16:04 -08:00
|
|
|
|
2011-01-31 15:03:05 -08:00
|
|
|
auto bounds_check = bcx.build.ICmp(lib.llvm.LLVMIntULT,
|
|
|
|
scaled_ix, lim);
|
2010-12-10 16:10:35 -08:00
|
|
|
|
2011-01-31 15:03:05 -08:00
|
|
|
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);
|
2010-12-10 16:10:35 -08:00
|
|
|
|
|
|
|
// fail: bad bounds check.
|
2011-04-19 15:22:57 -07:00
|
|
|
auto fail_res = trans_fail(fail_cx, some[common.span](sp),
|
|
|
|
"bounds check");
|
2010-12-10 16:10:35 -08:00
|
|
|
|
|
|
|
auto body = next_cx.build.GEP(v, vec(C_int(0), C_int(abi.vec_elt_data)));
|
2011-03-31 10:10:21 -07:00
|
|
|
auto elt;
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tystore, unit_ty)) {
|
2011-03-31 10:10:21 -07:00
|
|
|
body = next_cx.build.PointerCast(body, T_ptr(T_array(T_i8(), 0u)));
|
|
|
|
elt = next_cx.build.GEP(body, vec(C_int(0), scaled_ix));
|
|
|
|
} else {
|
|
|
|
elt = next_cx.build.GEP(body, vec(C_int(0), ix_val));
|
2011-04-07 18:00:29 -07:00
|
|
|
|
|
|
|
// We're crossing a box boundary here, so we may need to pointer cast.
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llunitty = type_of(next_cx.fcx.lcx.ccx, unit_ty);
|
2011-04-07 18:00:29 -07:00
|
|
|
elt = next_cx.build.PointerCast(elt, T_ptr(llunitty));
|
2011-03-31 10:10:21 -07:00
|
|
|
}
|
|
|
|
|
2010-12-23 17:31:16 -08:00
|
|
|
ret lval_mem(next_cx, elt);
|
2010-12-10 16:10:35 -08:00
|
|
|
}
|
|
|
|
|
2010-12-07 11:57:19 -08:00
|
|
|
// 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).
|
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
fn trans_lval(@block_ctxt cx, @ast.expr e) -> lval_result {
|
2010-11-26 15:54:04 -08:00
|
|
|
alt (e.node) {
|
2011-01-13 17:42:28 -08:00
|
|
|
case (ast.expr_path(?p, ?dopt, ?ann)) {
|
|
|
|
ret trans_path(cx, p, dopt, ann);
|
2010-11-26 15:54:04 -08:00
|
|
|
}
|
|
|
|
case (ast.expr_field(?base, ?ident, ?ann)) {
|
2011-04-05 14:18:44 -07:00
|
|
|
auto r = trans_expr(cx, base);
|
2011-04-20 18:52:04 -07:00
|
|
|
auto t = ty.expr_ty(cx.fcx.lcx.ccx.tystore, base);
|
2011-04-05 14:18:44 -07:00
|
|
|
ret trans_field(r.bcx, e.span, r.val, t, ident, ann);
|
2010-11-26 15:54:04 -08:00
|
|
|
}
|
2010-12-10 16:10:35 -08:00
|
|
|
case (ast.expr_index(?base, ?idx, ?ann)) {
|
|
|
|
ret trans_index(cx, e.span, base, idx, ann);
|
|
|
|
}
|
2011-04-07 12:50:37 -07:00
|
|
|
case (ast.expr_unary(?unop, ?base, ?ann)) {
|
|
|
|
check (unop == ast.deref);
|
|
|
|
|
|
|
|
auto sub = trans_expr(cx, base);
|
|
|
|
auto val = sub.bcx.build.GEP(sub.val,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.box_rc_field_body)));
|
|
|
|
ret lval_mem(sub.bcx, val);
|
|
|
|
}
|
2011-04-07 13:49:27 -07:00
|
|
|
case (ast.expr_self_method(?ident, ?ann)) {
|
2011-04-05 14:18:44 -07:00
|
|
|
alt (cx.fcx.llself) {
|
|
|
|
case (some[self_vt](?s_vt)) {
|
|
|
|
auto r = s_vt.v;
|
|
|
|
auto t = s_vt.t;
|
|
|
|
ret trans_field(cx, e.span, r, t, ident, ann);
|
|
|
|
}
|
|
|
|
case (_) {
|
|
|
|
// Shouldn't happen.
|
|
|
|
fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2011-04-07 12:50:37 -07:00
|
|
|
case (_) {
|
2011-04-17 14:24:45 +02:00
|
|
|
cx.fcx.lcx.ccx.sess.span_unimpl(e.span,
|
|
|
|
"expr variant in trans_lval");
|
2011-04-07 12:50:37 -07:00
|
|
|
}
|
2010-10-19 16:33:11 -07:00
|
|
|
}
|
|
|
|
fail;
|
|
|
|
}
|
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
fn trans_cast(@block_ctxt cx, @ast.expr e, &ast.ann ann) -> result {
|
2010-11-24 10:32:14 -08:00
|
|
|
auto e_res = trans_expr(cx, e);
|
|
|
|
auto llsrctype = val_ty(e_res.val);
|
2011-04-17 14:24:45 +02:00
|
|
|
auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
|
|
|
|
auto lldsttype = type_of(cx.fcx.lcx.ccx, t);
|
2011-04-22 17:00:46 -07:00
|
|
|
if (!ty.type_is_fp(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-03-18 18:49:59 -07:00
|
|
|
// TODO: native-to-native casts
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_is_native(cx.fcx.lcx.ccx.tystore,
|
|
|
|
ty.expr_ty(cx.fcx.lcx.ccx.tystore, e))) {
|
2011-03-18 18:12:58 -07:00
|
|
|
e_res.val = e_res.bcx.build.PtrToInt(e_res.val, lldsttype);
|
2011-04-22 17:00:46 -07:00
|
|
|
} else if (ty.type_is_native(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-03-18 18:49:59 -07:00
|
|
|
e_res.val = e_res.bcx.build.IntToPtr(e_res.val, lldsttype);
|
2011-03-18 18:12:58 -07:00
|
|
|
} else if (llvm.LLVMGetIntTypeWidth(lldsttype) >
|
2011-04-01 16:04:22 -07:00
|
|
|
llvm.LLVMGetIntTypeWidth(llsrctype)) {
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_is_signed(cx.fcx.lcx.ccx.tystore, t)) {
|
2010-11-24 10:32:14 -08:00
|
|
|
// Widening signed cast.
|
|
|
|
e_res.val =
|
|
|
|
e_res.bcx.build.SExtOrBitCast(e_res.val,
|
|
|
|
lldsttype);
|
|
|
|
} else {
|
|
|
|
// Widening unsigned cast.
|
|
|
|
e_res.val =
|
|
|
|
e_res.bcx.build.ZExtOrBitCast(e_res.val,
|
|
|
|
lldsttype);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Narrowing cast.
|
|
|
|
e_res.val =
|
|
|
|
e_res.bcx.build.TruncOrBitCast(e_res.val,
|
|
|
|
lldsttype);
|
|
|
|
}
|
|
|
|
} else {
|
2011-04-17 14:24:45 +02:00
|
|
|
cx.fcx.lcx.ccx.sess.unimpl("fp cast");
|
2010-11-24 10:32:14 -08:00
|
|
|
}
|
|
|
|
ret e_res;
|
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
fn trans_bind_thunk(@local_ctxt cx,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t incoming_fty,
|
|
|
|
ty.t outgoing_fty,
|
2011-01-21 07:58:16 -08:00
|
|
|
vec[option.t[@ast.expr]] args,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t closure_ty,
|
|
|
|
vec[ty.t] bound_tys,
|
2011-02-23 10:58:43 -08:00
|
|
|
uint ty_param_count) -> ValueRef {
|
2011-01-07 15:12:23 -08:00
|
|
|
// Construct a thunk-call with signature incoming_fty, and that copies
|
|
|
|
// args forward into a call to outgoing_fty.
|
|
|
|
|
2011-04-20 17:23:45 +02:00
|
|
|
let str s = mangle_name_by_seq(cx.ccx, cx.path, "thunk");
|
2011-04-17 14:24:45 +02:00
|
|
|
let TypeRef llthunk_ty = get_pair_fn_ty(type_of(cx.ccx, incoming_fty));
|
|
|
|
let ValueRef llthunk = decl_internal_fastcall_fn(cx.ccx.llmod,
|
|
|
|
s, llthunk_ty);
|
2011-01-07 15:12:23 -08:00
|
|
|
|
2011-03-04 14:53:52 -05:00
|
|
|
auto fcx = new_fn_ctxt(cx, llthunk);
|
2011-01-07 15:12:23 -08:00
|
|
|
auto bcx = new_top_block_ctxt(fcx);
|
2011-03-28 18:04:52 -07:00
|
|
|
auto lltop = bcx.llbb;
|
2011-01-07 15:12:23 -08:00
|
|
|
|
2011-04-20 18:52:04 -07:00
|
|
|
auto llclosure_ptr_ty =
|
|
|
|
type_of(cx.ccx, ty.mk_imm_box(cx.ccx.tystore, closure_ty));
|
2011-03-07 18:13:39 -08:00
|
|
|
auto llclosure = bcx.build.PointerCast(fcx.llenv, llclosure_ptr_ty);
|
2011-01-07 15:12:23 -08:00
|
|
|
|
2011-03-07 18:13:39 -08:00
|
|
|
auto lltarget = GEP_tup_like(bcx, closure_ty, llclosure,
|
|
|
|
vec(0,
|
|
|
|
abi.box_rc_field_body,
|
|
|
|
abi.closure_elt_target));
|
|
|
|
bcx = lltarget.bcx;
|
|
|
|
auto lltargetclosure = bcx.build.GEP(lltarget.val,
|
2011-01-07 15:12:23 -08:00
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.fn_field_box)));
|
|
|
|
lltargetclosure = bcx.build.Load(lltargetclosure);
|
2011-02-23 10:58:43 -08:00
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
auto outgoing_ret_ty = ty.ty_fn_ret(cx.ccx.tystore, outgoing_fty);
|
|
|
|
auto outgoing_args = ty.ty_fn_args(cx.ccx.tystore, outgoing_fty);
|
2011-02-23 10:58:43 -08:00
|
|
|
|
|
|
|
auto llretptr = fcx.llretptr;
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_has_dynamic_size(cx.ccx.tystore, outgoing_ret_ty)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
llretptr = bcx.build.PointerCast(llretptr, T_typaram_ptr(cx.ccx.tn));
|
2011-02-23 10:58:43 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
let vec[ValueRef] llargs = vec(llretptr,
|
2011-02-08 11:47:53 -08:00
|
|
|
fcx.lltaskptr,
|
2011-01-07 15:12:23 -08:00
|
|
|
lltargetclosure);
|
2011-02-23 10:58:43 -08:00
|
|
|
|
|
|
|
// Copy in the type parameters.
|
|
|
|
let uint i = 0u;
|
|
|
|
while (i < ty_param_count) {
|
|
|
|
auto lltyparam_ptr =
|
2011-03-07 18:13:39 -08:00
|
|
|
GEP_tup_like(bcx, closure_ty, llclosure,
|
|
|
|
vec(0,
|
|
|
|
abi.box_rc_field_body,
|
|
|
|
abi.closure_elt_ty_params,
|
|
|
|
(i as int)));
|
|
|
|
bcx = lltyparam_ptr.bcx;
|
|
|
|
llargs += vec(bcx.build.Load(lltyparam_ptr.val));
|
2011-02-23 10:58:43 -08:00
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
|
2011-03-10 14:31:15 -08:00
|
|
|
let uint a = 3u; // retptr, task ptr, env come first
|
2011-01-07 15:12:23 -08:00
|
|
|
let int b = 0;
|
2011-02-23 10:58:43 -08:00
|
|
|
let uint outgoing_arg_index = 0u;
|
2011-03-08 16:31:37 -08:00
|
|
|
let vec[TypeRef] llout_arg_tys =
|
2011-04-17 14:24:45 +02:00
|
|
|
type_of_explicit_args(cx.ccx, outgoing_args);
|
2011-03-08 16:31:37 -08:00
|
|
|
|
2011-01-07 15:12:23 -08:00
|
|
|
for (option.t[@ast.expr] arg in args) {
|
2011-03-08 16:31:37 -08:00
|
|
|
|
|
|
|
auto out_arg = outgoing_args.(outgoing_arg_index);
|
|
|
|
auto llout_arg_ty = llout_arg_tys.(outgoing_arg_index);
|
|
|
|
|
2011-01-07 15:12:23 -08:00
|
|
|
alt (arg) {
|
|
|
|
|
|
|
|
// Arg provided at binding time; thunk copies it from closure.
|
|
|
|
case (some[@ast.expr](_)) {
|
2011-03-07 18:13:39 -08:00
|
|
|
auto bound_arg =
|
|
|
|
GEP_tup_like(bcx, closure_ty, llclosure,
|
|
|
|
vec(0,
|
|
|
|
abi.box_rc_field_body,
|
|
|
|
abi.closure_elt_bindings,
|
|
|
|
b));
|
2011-03-08 16:31:37 -08:00
|
|
|
|
2011-03-07 18:13:39 -08:00
|
|
|
bcx = bound_arg.bcx;
|
2011-03-08 16:31:37 -08:00
|
|
|
auto val = bound_arg.val;
|
|
|
|
|
|
|
|
if (out_arg.mode == ast.val) {
|
|
|
|
val = bcx.build.Load(val);
|
2011-04-22 17:00:46 -07:00
|
|
|
} else if (ty.count_ty_params(cx.ccx.tystore,
|
|
|
|
out_arg.ty) > 0u) {
|
2011-03-08 16:31:37 -08:00
|
|
|
check (out_arg.mode == ast.alias);
|
|
|
|
val = bcx.build.PointerCast(val, llout_arg_ty);
|
|
|
|
}
|
|
|
|
|
2011-03-16 14:58:02 -07:00
|
|
|
llargs += vec(val);
|
2011-01-07 15:12:23 -08:00
|
|
|
b += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Arg will be provided when the thunk is invoked.
|
|
|
|
case (none[@ast.expr]) {
|
|
|
|
let ValueRef passed_arg = llvm.LLVMGetParam(llthunk, a);
|
2011-03-08 16:31:37 -08:00
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.count_ty_params(cx.ccx.tystore, out_arg.ty) > 0u) {
|
2011-03-08 16:31:37 -08:00
|
|
|
check (out_arg.mode == ast.alias);
|
2011-02-23 10:58:43 -08:00
|
|
|
passed_arg = bcx.build.PointerCast(passed_arg,
|
2011-03-08 16:31:37 -08:00
|
|
|
llout_arg_ty);
|
2011-02-23 10:58:43 -08:00
|
|
|
}
|
2011-03-08 16:31:37 -08:00
|
|
|
|
2011-03-16 14:58:02 -07:00
|
|
|
llargs += vec(passed_arg);
|
2011-01-07 15:12:23 -08:00
|
|
|
a += 1u;
|
|
|
|
}
|
|
|
|
}
|
2011-02-23 10:58:43 -08:00
|
|
|
|
2011-03-10 15:09:41 -08:00
|
|
|
outgoing_arg_index += 1u;
|
2011-01-07 15:12:23 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: turn this call + ret into a tail call.
|
2011-03-07 18:13:39 -08:00
|
|
|
auto lltargetfn = bcx.build.GEP(lltarget.val,
|
2011-01-07 15:12:23 -08:00
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.fn_field_code)));
|
2011-03-08 16:51:23 -08:00
|
|
|
|
|
|
|
// Cast the outgoing function to the appropriate type (see the comments in
|
|
|
|
// trans_bind below for why this is necessary).
|
2011-04-17 14:24:45 +02:00
|
|
|
auto lltargetty = type_of_fn(bcx.fcx.lcx.ccx,
|
2011-04-22 17:00:46 -07:00
|
|
|
ty.ty_fn_proto(bcx.fcx.lcx.ccx.tystore,
|
|
|
|
outgoing_fty),
|
2011-03-08 16:51:23 -08:00
|
|
|
outgoing_args,
|
|
|
|
outgoing_ret_ty,
|
|
|
|
ty_param_count);
|
|
|
|
lltargetfn = bcx.build.PointerCast(lltargetfn, T_ptr(T_ptr(lltargetty)));
|
|
|
|
|
2011-01-07 15:12:23 -08:00
|
|
|
lltargetfn = bcx.build.Load(lltargetfn);
|
2011-02-23 10:58:43 -08:00
|
|
|
|
2011-01-07 15:12:23 -08:00
|
|
|
auto r = bcx.build.FastCall(lltargetfn, llargs);
|
2011-02-08 11:47:53 -08:00
|
|
|
bcx.build.RetVoid();
|
2011-01-07 15:12:23 -08:00
|
|
|
|
2011-03-28 18:04:52 -07:00
|
|
|
// Tie up the llallocas -> lltop edge.
|
|
|
|
new_builder(fcx.llallocas).Br(lltop);
|
|
|
|
|
2011-01-07 15:12:23 -08:00
|
|
|
ret llthunk;
|
|
|
|
}
|
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
fn trans_bind(@block_ctxt cx, @ast.expr f,
|
|
|
|
vec[option.t[@ast.expr]] args,
|
|
|
|
&ast.ann ann) -> result {
|
2011-01-03 22:39:43 -08:00
|
|
|
auto f_res = trans_lval(cx, f);
|
|
|
|
if (f_res.is_mem) {
|
2011-04-17 14:24:45 +02:00
|
|
|
cx.fcx.lcx.ccx.sess.unimpl("re-binding existing function");
|
2011-01-03 22:39:43 -08:00
|
|
|
} else {
|
2011-01-05 18:57:28 -08:00
|
|
|
let vec[@ast.expr] bound = vec();
|
|
|
|
|
2011-01-05 16:06:01 -08:00
|
|
|
for (option.t[@ast.expr] argopt in args) {
|
|
|
|
alt (argopt) {
|
|
|
|
case (none[@ast.expr]) {
|
|
|
|
}
|
|
|
|
case (some[@ast.expr](?e)) {
|
2011-03-16 14:58:02 -07:00
|
|
|
_vec.push[@ast.expr](bound, e);
|
2011-01-05 16:06:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-02-23 10:58:43 -08:00
|
|
|
|
|
|
|
// Figure out which tydescs we need to pass, if any.
|
2011-04-22 12:27:28 -07:00
|
|
|
let ty.t outgoing_fty;
|
2011-03-06 13:56:38 -05:00
|
|
|
let vec[ValueRef] lltydescs;
|
2011-02-23 10:58:43 -08:00
|
|
|
alt (f_res.generic) {
|
|
|
|
case (none[generic_info]) {
|
2011-04-20 18:52:04 -07:00
|
|
|
outgoing_fty = ty.expr_ty(cx.fcx.lcx.ccx.tystore, f);
|
2011-03-06 13:56:38 -05:00
|
|
|
lltydescs = vec();
|
2011-02-23 10:58:43 -08:00
|
|
|
}
|
|
|
|
case (some[generic_info](?ginfo)) {
|
|
|
|
outgoing_fty = ginfo.item_type;
|
|
|
|
lltydescs = ginfo.tydescs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
auto ty_param_count = _vec.len[ValueRef](lltydescs);
|
|
|
|
|
|
|
|
if (_vec.len[@ast.expr](bound) == 0u && ty_param_count == 0u) {
|
2011-01-05 16:06:01 -08:00
|
|
|
// Trivial 'binding': just return the static pair-ptr.
|
|
|
|
ret f_res.res;
|
|
|
|
} else {
|
|
|
|
auto bcx = f_res.res.bcx;
|
2011-04-17 14:24:45 +02:00
|
|
|
auto pair_t = node_type(cx.fcx.lcx.ccx, ann);
|
2011-03-28 18:04:52 -07:00
|
|
|
auto pair_v = alloca(bcx, pair_t);
|
2011-01-05 18:57:28 -08:00
|
|
|
|
|
|
|
// Translate the bound expressions.
|
2011-04-22 12:27:28 -07:00
|
|
|
let vec[ty.t] bound_tys = vec();
|
2011-01-05 18:57:28 -08:00
|
|
|
let vec[ValueRef] bound_vals = vec();
|
2011-02-23 10:58:43 -08:00
|
|
|
auto i = 0u;
|
2011-01-05 18:57:28 -08:00
|
|
|
for (@ast.expr e in bound) {
|
|
|
|
auto arg = trans_expr(bcx, e);
|
|
|
|
bcx = arg.bcx;
|
2011-02-23 10:58:43 -08:00
|
|
|
|
2011-03-16 14:58:02 -07:00
|
|
|
_vec.push[ValueRef](bound_vals, arg.val);
|
2011-04-22 12:27:28 -07:00
|
|
|
_vec.push[ty.t](bound_tys,
|
2011-04-20 18:52:04 -07:00
|
|
|
ty.expr_ty(cx.fcx.lcx.ccx.tystore, e));
|
2011-02-23 10:58:43 -08:00
|
|
|
|
|
|
|
i += 1u;
|
2011-01-05 18:57:28 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Synthesize a closure type.
|
2011-04-22 12:27:28 -07:00
|
|
|
let ty.t bindings_ty = ty.mk_imm_tup(cx.fcx.lcx.ccx.tystore,
|
2011-04-20 18:52:04 -07:00
|
|
|
bound_tys);
|
2011-03-07 18:13:39 -08:00
|
|
|
|
|
|
|
// NB: keep this in sync with T_closure_ptr; we're making
|
|
|
|
// a ty.t structure that has the same "shape" as the LLVM type
|
|
|
|
// it constructs.
|
2011-04-22 12:27:28 -07:00
|
|
|
let ty.t tydesc_ty = ty.mk_type(cx.fcx.lcx.ccx.tystore);
|
2011-03-07 18:13:39 -08:00
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
let vec[ty.t] captured_tys =
|
|
|
|
_vec.init_elt[ty.t](tydesc_ty, ty_param_count);
|
2011-03-07 18:13:39 -08:00
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
let vec[ty.t] closure_tys =
|
2011-03-07 18:13:39 -08:00
|
|
|
vec(tydesc_ty,
|
|
|
|
outgoing_fty,
|
|
|
|
bindings_ty,
|
2011-04-20 18:52:04 -07:00
|
|
|
ty.mk_imm_tup(cx.fcx.lcx.ccx.tystore, captured_tys));
|
2011-03-07 18:13:39 -08:00
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
let ty.t closure_ty = ty.mk_imm_tup(cx.fcx.lcx.ccx.tystore,
|
2011-04-20 18:52:04 -07:00
|
|
|
closure_tys);
|
2011-03-07 18:13:39 -08:00
|
|
|
|
|
|
|
auto r = trans_malloc_boxed(bcx, closure_ty);
|
2011-01-05 18:57:28 -08:00
|
|
|
auto box = r.val;
|
|
|
|
bcx = r.bcx;
|
|
|
|
auto rc = bcx.build.GEP(box,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.box_rc_field_refcnt)));
|
|
|
|
auto closure =
|
|
|
|
bcx.build.GEP(box,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.box_rc_field_body)));
|
|
|
|
bcx.build.Store(C_int(1), rc);
|
|
|
|
|
|
|
|
// Store bindings tydesc.
|
|
|
|
auto bound_tydesc =
|
|
|
|
bcx.build.GEP(closure,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.closure_elt_tydesc)));
|
|
|
|
auto bindings_tydesc = get_tydesc(bcx, bindings_ty);
|
2011-01-31 15:03:05 -08:00
|
|
|
bcx = bindings_tydesc.bcx;
|
|
|
|
bcx.build.Store(bindings_tydesc.val, bound_tydesc);
|
2011-01-05 18:57:28 -08:00
|
|
|
|
2011-03-08 16:51:23 -08:00
|
|
|
// 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.
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llfnty = type_of_fn(bcx.fcx.lcx.ccx,
|
2011-04-22 17:00:46 -07:00
|
|
|
ty.ty_fn_proto(bcx.fcx.lcx.ccx.tystore, outgoing_fty),
|
|
|
|
ty.ty_fn_args(bcx.fcx.lcx.ccx.tystore, outgoing_fty),
|
|
|
|
ty.ty_fn_ret(bcx.fcx.lcx.ccx.tystore, outgoing_fty),
|
|
|
|
ty_param_count);
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llclosurety = T_ptr(T_fn_pair(bcx.fcx.lcx.ccx.tn, llfnty));
|
2011-03-08 16:51:23 -08:00
|
|
|
|
2011-01-06 12:55:27 -08:00
|
|
|
// Store thunk-target.
|
|
|
|
auto bound_target =
|
2011-01-05 18:57:28 -08:00
|
|
|
bcx.build.GEP(closure,
|
|
|
|
vec(C_int(0),
|
2011-01-06 12:55:27 -08:00
|
|
|
C_int(abi.closure_elt_target)));
|
2011-02-23 10:58:43 -08:00
|
|
|
auto src = bcx.build.Load(f_res.res.val);
|
2011-03-08 16:51:23 -08:00
|
|
|
bound_target = bcx.build.PointerCast(bound_target, llclosurety);
|
2011-02-23 10:58:43 -08:00
|
|
|
bcx.build.Store(src, bound_target);
|
2011-01-05 18:57:28 -08:00
|
|
|
|
2011-01-06 12:55:27 -08:00
|
|
|
// Copy expr values into boxed bindings.
|
2011-02-23 10:58:43 -08:00
|
|
|
i = 0u;
|
2011-01-06 12:55:27 -08:00
|
|
|
auto bindings =
|
|
|
|
bcx.build.GEP(closure,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.closure_elt_bindings)));
|
2011-01-05 18:57:28 -08:00
|
|
|
for (ValueRef v in bound_vals) {
|
|
|
|
auto bound = bcx.build.GEP(bindings,
|
2011-02-23 10:58:43 -08:00
|
|
|
vec(C_int(0), C_int(i as int)));
|
2011-01-24 15:26:10 -08:00
|
|
|
bcx = copy_ty(r.bcx, INIT, bound, v, bound_tys.(i)).bcx;
|
2011-02-23 10:58:43 -08:00
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If necessary, copy tydescs describing type parameters into the
|
|
|
|
// appropriate slot in the closure.
|
|
|
|
alt (f_res.generic) {
|
|
|
|
case (none[generic_info]) { /* nothing to do */ }
|
|
|
|
case (some[generic_info](?ginfo)) {
|
|
|
|
auto ty_params_slot =
|
|
|
|
bcx.build.GEP(closure,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.closure_elt_ty_params)));
|
|
|
|
auto i = 0;
|
|
|
|
for (ValueRef td in ginfo.tydescs) {
|
|
|
|
auto ty_param_slot = bcx.build.GEP(ty_params_slot,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(i)));
|
|
|
|
bcx.build.Store(td, ty_param_slot);
|
|
|
|
i += 1;
|
|
|
|
}
|
2011-03-10 15:14:45 -08:00
|
|
|
|
|
|
|
outgoing_fty = ginfo.item_type;
|
2011-02-23 10:58:43 -08:00
|
|
|
}
|
2011-01-05 18:57:28 -08:00
|
|
|
}
|
|
|
|
|
2011-01-07 15:12:23 -08:00
|
|
|
// Make thunk and store thunk-ptr in outer pair's code slot.
|
|
|
|
auto pair_code = bcx.build.GEP(pair_v,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.fn_field_code)));
|
2011-01-07 16:26:30 -08:00
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
let ty.t pair_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
|
2011-03-07 18:13:39 -08:00
|
|
|
|
2011-01-07 15:12:23 -08:00
|
|
|
let ValueRef llthunk =
|
2011-04-17 14:24:45 +02:00
|
|
|
trans_bind_thunk(cx.fcx.lcx, pair_ty, outgoing_fty,
|
2011-03-07 18:13:39 -08:00
|
|
|
args, closure_ty, bound_tys,
|
2011-02-23 10:58:43 -08:00
|
|
|
ty_param_count);
|
2011-01-07 15:12:23 -08:00
|
|
|
|
|
|
|
bcx.build.Store(llthunk, pair_code);
|
|
|
|
|
|
|
|
// Store box ptr in outer pair's box slot.
|
|
|
|
auto pair_box = bcx.build.GEP(pair_v,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.fn_field_box)));
|
2011-02-17 18:16:51 -08:00
|
|
|
bcx.build.Store
|
|
|
|
(bcx.build.PointerCast
|
|
|
|
(box,
|
2011-04-17 14:24:45 +02:00
|
|
|
T_opaque_closure_ptr(bcx.fcx.lcx.ccx.tn)),
|
2011-02-17 18:16:51 -08:00
|
|
|
pair_box);
|
2011-01-05 18:57:28 -08:00
|
|
|
|
2011-01-07 16:26:30 -08:00
|
|
|
find_scope_cx(cx).cleanups +=
|
2011-03-16 14:58:02 -07:00
|
|
|
vec(clean(bind drop_slot(_, pair_v, pair_ty)));
|
2011-01-07 16:26:30 -08:00
|
|
|
|
2011-01-05 16:06:01 -08:00
|
|
|
ret res(bcx, pair_v);
|
|
|
|
}
|
2011-01-03 22:39:43 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-23 14:17:44 -07:00
|
|
|
fn trans_arg_expr(@block_ctxt cx,
|
|
|
|
ty.arg arg,
|
|
|
|
TypeRef lldestty0,
|
|
|
|
@ast.expr e) -> result {
|
|
|
|
|
|
|
|
auto val;
|
|
|
|
auto bcx = cx;
|
|
|
|
auto e_ty = ty.expr_ty(cx.fcx.lcx.ccx.tystore, e);
|
|
|
|
|
|
|
|
if (ty.type_is_structural(cx.fcx.lcx.ccx.tystore, e_ty)) {
|
|
|
|
auto re = trans_expr(bcx, e);
|
|
|
|
val = re.val;
|
|
|
|
bcx = re.bcx;
|
|
|
|
} else if (arg.mode == ast.alias) {
|
|
|
|
let lval_result lv;
|
|
|
|
if (ty.is_lval(e)) {
|
|
|
|
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);
|
|
|
|
} else {
|
|
|
|
lv = lval_mem(r.bcx, r.val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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.
|
|
|
|
val = do_spill(lv.res.bcx, lv.res.val);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
auto re = trans_expr(bcx, e);
|
|
|
|
val = re.val;
|
|
|
|
bcx = re.bcx;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ty.count_ty_params(cx.fcx.lcx.ccx.tystore, arg.ty) > 0u) {
|
|
|
|
auto lldestty = lldestty0;
|
|
|
|
if (arg.mode == ast.val) {
|
|
|
|
// FIXME: we'd prefer to use &&, but rustboot doesn't like it
|
|
|
|
if (ty.type_is_structural(cx.fcx.lcx.ccx.tystore, e_ty)) {
|
|
|
|
lldestty = T_ptr(lldestty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
val = bcx.build.PointerCast(val, lldestty);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arg.mode == ast.val) {
|
|
|
|
// FIXME: we'd prefer to use &&, but rustboot doesn't like it
|
|
|
|
if (ty.type_is_structural(cx.fcx.lcx.ccx.tystore, e_ty)) {
|
|
|
|
// Until here we've been treating structures by pointer;
|
|
|
|
// we are now passing it as an arg, so need to load it.
|
|
|
|
val = bcx.build.Load(val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret res(bcx, val);
|
|
|
|
}
|
|
|
|
|
2011-02-08 11:47:53 -08:00
|
|
|
// NB: must keep 4 fns in sync:
|
|
|
|
//
|
|
|
|
// - type_of_fn_full
|
|
|
|
// - create_llargs_for_fn_args.
|
|
|
|
// - new_fn_ctxt
|
|
|
|
// - trans_args
|
|
|
|
|
|
|
|
fn trans_args(@block_ctxt cx,
|
|
|
|
ValueRef llenv,
|
|
|
|
option.t[ValueRef] llobj,
|
|
|
|
option.t[generic_info] gen,
|
2011-02-18 17:30:57 -08:00
|
|
|
option.t[ValueRef] lliterbody,
|
2011-02-08 11:47:53 -08:00
|
|
|
&vec[@ast.expr] es,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t fn_ty)
|
2011-02-08 11:47:53 -08:00
|
|
|
-> tup(@block_ctxt, vec[ValueRef], ValueRef) {
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
let vec[ty.arg] args = ty.ty_fn_args(cx.fcx.lcx.ccx.tystore, fn_ty);
|
2011-02-08 11:47:53 -08:00
|
|
|
let vec[ValueRef] llargs = vec();
|
|
|
|
let vec[ValueRef] lltydescs = vec();
|
|
|
|
let @block_ctxt bcx = cx;
|
|
|
|
|
|
|
|
|
|
|
|
// Arg 0: Output pointer.
|
2011-04-22 17:00:46 -07:00
|
|
|
auto retty = ty.ty_fn_ret(cx.fcx.lcx.ccx.tystore, fn_ty);
|
2011-02-10 15:00:16 -08:00
|
|
|
auto llretslot_res = alloc_ty(bcx, retty);
|
|
|
|
bcx = llretslot_res.bcx;
|
|
|
|
auto llretslot = llretslot_res.val;
|
|
|
|
|
2011-02-08 11:47:53 -08:00
|
|
|
alt (gen) {
|
|
|
|
case (some[generic_info](?g)) {
|
|
|
|
lltydescs = g.tydescs;
|
2011-04-22 17:00:46 -07:00
|
|
|
args = ty.ty_fn_args(cx.fcx.lcx.ccx.tystore, g.item_type);
|
|
|
|
retty = ty.ty_fn_ret(cx.fcx.lcx.ccx.tystore, g.item_type);
|
2011-02-08 11:47:53 -08:00
|
|
|
}
|
|
|
|
case (_) {
|
|
|
|
}
|
|
|
|
}
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tystore, retty)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
llargs += vec(bcx.build.PointerCast
|
|
|
|
(llretslot, T_typaram_ptr(cx.fcx.lcx.ccx.tn)));
|
2011-04-22 17:00:46 -07:00
|
|
|
} else if (ty.count_ty_params(cx.fcx.lcx.ccx.tystore, retty) != 0u) {
|
2011-02-08 17:05:53 -08:00
|
|
|
// 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.
|
2011-03-16 14:58:02 -07:00
|
|
|
llargs +=
|
|
|
|
vec(cx.build.PointerCast(llretslot,
|
2011-04-17 14:24:45 +02:00
|
|
|
T_ptr(type_of(bcx.fcx.lcx.ccx, retty))));
|
2011-02-08 11:47:53 -08:00
|
|
|
} else {
|
2011-03-16 14:58:02 -07:00
|
|
|
llargs += vec(llretslot);
|
2011-02-08 11:47:53 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Arg 1: Task pointer.
|
2011-03-16 14:58:02 -07:00
|
|
|
llargs += vec(bcx.fcx.lltaskptr);
|
2011-02-08 11:47:53 -08:00
|
|
|
|
|
|
|
// Arg 2: Env (closure-bindings / self-obj)
|
|
|
|
alt (llobj) {
|
|
|
|
case (some[ValueRef](?ob)) {
|
|
|
|
// Every object is always found in memory,
|
|
|
|
// and not-yet-loaded (as part of an lval x.y
|
|
|
|
// doted method-call).
|
2011-03-16 14:58:02 -07:00
|
|
|
llargs += vec(bcx.build.Load(ob));
|
2011-02-08 11:47:53 -08:00
|
|
|
}
|
|
|
|
case (_) {
|
2011-03-16 14:58:02 -07:00
|
|
|
llargs += vec(llenv);
|
2011-02-08 11:47:53 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Args >3: ty_params ...
|
|
|
|
llargs += lltydescs;
|
|
|
|
|
2011-02-18 17:30:57 -08:00
|
|
|
// ... then possibly an lliterbody argument.
|
|
|
|
alt (lliterbody) {
|
|
|
|
case (none[ValueRef]) {}
|
|
|
|
case (some[ValueRef](?lli)) {
|
2011-03-16 14:58:02 -07:00
|
|
|
llargs += vec(lli);
|
2011-02-18 17:30:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-08 11:47:53 -08:00
|
|
|
// ... then explicit args.
|
2011-02-24 13:51:53 -08:00
|
|
|
|
|
|
|
// 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.
|
2011-04-17 14:24:45 +02:00
|
|
|
auto arg_tys = type_of_explicit_args(cx.fcx.lcx.ccx, args);
|
2011-02-24 13:51:53 -08:00
|
|
|
|
2011-02-08 11:47:53 -08:00
|
|
|
auto i = 0u;
|
|
|
|
for (@ast.expr e in es) {
|
2011-04-23 14:17:44 -07:00
|
|
|
auto r = trans_arg_expr(bcx, args.(i), arg_tys.(i), e);
|
|
|
|
bcx = r.bcx;
|
|
|
|
llargs += vec(r.val);
|
2011-02-08 11:47:53 -08:00
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret tup(bcx, llargs, llretslot);
|
|
|
|
}
|
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
fn trans_call(@block_ctxt cx, @ast.expr f,
|
2011-02-18 17:30:57 -08:00
|
|
|
option.t[ValueRef] lliterbody,
|
|
|
|
vec[@ast.expr] args,
|
|
|
|
&ast.ann ann) -> result {
|
2011-04-05 16:17:47 -07:00
|
|
|
|
|
|
|
// 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.
|
|
|
|
|
2010-11-24 10:36:46 -08:00
|
|
|
auto f_res = trans_lval(cx, f);
|
2010-12-23 17:31:16 -08:00
|
|
|
auto faddr = f_res.res.val;
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llenv = C_null(T_opaque_closure_ptr(cx.fcx.lcx.ccx.tn));
|
2011-01-05 15:31:35 -08:00
|
|
|
|
|
|
|
alt (f_res.llobj) {
|
|
|
|
case (some[ValueRef](_)) {
|
|
|
|
// It's a vtbl entry.
|
|
|
|
faddr = f_res.res.bcx.build.Load(faddr);
|
|
|
|
}
|
|
|
|
case (none[ValueRef]) {
|
|
|
|
// It's a closure.
|
|
|
|
auto bcx = f_res.res.bcx;
|
2011-01-07 15:12:23 -08:00
|
|
|
auto pair = faddr;
|
|
|
|
faddr = bcx.build.GEP(pair, vec(C_int(0),
|
2011-01-21 07:50:02 -08:00
|
|
|
C_int(abi.fn_field_code)));
|
2011-01-05 15:31:35 -08:00
|
|
|
faddr = bcx.build.Load(faddr);
|
2011-01-07 15:12:23 -08:00
|
|
|
|
2011-02-08 11:47:53 -08:00
|
|
|
auto llclosure = bcx.build.GEP(pair,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.fn_field_box)));
|
|
|
|
llenv = bcx.build.Load(llclosure);
|
2011-01-03 22:39:43 -08:00
|
|
|
}
|
2010-12-20 16:48:28 -08:00
|
|
|
}
|
2011-03-31 11:26:25 -07:00
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
let ty.t fn_ty;
|
2011-04-05 16:17:47 -07:00
|
|
|
alt (f_res.method_ty) {
|
2011-04-22 12:27:28 -07:00
|
|
|
case (some[ty.t](?meth)) {
|
2011-04-05 16:17:47 -07:00
|
|
|
// self-call
|
|
|
|
fn_ty = meth;
|
2011-03-31 11:26:25 -07:00
|
|
|
}
|
2011-04-12 12:06:20 -07:00
|
|
|
|
2011-04-05 16:17:47 -07:00
|
|
|
case (_) {
|
2011-04-20 18:52:04 -07:00
|
|
|
fn_ty = ty.expr_ty(cx.fcx.lcx.ccx.tystore, f);
|
2011-03-31 11:26:25 -07:00
|
|
|
|
|
|
|
}
|
2011-04-05 16:17:47 -07:00
|
|
|
|
2011-03-31 11:26:25 -07:00
|
|
|
}
|
2011-04-05 16:17:47 -07:00
|
|
|
|
2011-03-31 11:26:25 -07:00
|
|
|
auto ret_ty = ty.ann_to_type(ann);
|
|
|
|
auto args_res = trans_args(f_res.res.bcx,
|
|
|
|
llenv, f_res.llobj,
|
|
|
|
f_res.generic,
|
|
|
|
lliterbody,
|
|
|
|
args, fn_ty);
|
|
|
|
|
|
|
|
auto bcx = args_res._0;
|
|
|
|
auto llargs = args_res._1;
|
|
|
|
auto llretslot = args_res._2;
|
|
|
|
|
|
|
|
/*
|
2011-04-17 14:24:45 +02:00
|
|
|
log "calling: " + val_str(cx.fcx.lcx.ccx.tn, faddr);
|
2011-03-31 11:26:25 -07:00
|
|
|
|
2011-04-01 16:04:22 -07:00
|
|
|
for (ValueRef arg in llargs) {
|
2011-04-17 14:24:45 +02:00
|
|
|
log "arg: " + val_str(cx.fcx.lcx.ccx.tn, arg);
|
2011-04-01 16:04:22 -07:00
|
|
|
}
|
2011-03-31 11:26:25 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
bcx.build.FastCall(faddr, llargs);
|
|
|
|
auto retval = C_nil();
|
|
|
|
|
2011-04-23 14:17:44 -07:00
|
|
|
alt (lliterbody) {
|
|
|
|
case (none[ValueRef]) {
|
|
|
|
if (!ty.type_is_nil(cx.fcx.lcx.ccx.tystore, ret_ty)) {
|
|
|
|
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.
|
|
|
|
find_scope_cx(cx).cleanups +=
|
|
|
|
vec(clean(bind drop_ty(_, retval, ret_ty)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case (some[ValueRef](_)) {
|
|
|
|
// 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.
|
|
|
|
}
|
2011-03-31 11:26:25 -07:00
|
|
|
}
|
|
|
|
ret res(bcx, retval);
|
|
|
|
}
|
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
fn trans_tup(@block_ctxt cx, vec[ast.elt] elts,
|
|
|
|
&ast.ann ann) -> result {
|
2011-02-10 15:00:16 -08:00
|
|
|
auto bcx = cx;
|
2011-04-17 14:24:45 +02:00
|
|
|
auto t = node_ann_type(bcx.fcx.lcx.ccx, ann);
|
2011-02-10 15:00:16 -08:00
|
|
|
auto tup_res = alloc_ty(bcx, t);
|
|
|
|
auto tup_val = tup_res.val;
|
|
|
|
bcx = tup_res.bcx;
|
|
|
|
|
2011-03-16 14:58:02 -07:00
|
|
|
find_scope_cx(cx).cleanups +=
|
|
|
|
vec(clean(bind drop_ty(_, tup_val, t)));
|
2010-11-24 18:10:52 -08:00
|
|
|
let int i = 0;
|
2011-02-10 15:00:16 -08:00
|
|
|
|
2010-11-30 16:31:43 -08:00
|
|
|
for (ast.elt e in elts) {
|
2011-04-20 18:52:04 -07:00
|
|
|
auto e_ty = ty.expr_ty(cx.fcx.lcx.ccx.tystore, e.expr);
|
2011-02-10 15:00:16 -08:00
|
|
|
auto src_res = trans_expr(bcx, e.expr);
|
|
|
|
bcx = src_res.bcx;
|
|
|
|
auto dst_res = GEP_tup_like(bcx, t, tup_val, vec(0, i));
|
|
|
|
bcx = dst_res.bcx;
|
|
|
|
bcx = copy_ty(src_res.bcx, INIT, dst_res.val, src_res.val, e_ty).bcx;
|
2010-11-24 18:10:52 -08:00
|
|
|
i += 1;
|
|
|
|
}
|
2011-02-10 15:00:16 -08:00
|
|
|
ret res(bcx, tup_val);
|
2010-11-24 18:10:52 -08:00
|
|
|
}
|
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
fn trans_vec(@block_ctxt cx, vec[@ast.expr] args,
|
|
|
|
&ast.ann ann) -> result {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
|
2010-12-21 12:13:51 -08:00
|
|
|
auto unit_ty = t;
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-03-17 17:39:47 -07:00
|
|
|
case (ty.ty_vec(?mt)) {
|
|
|
|
unit_ty = mt.ty;
|
2010-12-10 17:25:11 -08:00
|
|
|
}
|
|
|
|
case (_) {
|
2011-04-17 14:24:45 +02:00
|
|
|
cx.fcx.lcx.ccx.sess.bug("non-vec type in trans_vec");
|
2010-12-10 17:25:11 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-31 15:03:05 -08:00
|
|
|
auto bcx = cx;
|
|
|
|
auto unit_sz = size_of(bcx, unit_ty);
|
|
|
|
bcx = unit_sz.bcx;
|
2011-03-18 16:41:56 -07:00
|
|
|
auto data_sz = bcx.build.Mul(C_int(_vec.len[@ast.expr](args) as int),
|
|
|
|
unit_sz.val);
|
2010-12-10 17:25:11 -08:00
|
|
|
|
|
|
|
// FIXME: pass tydesc properly.
|
2011-01-31 15:03:05 -08:00
|
|
|
auto sub = trans_upcall(bcx, "upcall_new_vec", vec(data_sz, C_int(0)));
|
2011-02-10 15:00:16 -08:00
|
|
|
bcx = sub.bcx;
|
2010-12-10 17:25:11 -08:00
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llty = type_of(bcx.fcx.lcx.ccx, t);
|
2011-03-02 16:42:09 -08:00
|
|
|
auto vec_val = vi2p(bcx, sub.val, llty);
|
2011-03-16 14:58:02 -07:00
|
|
|
find_scope_cx(bcx).cleanups +=
|
|
|
|
vec(clean(bind drop_ty(_, vec_val, t)));
|
2010-12-10 17:25:11 -08:00
|
|
|
|
2011-02-10 15:00:16 -08:00
|
|
|
auto body = bcx.build.GEP(vec_val, vec(C_int(0),
|
|
|
|
C_int(abi.vec_elt_data)));
|
|
|
|
|
|
|
|
auto pseudo_tup_ty =
|
2011-04-20 18:52:04 -07:00
|
|
|
ty.mk_imm_tup(cx.fcx.lcx.ccx.tystore,
|
2011-04-22 12:27:28 -07:00
|
|
|
_vec.init_elt[ty.t](unit_ty,
|
2011-04-20 11:23:36 -07:00
|
|
|
_vec.len[@ast.expr](args)));
|
2010-12-10 17:25:11 -08:00
|
|
|
let int i = 0;
|
2011-02-10 15:00:16 -08:00
|
|
|
|
2010-12-10 17:25:11 -08:00
|
|
|
for (@ast.expr e in args) {
|
2011-02-10 15:00:16 -08:00
|
|
|
auto src_res = trans_expr(bcx, e);
|
|
|
|
bcx = src_res.bcx;
|
|
|
|
auto dst_res = GEP_tup_like(bcx, pseudo_tup_ty, body, vec(0, i));
|
|
|
|
bcx = dst_res.bcx;
|
2011-03-10 10:40:44 -08:00
|
|
|
|
|
|
|
// 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;
|
2011-04-22 17:00:46 -07:00
|
|
|
if (!ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tystore, unit_ty)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llunit_ty = type_of(cx.fcx.lcx.ccx, unit_ty);
|
2011-03-10 10:40:44 -08:00
|
|
|
dst_val = bcx.build.PointerCast(dst_res.val, T_ptr(llunit_ty));
|
|
|
|
} else {
|
|
|
|
dst_val = dst_res.val;
|
|
|
|
}
|
|
|
|
|
|
|
|
bcx = copy_ty(bcx, INIT, dst_val, src_res.val, unit_ty).bcx;
|
2010-12-10 17:25:11 -08:00
|
|
|
i += 1;
|
|
|
|
}
|
2011-02-10 15:00:16 -08:00
|
|
|
auto fill = bcx.build.GEP(vec_val,
|
|
|
|
vec(C_int(0), C_int(abi.vec_elt_fill)));
|
|
|
|
bcx.build.Store(data_sz, fill);
|
2010-12-13 11:16:04 -08:00
|
|
|
|
2011-02-10 15:00:16 -08:00
|
|
|
ret res(bcx, vec_val);
|
2010-12-10 17:25:11 -08:00
|
|
|
}
|
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
fn trans_rec(@block_ctxt cx, vec[ast.field] fields,
|
2011-02-14 15:52:38 -08:00
|
|
|
option.t[@ast.expr] base, &ast.ann ann) -> result {
|
|
|
|
|
2011-02-10 15:00:16 -08:00
|
|
|
auto bcx = cx;
|
2011-04-17 14:24:45 +02:00
|
|
|
auto t = node_ann_type(bcx.fcx.lcx.ccx, ann);
|
2011-02-10 15:00:16 -08:00
|
|
|
auto rec_res = alloc_ty(bcx, t);
|
|
|
|
auto rec_val = rec_res.val;
|
|
|
|
bcx = rec_res.bcx;
|
|
|
|
|
2011-03-16 14:58:02 -07:00
|
|
|
find_scope_cx(cx).cleanups +=
|
|
|
|
vec(clean(bind drop_ty(_, rec_val, t)));
|
2010-11-30 10:39:35 -08:00
|
|
|
let int i = 0;
|
2011-02-10 15:00:16 -08:00
|
|
|
|
2011-02-15 18:16:13 -08:00
|
|
|
auto base_val = C_nil();
|
|
|
|
|
|
|
|
alt (base) {
|
|
|
|
case (none[@ast.expr]) { }
|
|
|
|
case (some[@ast.expr](?bexp)) {
|
|
|
|
auto base_res = trans_expr(bcx, bexp);
|
|
|
|
bcx = base_res.bcx;
|
|
|
|
base_val = base_res.val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let vec[ty.field] ty_fields = vec();
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-02-15 18:16:13 -08:00
|
|
|
case (ty.ty_rec(?flds)) { ty_fields = flds; }
|
|
|
|
}
|
|
|
|
|
|
|
|
for (ty.field tf in ty_fields) {
|
2011-03-17 17:39:47 -07:00
|
|
|
auto e_ty = tf.mt.ty;
|
2011-02-10 15:00:16 -08:00
|
|
|
auto dst_res = GEP_tup_like(bcx, t, rec_val, vec(0, i));
|
|
|
|
bcx = dst_res.bcx;
|
2011-02-15 18:16:13 -08:00
|
|
|
|
|
|
|
auto expr_provided = false;
|
|
|
|
auto src_res = res(bcx, C_nil());
|
|
|
|
|
|
|
|
for (ast.field f in fields) {
|
|
|
|
if (_str.eq(f.ident, tf.ident)) {
|
|
|
|
expr_provided = true;
|
|
|
|
src_res = trans_expr(bcx, f.expr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!expr_provided) {
|
|
|
|
src_res = GEP_tup_like(bcx, t, base_val, vec(0, i));
|
|
|
|
src_res = res(src_res.bcx,
|
2011-04-12 12:06:20 -07:00
|
|
|
load_if_immediate(bcx, src_res.val, e_ty));
|
2011-02-15 18:16:13 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
bcx = src_res.bcx;
|
|
|
|
bcx = copy_ty(bcx, INIT, dst_res.val, src_res.val, e_ty).bcx;
|
2010-11-30 10:39:35 -08:00
|
|
|
i += 1;
|
|
|
|
}
|
2011-02-10 15:00:16 -08:00
|
|
|
ret res(bcx, rec_val);
|
2010-11-30 10:39:35 -08:00
|
|
|
}
|
|
|
|
|
2010-11-24 18:10:52 -08:00
|
|
|
|
2010-11-25 16:40:24 -08:00
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
fn trans_expr(@block_ctxt cx, @ast.expr e) -> result {
|
2010-10-05 18:21:44 -07:00
|
|
|
alt (e.node) {
|
2010-12-09 12:32:16 -08:00
|
|
|
case (ast.expr_lit(?lit, ?ann)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
ret res(cx, trans_lit(cx.fcx.lcx.ccx, *lit, ann));
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
|
|
|
|
2010-11-05 18:31:02 -07:00
|
|
|
case (ast.expr_unary(?op, ?x, ?ann)) {
|
2011-04-07 12:50:37 -07:00
|
|
|
if (op != ast.deref) {
|
|
|
|
ret trans_unary(cx, op, x, ann);
|
|
|
|
}
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
|
|
|
|
2010-10-19 13:28:43 -07:00
|
|
|
case (ast.expr_binary(?op, ?x, ?y, _)) {
|
2010-11-26 15:54:04 -08:00
|
|
|
ret trans_binary(cx, op, x, y);
|
2010-09-28 12:23:40 -07:00
|
|
|
}
|
2010-10-04 15:55:12 -07:00
|
|
|
|
2010-10-19 13:28:43 -07:00
|
|
|
case (ast.expr_if(?cond, ?thn, ?els, _)) {
|
2010-11-26 15:54:04 -08:00
|
|
|
ret trans_if(cx, cond, thn, els);
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
|
|
|
|
2011-01-21 07:59:06 -08:00
|
|
|
case (ast.expr_for(?decl, ?seq, ?body, _)) {
|
|
|
|
ret trans_for(cx, decl, seq, body);
|
|
|
|
}
|
|
|
|
|
2011-02-14 18:17:31 -08:00
|
|
|
case (ast.expr_for_each(?decl, ?seq, ?body, _)) {
|
|
|
|
ret trans_for_each(cx, decl, seq, body);
|
|
|
|
}
|
|
|
|
|
2010-11-03 11:05:15 -07:00
|
|
|
case (ast.expr_while(?cond, ?body, _)) {
|
2010-11-26 15:54:04 -08:00
|
|
|
ret trans_while(cx, cond, body);
|
2010-11-03 11:05:15 -07:00
|
|
|
}
|
|
|
|
|
2010-11-04 07:55:33 -07:00
|
|
|
case (ast.expr_do_while(?body, ?cond, _)) {
|
2010-11-26 15:54:04 -08:00
|
|
|
ret trans_do_while(cx, body, cond);
|
2010-11-04 07:55:33 -07:00
|
|
|
}
|
|
|
|
|
2011-04-02 19:06:19 -04:00
|
|
|
case (ast.expr_alt(?expr, ?arms, ?ann)) {
|
|
|
|
ret trans_alt(cx, expr, arms, ann);
|
2010-12-15 09:38:23 -08:00
|
|
|
}
|
|
|
|
|
2010-10-19 13:28:43 -07:00
|
|
|
case (ast.expr_block(?blk, _)) {
|
2011-03-31 00:46:26 -04:00
|
|
|
auto sub_cx = new_scope_block_ctxt(cx, "block-expr body");
|
|
|
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
|
|
|
auto sub = trans_block(sub_cx, blk);
|
|
|
|
|
|
|
|
cx.build.Br(sub_cx.llbb);
|
|
|
|
sub.bcx.build.Br(next_cx.llbb);
|
|
|
|
|
|
|
|
ret res(next_cx, sub.val);
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
2010-10-19 14:54:10 -07:00
|
|
|
|
2010-11-24 16:55:45 -08:00
|
|
|
case (ast.expr_assign(?dst, ?src, ?ann)) {
|
2010-11-26 15:54:04 -08:00
|
|
|
auto lhs_res = trans_lval(cx, dst);
|
2010-12-23 17:31:16 -08:00
|
|
|
check (lhs_res.is_mem);
|
|
|
|
auto rhs_res = trans_expr(lhs_res.res.bcx, src);
|
2011-04-17 14:24:45 +02:00
|
|
|
auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
|
2010-11-24 18:10:52 -08:00
|
|
|
// FIXME: calculate copy init-ness in typestate.
|
2011-01-24 15:26:10 -08:00
|
|
|
ret copy_ty(rhs_res.bcx, DROP_EXISTING,
|
|
|
|
lhs_res.res.val, rhs_res.val, t);
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2010-10-19 16:33:11 -07:00
|
|
|
|
2010-12-08 14:50:47 -08:00
|
|
|
case (ast.expr_assign_op(?op, ?dst, ?src, ?ann)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
|
2010-12-08 14:50:47 -08:00
|
|
|
auto lhs_res = trans_lval(cx, dst);
|
2010-12-23 17:31:16 -08:00
|
|
|
check (lhs_res.is_mem);
|
2011-04-12 12:06:20 -07:00
|
|
|
auto lhs_val = load_if_immediate(lhs_res.res.bcx,
|
2011-01-21 07:50:02 -08:00
|
|
|
lhs_res.res.val, t);
|
2010-12-23 17:31:16 -08:00
|
|
|
auto rhs_res = trans_expr(lhs_res.res.bcx, src);
|
2011-02-13 00:49:04 -05:00
|
|
|
auto v = trans_eager_binop(rhs_res.bcx, op, t,
|
|
|
|
lhs_val, rhs_res.val);
|
2010-12-08 14:50:47 -08:00
|
|
|
// FIXME: calculate copy init-ness in typestate.
|
2011-02-28 16:36:08 -08:00
|
|
|
ret copy_ty(v.bcx, DROP_EXISTING,
|
|
|
|
lhs_res.res.val, v.val, t);
|
2010-12-08 14:50:47 -08:00
|
|
|
}
|
|
|
|
|
2011-01-03 22:39:43 -08:00
|
|
|
case (ast.expr_bind(?f, ?args, ?ann)) {
|
|
|
|
ret trans_bind(cx, f, args, ann);
|
|
|
|
}
|
|
|
|
|
2010-12-08 16:20:04 -08:00
|
|
|
case (ast.expr_call(?f, ?args, ?ann)) {
|
2011-02-18 17:30:57 -08:00
|
|
|
ret trans_call(cx, f, none[ValueRef], args, ann);
|
2010-10-21 17:24:26 -07:00
|
|
|
}
|
|
|
|
|
2010-11-22 16:27:00 -08:00
|
|
|
case (ast.expr_cast(?e, _, ?ann)) {
|
2010-11-26 15:54:04 -08:00
|
|
|
ret trans_cast(cx, e, ann);
|
2010-11-22 16:27:00 -08:00
|
|
|
}
|
2010-11-24 18:10:52 -08:00
|
|
|
|
2011-03-17 17:39:47 -07:00
|
|
|
case (ast.expr_vec(?args, _, ?ann)) {
|
2010-12-10 17:25:11 -08:00
|
|
|
ret trans_vec(cx, args, ann);
|
|
|
|
}
|
|
|
|
|
2010-11-24 18:10:52 -08:00
|
|
|
case (ast.expr_tup(?args, ?ann)) {
|
|
|
|
ret trans_tup(cx, args, ann);
|
|
|
|
}
|
2010-11-25 16:40:24 -08:00
|
|
|
|
2011-02-14 15:52:38 -08:00
|
|
|
case (ast.expr_rec(?args, ?base, ?ann)) {
|
|
|
|
ret trans_rec(cx, args, base, ann);
|
2010-11-30 10:39:35 -08:00
|
|
|
}
|
|
|
|
|
2011-02-26 20:51:02 -05:00
|
|
|
case (ast.expr_ext(_, _, _, ?expanded, _)) {
|
2011-02-27 22:35:27 -05:00
|
|
|
ret trans_expr(cx, expanded);
|
2011-02-26 20:51:02 -05:00
|
|
|
}
|
|
|
|
|
2011-03-24 12:12:04 -07:00
|
|
|
case (ast.expr_fail(_)) {
|
2011-04-19 15:22:57 -07:00
|
|
|
ret trans_fail(cx, some[common.span](e.span), "explicit failure");
|
2011-02-14 17:46:28 -08:00
|
|
|
}
|
|
|
|
|
2011-04-19 11:21:23 +02:00
|
|
|
case (ast.expr_log(?lvl, ?a, _)) {
|
|
|
|
ret trans_log(lvl, cx, a);
|
2011-02-14 17:46:28 -08:00
|
|
|
}
|
|
|
|
|
2011-03-24 12:12:04 -07:00
|
|
|
case (ast.expr_check_expr(?a, _)) {
|
2011-02-14 17:46:28 -08:00
|
|
|
ret trans_check_expr(cx, a);
|
|
|
|
}
|
|
|
|
|
2011-03-24 12:12:04 -07:00
|
|
|
case (ast.expr_break(?a)) {
|
2011-03-25 16:28:16 +01:00
|
|
|
ret trans_break(cx);
|
|
|
|
}
|
|
|
|
|
2011-03-24 12:12:04 -07:00
|
|
|
case (ast.expr_cont(?a)) {
|
2011-03-25 16:28:16 +01:00
|
|
|
ret trans_cont(cx);
|
|
|
|
}
|
|
|
|
|
2011-03-24 12:12:04 -07:00
|
|
|
case (ast.expr_ret(?e, _)) {
|
2011-02-14 17:46:28 -08:00
|
|
|
ret trans_ret(cx, e);
|
|
|
|
}
|
|
|
|
|
2011-03-24 12:12:04 -07:00
|
|
|
case (ast.expr_put(?e, _)) {
|
2011-02-14 17:58:32 -08:00
|
|
|
ret trans_put(cx, e);
|
|
|
|
}
|
|
|
|
|
2011-03-24 12:12:04 -07:00
|
|
|
case (ast.expr_be(?e, _)) {
|
2011-02-14 17:46:28 -08:00
|
|
|
ret trans_be(cx, e);
|
|
|
|
}
|
|
|
|
|
2011-03-16 21:49:15 -04:00
|
|
|
case (ast.expr_port(?ann)) {
|
|
|
|
ret trans_port(cx, ann);
|
|
|
|
}
|
|
|
|
|
|
|
|
case (ast.expr_chan(?e, ?ann)) {
|
|
|
|
ret trans_chan(cx, e, ann);
|
|
|
|
}
|
|
|
|
|
|
|
|
case (ast.expr_send(?lhs, ?rhs, ?ann)) {
|
|
|
|
ret trans_send(cx, lhs, rhs, ann);
|
|
|
|
}
|
|
|
|
|
|
|
|
case (ast.expr_recv(?lhs, ?rhs, ?ann)) {
|
|
|
|
ret trans_recv(cx, lhs, rhs, ann);
|
|
|
|
}
|
|
|
|
|
2010-11-26 15:54:04 -08:00
|
|
|
case (_) {
|
2011-04-07 12:50:37 -07:00
|
|
|
// The expression is an lvalue. Fall through.
|
2010-11-26 15:54:04 -08:00
|
|
|
}
|
2010-09-28 12:23:40 -07:00
|
|
|
}
|
2011-04-07 12:50:37 -07:00
|
|
|
|
|
|
|
// lval cases fall through to trans_lval and then
|
|
|
|
// possibly load the result (if it's non-structural).
|
|
|
|
|
2011-04-20 18:52:04 -07:00
|
|
|
auto t = ty.expr_ty(cx.fcx.lcx.ccx.tystore, e);
|
2011-04-07 12:50:37 -07:00
|
|
|
auto sub = trans_lval(cx, e);
|
2011-04-12 12:06:20 -07:00
|
|
|
ret res(sub.res.bcx, load_if_immediate(sub.res.bcx, sub.res.val, t));
|
2010-09-28 12:23:40 -07:00
|
|
|
}
|
|
|
|
|
2010-12-03 13:03:07 -08:00
|
|
|
// We pass structural values around the compiler "by pointer" and
|
2011-04-12 12:06:20 -07:00
|
|
|
// 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.
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
fn type_is_immediate(@crate_ctxt ccx, ty.t t) -> bool {
|
|
|
|
ret ty.type_is_scalar(ccx.tystore, t) ||
|
|
|
|
ty.type_is_boxed(ccx.tystore, t) ||
|
|
|
|
ty.type_is_native(ccx.tystore, t);
|
2011-04-12 12:06:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn do_spill(@block_ctxt cx, ValueRef v) -> ValueRef {
|
|
|
|
// We have a value but we have to spill it to pass by alias.
|
|
|
|
auto llptr = alloca(cx, val_ty(v));
|
|
|
|
cx.build.Store(v, llptr);
|
|
|
|
ret llptr;
|
|
|
|
}
|
2010-12-03 13:03:07 -08:00
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn spill_if_immediate(@block_ctxt cx, ValueRef v, ty.t t) -> ValueRef {
|
2011-04-22 17:00:46 -07:00
|
|
|
if (type_is_immediate(cx.fcx.lcx.ccx, t)) {
|
2011-04-12 12:06:20 -07:00
|
|
|
ret do_spill(cx, v);
|
|
|
|
}
|
|
|
|
ret v;
|
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn load_if_immediate(@block_ctxt cx, ValueRef v, ty.t t) -> ValueRef {
|
2011-04-22 17:00:46 -07:00
|
|
|
if (type_is_immediate(cx.fcx.lcx.ccx, t)) {
|
2010-12-03 13:03:07 -08:00
|
|
|
ret cx.build.Load(v);
|
|
|
|
}
|
2011-04-12 12:06:20 -07:00
|
|
|
ret v;
|
2010-12-03 13:03:07 -08:00
|
|
|
}
|
|
|
|
|
2011-04-19 11:21:23 +02:00
|
|
|
fn trans_log(int lvl, @block_ctxt cx, @ast.expr e) -> result {
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
auto lcx = cx.fcx.lcx;
|
|
|
|
auto modname = _str.connect(lcx.module_path, ".");
|
|
|
|
auto global;
|
|
|
|
if (lcx.ccx.module_data.contains_key(modname)) {
|
|
|
|
global = lcx.ccx.module_data.get(modname);
|
|
|
|
} else {
|
|
|
|
global = llvm.LLVMAddGlobal(lcx.ccx.llmod, T_int(),
|
|
|
|
_str.buf("_rust_mod_log_" + modname));
|
|
|
|
llvm.LLVMSetGlobalConstant(global, False);
|
|
|
|
llvm.LLVMSetInitializer(global, C_null(T_int()));
|
|
|
|
llvm.LLVMSetLinkage(global, lib.llvm.LLVMInternalLinkage
|
|
|
|
as llvm.Linkage);
|
|
|
|
lcx.ccx.module_data.insert(modname, global);
|
|
|
|
}
|
|
|
|
|
2011-04-20 04:55:55 +00:00
|
|
|
auto log_cx = new_scope_block_ctxt(cx, "log");
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
auto after_cx = new_sub_block_ctxt(cx, "after");
|
|
|
|
auto load = cx.build.Load(global);
|
2011-04-19 11:21:23 +02:00
|
|
|
auto test = cx.build.ICmp(lib.llvm.LLVMIntSGE, load, C_int(lvl));
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
cx.build.CondBr(test, log_cx.llbb, after_cx.llbb);
|
|
|
|
|
|
|
|
auto sub = trans_expr(log_cx, e);
|
2011-04-20 18:52:04 -07:00
|
|
|
auto e_ty = ty.expr_ty(cx.fcx.lcx.ccx.tystore, e);
|
2011-03-24 12:12:04 -07:00
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_is_fp(cx.fcx.lcx.ccx.tystore, e_ty)) {
|
2011-03-22 17:25:40 -07:00
|
|
|
let TypeRef tr;
|
|
|
|
let bool is32bit = false;
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.fcx.lcx.ccx.tystore, e_ty)) {
|
2011-03-22 17:25:40 -07:00
|
|
|
case (ty.ty_machine(util.common.ty_f32)) {
|
|
|
|
tr = T_f32();
|
|
|
|
is32bit = true;
|
|
|
|
}
|
|
|
|
case (ty.ty_machine(util.common.ty_f64)) {
|
|
|
|
tr = T_f64();
|
|
|
|
}
|
|
|
|
case (_) {
|
|
|
|
tr = T_float();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (is32bit) {
|
2011-04-19 12:02:06 +02:00
|
|
|
auto uval = trans_upcall(sub.bcx,
|
|
|
|
"upcall_log_float",
|
|
|
|
vec(C_int(lvl), sub.val));
|
|
|
|
uval.bcx.build.Br(after_cx.llbb);
|
2011-03-22 17:25:40 -07:00
|
|
|
} else {
|
2011-03-28 18:04:52 -07:00
|
|
|
auto tmp = alloca(sub.bcx, tr);
|
2011-03-21 17:12:05 -07:00
|
|
|
sub.bcx.build.Store(sub.val, tmp);
|
2011-04-19 12:02:06 +02:00
|
|
|
auto uval = trans_upcall(sub.bcx,
|
|
|
|
"upcall_log_double",
|
|
|
|
vec(C_int(lvl), vp2i(sub.bcx, tmp)));
|
|
|
|
uval.bcx.build.Br(after_cx.llbb);
|
2011-03-21 17:12:05 -07:00
|
|
|
}
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
} else {
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.fcx.lcx.ccx.tystore, e_ty)) {
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
case (ty.ty_str) {
|
|
|
|
auto v = vp2i(sub.bcx, sub.val);
|
|
|
|
trans_upcall(sub.bcx,
|
2010-12-08 15:29:09 -08:00
|
|
|
"upcall_log_str",
|
2011-04-19 11:21:23 +02:00
|
|
|
vec(C_int(lvl), v)).bcx.build.Br(after_cx.llbb);
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
}
|
|
|
|
case (_) {
|
2011-04-19 11:21:23 +02:00
|
|
|
auto v = vec(C_int(lvl), sub.val);
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
trans_upcall(sub.bcx,
|
2010-12-08 15:29:09 -08:00
|
|
|
"upcall_log_int",
|
2011-04-19 11:21:23 +02:00
|
|
|
v).bcx.build.Br(after_cx.llbb);
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
}
|
2010-09-23 18:38:37 -07:00
|
|
|
}
|
|
|
|
}
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
|
|
|
|
ret res(after_cx, C_nil());
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
fn trans_check_expr(@block_ctxt cx, @ast.expr e) -> result {
|
2010-10-22 15:37:42 -07:00
|
|
|
auto cond_res = trans_expr(cx, e);
|
|
|
|
|
2011-04-01 17:20:22 -07:00
|
|
|
auto expr_str = pretty.pprust.expr_to_str(e);
|
2010-11-10 17:46:49 -08:00
|
|
|
auto fail_cx = new_sub_block_ctxt(cx, "fail");
|
2011-04-19 15:22:57 -07:00
|
|
|
auto fail_res = trans_fail(fail_cx, some[common.span](e.span), expr_str);
|
2010-10-22 15:37:42 -07:00
|
|
|
|
2010-11-10 17:46:49 -08:00
|
|
|
auto next_cx = new_sub_block_ctxt(cx, "next");
|
2010-10-22 15:37:42 -07:00
|
|
|
cond_res.bcx.build.CondBr(cond_res.val,
|
|
|
|
next_cx.llbb,
|
|
|
|
fail_cx.llbb);
|
|
|
|
ret res(next_cx, C_nil());
|
|
|
|
}
|
|
|
|
|
2011-04-19 15:22:57 -07:00
|
|
|
fn trans_fail(@block_ctxt cx, option.t[common.span] sp_opt, str fail_str)
|
|
|
|
-> result {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto V_fail_str = p2i(C_cstr(cx.fcx.lcx.ccx, fail_str));
|
2011-04-19 15:22:57 -07:00
|
|
|
|
|
|
|
auto V_filename; auto V_line;
|
|
|
|
alt (sp_opt) {
|
|
|
|
case (some[common.span](?sp)) {
|
|
|
|
auto loc = cx.fcx.lcx.ccx.sess.lookup_pos(sp.lo);
|
|
|
|
V_filename = p2i(C_cstr(cx.fcx.lcx.ccx, loc.filename));
|
|
|
|
V_line = loc.line as int;
|
|
|
|
}
|
|
|
|
case (none[common.span]) {
|
|
|
|
V_filename = p2i(C_str(cx.fcx.lcx.ccx, "<runtime>"));
|
|
|
|
V_line = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-28 00:09:26 -05:00
|
|
|
auto args = vec(V_fail_str, V_filename, C_int(V_line));
|
|
|
|
|
2011-04-02 13:55:29 -04:00
|
|
|
auto sub = trans_upcall(cx, "upcall_fail", args);
|
|
|
|
sub.bcx.build.Unreachable();
|
|
|
|
ret res(sub.bcx, C_nil());
|
2011-01-28 00:09:26 -05:00
|
|
|
}
|
|
|
|
|
2011-02-14 17:58:32 -08:00
|
|
|
fn trans_put(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
|
2011-02-18 18:52:16 -08:00
|
|
|
auto llcallee = C_nil();
|
|
|
|
auto llenv = C_nil();
|
|
|
|
|
|
|
|
alt (cx.fcx.lliterbody) {
|
|
|
|
case (some[ValueRef](?lli)) {
|
2011-03-28 18:04:52 -07:00
|
|
|
auto slot = alloca(cx, val_ty(lli));
|
2011-02-18 18:52:16 -08:00
|
|
|
cx.build.Store(lli, slot);
|
|
|
|
|
|
|
|
llcallee = cx.build.GEP(slot, vec(C_int(0),
|
|
|
|
C_int(abi.fn_field_code)));
|
|
|
|
llcallee = cx.build.Load(llcallee);
|
|
|
|
|
|
|
|
llenv = cx.build.GEP(slot, vec(C_int(0),
|
|
|
|
C_int(abi.fn_field_box)));
|
|
|
|
llenv = cx.build.Load(llenv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
auto bcx = cx;
|
2011-03-28 18:04:52 -07:00
|
|
|
auto dummy_retslot = alloca(bcx, T_nil());
|
2011-02-18 18:52:16 -08:00
|
|
|
let vec[ValueRef] llargs = vec(dummy_retslot, cx.fcx.lltaskptr, llenv);
|
|
|
|
alt (e) {
|
|
|
|
case (none[@ast.expr]) { }
|
|
|
|
case (some[@ast.expr](?x)) {
|
2011-04-23 14:17:44 -07:00
|
|
|
auto e_ty = ty.expr_ty(cx.fcx.lcx.ccx.tystore, x);
|
|
|
|
auto arg = rec(mode=ast.alias, ty=e_ty);
|
|
|
|
auto arg_tys = type_of_explicit_args(cx.fcx.lcx.ccx, vec(arg));
|
|
|
|
auto r = trans_arg_expr(bcx, arg, arg_tys.(0), x);
|
2011-02-18 18:52:16 -08:00
|
|
|
bcx = r.bcx;
|
2011-04-23 14:17:44 -07:00
|
|
|
llargs += vec(r.val);
|
2011-02-18 18:52:16 -08:00
|
|
|
}
|
|
|
|
}
|
2011-03-11 14:28:49 -08:00
|
|
|
|
2011-02-18 18:52:16 -08:00
|
|
|
ret res(bcx, bcx.build.FastCall(llcallee, llargs));
|
2011-02-14 17:58:32 -08:00
|
|
|
}
|
|
|
|
|
2011-03-25 16:28:16 +01:00
|
|
|
fn trans_break_cont(@block_ctxt cx, bool to_end) -> result {
|
|
|
|
auto bcx = cx;
|
|
|
|
// Locate closest loop block, outputting cleanup as we go.
|
|
|
|
auto cleanup_cx = cx;
|
|
|
|
while (true) {
|
|
|
|
bcx = trans_block_cleanups(bcx, cleanup_cx);
|
|
|
|
alt (cleanup_cx.kind) {
|
|
|
|
case (LOOP_SCOPE_BLOCK(?_cont, ?_break)) {
|
|
|
|
if (to_end) {
|
|
|
|
bcx.build.Br(_break.llbb);
|
|
|
|
} else {
|
|
|
|
alt (_cont) {
|
|
|
|
case (option.some[@block_ctxt](?_cont)) {
|
|
|
|
bcx.build.Br(_cont.llbb);
|
|
|
|
}
|
|
|
|
case (_) {
|
|
|
|
bcx.build.Br(cleanup_cx.llbb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret res(new_sub_block_ctxt(cx, "unreachable"), C_nil());
|
|
|
|
}
|
|
|
|
case (_) {
|
|
|
|
alt (cleanup_cx.parent) {
|
|
|
|
case (parent_some(?cx)) { cleanup_cx = cx; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret res(cx, C_nil()); // Never reached. Won't compile otherwise.
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trans_break(@block_ctxt cx) -> result {
|
|
|
|
ret trans_break_cont(cx, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trans_cont(@block_ctxt cx) -> result {
|
|
|
|
ret trans_break_cont(cx, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
fn trans_ret(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
|
|
|
|
auto bcx = cx;
|
|
|
|
auto val = C_nil();
|
|
|
|
|
2010-10-22 19:23:10 -07:00
|
|
|
alt (e) {
|
|
|
|
case (some[@ast.expr](?x)) {
|
2011-04-20 18:52:04 -07:00
|
|
|
auto t = ty.expr_ty(cx.fcx.lcx.ccx.tystore, x);
|
2011-01-21 07:58:16 -08:00
|
|
|
auto r = trans_expr(cx, x);
|
|
|
|
bcx = r.bcx;
|
|
|
|
val = r.val;
|
2011-02-08 11:47:53 -08:00
|
|
|
bcx = copy_ty(bcx, INIT, cx.fcx.llretptr, val, t).bcx;
|
2010-10-22 19:23:10 -07:00
|
|
|
}
|
2010-12-01 17:08:46 -08:00
|
|
|
case (_) { /* fall through */ }
|
2010-10-22 19:23:10 -07:00
|
|
|
}
|
|
|
|
|
2010-11-10 17:46:49 -08:00
|
|
|
// Run all cleanups and back out.
|
|
|
|
let bool more_cleanups = true;
|
2010-11-14 10:48:44 -08:00
|
|
|
auto cleanup_cx = cx;
|
2010-11-10 17:46:49 -08:00
|
|
|
while (more_cleanups) {
|
2011-01-21 07:58:16 -08:00
|
|
|
bcx = trans_block_cleanups(bcx, cleanup_cx);
|
2010-11-14 10:48:44 -08:00
|
|
|
alt (cleanup_cx.parent) {
|
2010-11-10 17:46:49 -08:00
|
|
|
case (parent_some(?b)) {
|
2010-11-14 10:48:44 -08:00
|
|
|
cleanup_cx = b;
|
2010-11-10 17:46:49 -08:00
|
|
|
}
|
|
|
|
case (parent_none) {
|
|
|
|
more_cleanups = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
bcx.build.RetVoid();
|
|
|
|
ret res(bcx, C_nil());
|
2010-10-22 19:23:10 -07:00
|
|
|
}
|
|
|
|
|
2011-01-30 17:18:19 -05:00
|
|
|
fn trans_be(@block_ctxt cx, @ast.expr e) -> result {
|
2011-02-09 22:36:37 -05:00
|
|
|
// FIXME: This should be a typestate precondition
|
2011-02-14 16:33:51 -08:00
|
|
|
check (ast.is_call_expr(e));
|
2011-02-09 22:36:37 -05:00
|
|
|
// FIXME: Turn this into a real tail call once
|
|
|
|
// calling convention issues are settled
|
2011-01-30 17:18:19 -05:00
|
|
|
ret trans_ret(cx, some(e));
|
|
|
|
}
|
|
|
|
|
2011-03-16 21:49:15 -04:00
|
|
|
fn trans_port(@block_ctxt cx, ast.ann ann) -> result {
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
auto t = node_ann_type(cx.fcx.lcx.ccx, ann);
|
2011-03-16 21:49:15 -04:00
|
|
|
auto unit_ty;
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-03-16 21:49:15 -04:00
|
|
|
case (ty.ty_port(?t)) {
|
|
|
|
unit_ty = t;
|
|
|
|
}
|
|
|
|
case (_) {
|
2011-04-17 14:24:45 +02:00
|
|
|
cx.fcx.lcx.ccx.sess.bug("non-port type in trans_port");
|
2011-03-16 21:49:15 -04:00
|
|
|
fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llunit_ty = type_of(cx.fcx.lcx.ccx, unit_ty);
|
2011-03-16 21:49:15 -04:00
|
|
|
|
|
|
|
auto bcx = cx;
|
|
|
|
auto unit_sz = size_of(bcx, unit_ty);
|
|
|
|
bcx = unit_sz.bcx;
|
|
|
|
auto sub = trans_upcall(bcx, "upcall_new_port", vec(unit_sz.val));
|
|
|
|
bcx = sub.bcx;
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llty = type_of(cx.fcx.lcx.ccx, t);
|
2011-03-16 21:49:15 -04:00
|
|
|
auto port_val = vi2p(bcx, sub.val, llty);
|
|
|
|
auto dropref = clean(bind drop_ty(_, port_val, t));
|
|
|
|
find_scope_cx(bcx).cleanups += vec(dropref);
|
|
|
|
|
|
|
|
ret res(bcx, port_val);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trans_chan(@block_ctxt cx, @ast.expr e, ast.ann ann) -> result {
|
|
|
|
|
|
|
|
auto bcx = cx;
|
|
|
|
auto prt = trans_expr(bcx, e);
|
|
|
|
bcx = prt.bcx;
|
|
|
|
|
|
|
|
auto prt_val = vp2i(bcx, prt.val);
|
|
|
|
auto sub = trans_upcall(bcx, "upcall_new_chan", vec(prt_val));
|
|
|
|
bcx = sub.bcx;
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
auto chan_ty = node_ann_type(bcx.fcx.lcx.ccx, ann);
|
|
|
|
auto chan_llty = type_of(bcx.fcx.lcx.ccx, chan_ty);
|
2011-03-16 21:49:15 -04:00
|
|
|
auto chan_val = vi2p(bcx, sub.val, chan_llty);
|
|
|
|
auto dropref = clean(bind drop_ty(_, chan_val, chan_ty));
|
|
|
|
find_scope_cx(bcx).cleanups += vec(dropref);
|
|
|
|
|
|
|
|
ret res(bcx, chan_val);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trans_send(@block_ctxt cx, @ast.expr lhs, @ast.expr rhs,
|
|
|
|
ast.ann ann) -> result {
|
2011-03-17 23:33:00 -04:00
|
|
|
|
|
|
|
auto bcx = cx;
|
|
|
|
auto chn = trans_expr(bcx, lhs);
|
|
|
|
bcx = chn.bcx;
|
|
|
|
auto data = trans_expr(bcx, rhs);
|
|
|
|
bcx = data.bcx;
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
auto chan_ty = node_ann_type(cx.fcx.lcx.ccx, ann);
|
2011-03-17 23:33:00 -04:00
|
|
|
auto unit_ty;
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.fcx.lcx.ccx.tystore, chan_ty)) {
|
2011-03-17 23:33:00 -04:00
|
|
|
case (ty.ty_chan(?t)) {
|
|
|
|
unit_ty = t;
|
|
|
|
}
|
|
|
|
case (_) {
|
2011-04-17 14:24:45 +02:00
|
|
|
bcx.fcx.lcx.ccx.sess.bug("non-chan type in trans_send");
|
2011-03-17 23:33:00 -04:00
|
|
|
fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-21 21:13:08 -04:00
|
|
|
auto data_alloc = alloc_ty(bcx, unit_ty);
|
|
|
|
bcx = data_alloc.bcx;
|
|
|
|
auto data_tmp = copy_ty(bcx, INIT, data_alloc.val, data.val, unit_ty);
|
|
|
|
bcx = data_tmp.bcx;
|
2011-03-17 23:33:00 -04:00
|
|
|
|
2011-03-21 22:32:11 -04:00
|
|
|
find_scope_cx(bcx).cleanups +=
|
|
|
|
vec(clean(bind drop_ty(_, data_alloc.val, unit_ty)));
|
2011-03-17 23:33:00 -04:00
|
|
|
|
2011-03-21 21:13:08 -04:00
|
|
|
auto sub = trans_upcall(bcx, "upcall_send",
|
|
|
|
vec(vp2i(bcx, chn.val),
|
|
|
|
vp2i(bcx, data_alloc.val)));
|
2011-03-17 23:33:00 -04:00
|
|
|
bcx = sub.bcx;
|
|
|
|
|
2011-03-21 21:13:08 -04:00
|
|
|
ret res(bcx, chn.val);
|
2011-03-16 21:49:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn trans_recv(@block_ctxt cx, @ast.expr lhs, @ast.expr rhs,
|
|
|
|
ast.ann ann) -> result {
|
2011-03-17 23:33:00 -04:00
|
|
|
|
|
|
|
auto bcx = cx;
|
2011-03-18 00:45:18 -04:00
|
|
|
auto data = trans_lval(bcx, lhs);
|
|
|
|
check (data.is_mem);
|
|
|
|
bcx = data.res.bcx;
|
2011-04-17 14:24:45 +02:00
|
|
|
auto unit_ty = node_ann_type(bcx.fcx.lcx.ccx, ann);
|
2011-03-24 21:54:19 -04:00
|
|
|
|
|
|
|
// FIXME: calculate copy init-ness in typestate.
|
|
|
|
ret recv_val(bcx, data.res.val, rhs, unit_ty, DROP_EXISTING);
|
2011-04-01 16:04:22 -07:00
|
|
|
}
|
2011-03-24 21:54:19 -04:00
|
|
|
|
|
|
|
fn recv_val(@block_ctxt cx, ValueRef lhs, @ast.expr rhs,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t unit_ty, copy_action action) -> result {
|
2011-03-24 21:54:19 -04:00
|
|
|
|
|
|
|
auto bcx = cx;
|
2011-03-17 23:33:00 -04:00
|
|
|
auto prt = trans_expr(bcx, rhs);
|
|
|
|
bcx = prt.bcx;
|
2011-03-18 00:45:18 -04:00
|
|
|
|
2011-03-21 21:13:08 -04:00
|
|
|
auto sub = trans_upcall(bcx, "upcall_recv",
|
2011-03-24 21:54:19 -04:00
|
|
|
vec(vp2i(bcx, lhs),
|
2011-03-21 21:13:08 -04:00
|
|
|
vp2i(bcx, prt.val)));
|
|
|
|
bcx = sub.bcx;
|
|
|
|
|
2011-04-12 12:06:20 -07:00
|
|
|
auto data_load = load_if_immediate(bcx, lhs, unit_ty);
|
2011-03-24 21:54:19 -04:00
|
|
|
auto cp = copy_ty(bcx, action, lhs, data_load, unit_ty);
|
2011-03-21 21:13:08 -04:00
|
|
|
bcx = cp.bcx;
|
2011-03-18 00:45:18 -04:00
|
|
|
|
2011-03-21 22:32:11 -04:00
|
|
|
// TODO: Any cleanup need to be done here?
|
2011-03-17 23:33:00 -04:00
|
|
|
|
2011-03-24 21:54:19 -04:00
|
|
|
ret res(bcx, lhs);
|
2011-03-16 21:49:15 -04:00
|
|
|
}
|
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
fn init_local(@block_ctxt cx, @ast.local local) -> result {
|
|
|
|
|
|
|
|
// Make a note to drop this slot on the way out.
|
|
|
|
check (cx.fcx.lllocals.contains_key(local.id));
|
|
|
|
auto llptr = cx.fcx.lllocals.get(local.id);
|
2011-04-17 14:24:45 +02:00
|
|
|
auto ty = node_ann_type(cx.fcx.lcx.ccx, local.ann);
|
2011-01-21 07:58:16 -08:00
|
|
|
auto bcx = cx;
|
|
|
|
|
|
|
|
find_scope_cx(cx).cleanups +=
|
2011-03-16 14:58:02 -07:00
|
|
|
vec(clean(bind drop_slot(_, llptr, ty)));
|
2011-01-21 07:58:16 -08:00
|
|
|
|
|
|
|
alt (local.init) {
|
2011-03-24 21:04:29 -04:00
|
|
|
case (some[ast.initializer](?init)) {
|
2011-03-24 21:54:19 -04:00
|
|
|
alt (init.op) {
|
|
|
|
case (ast.init_assign) {
|
|
|
|
auto sub = trans_expr(bcx, init.expr);
|
|
|
|
bcx = copy_ty(sub.bcx, INIT, llptr, sub.val, ty).bcx;
|
|
|
|
}
|
|
|
|
case (ast.init_recv) {
|
|
|
|
bcx = recv_val(bcx, llptr, init.expr, ty, INIT).bcx;
|
|
|
|
}
|
|
|
|
}
|
2011-01-21 07:58:16 -08:00
|
|
|
}
|
|
|
|
case (_) {
|
2011-04-05 23:42:33 -04:00
|
|
|
bcx = zero_alloca(bcx, llptr, ty).bcx;
|
2011-01-21 07:58:16 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ret res(bcx, llptr);
|
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn zero_alloca(@block_ctxt cx, ValueRef llptr, ty.t t) -> result {
|
2011-04-05 23:42:33 -04:00
|
|
|
auto bcx = cx;
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-04-05 23:42:33 -04:00
|
|
|
auto llsz = size_of(bcx, t);
|
|
|
|
bcx = call_bzero(llsz.bcx, llptr, llsz.val).bcx;
|
|
|
|
} else {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llty = type_of(bcx.fcx.lcx.ccx, t);
|
2011-04-05 23:42:33 -04:00
|
|
|
auto null = lib.llvm.llvm.LLVMConstNull(llty);
|
|
|
|
bcx.build.Store(null, llptr);
|
|
|
|
}
|
|
|
|
ret res(bcx, llptr);
|
|
|
|
}
|
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
|
|
|
|
auto bcx = cx;
|
2010-10-05 18:21:44 -07:00
|
|
|
alt (s.node) {
|
2011-04-06 17:56:44 -07:00
|
|
|
case (ast.stmt_expr(?e,_)) {
|
2011-01-21 07:58:16 -08:00
|
|
|
bcx = trans_expr(cx, e).bcx;
|
2010-09-23 13:15:51 -07:00
|
|
|
}
|
2010-10-04 15:55:12 -07:00
|
|
|
|
2011-04-06 17:56:44 -07:00
|
|
|
case (ast.stmt_decl(?d,_)) {
|
2010-10-19 14:54:10 -07:00
|
|
|
alt (d.node) {
|
|
|
|
case (ast.decl_local(?local)) {
|
2011-01-21 07:58:16 -08:00
|
|
|
bcx = init_local(bcx, local).bcx;
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2010-12-31 15:16:11 -08:00
|
|
|
case (ast.decl_item(?i)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
trans_item(cx.fcx.lcx, *i);
|
2010-12-31 15:16:11 -08:00
|
|
|
}
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
|
|
|
}
|
2010-09-23 13:15:51 -07:00
|
|
|
case (_) {
|
2011-04-17 14:24:45 +02:00
|
|
|
cx.fcx.lcx.ccx.sess.unimpl("stmt variant");
|
2010-09-23 13:15:51 -07:00
|
|
|
}
|
|
|
|
}
|
2011-01-21 07:58:16 -08:00
|
|
|
ret res(bcx, C_nil());
|
2010-10-01 18:25:42 -07:00
|
|
|
}
|
|
|
|
|
2010-12-17 18:42:15 -08:00
|
|
|
fn new_builder(BasicBlockRef llbb) -> builder {
|
2010-09-27 13:43:53 -07:00
|
|
|
let BuilderRef llbuild = llvm.LLVMCreateBuilder();
|
|
|
|
llvm.LLVMPositionBuilderAtEnd(llbuild, llbb);
|
2011-04-19 10:23:49 -07:00
|
|
|
ret builder(llbuild, @mutable false);
|
2010-09-27 13:43:53 -07:00
|
|
|
}
|
|
|
|
|
2010-10-04 15:55:12 -07:00
|
|
|
// You probably don't want to use this one. See the
|
|
|
|
// next three functions instead.
|
2010-11-10 17:46:49 -08:00
|
|
|
fn new_block_ctxt(@fn_ctxt cx, block_parent parent,
|
2011-01-24 15:26:10 -08:00
|
|
|
block_kind kind,
|
2010-11-10 17:46:49 -08:00
|
|
|
str name) -> @block_ctxt {
|
2010-12-02 19:12:34 -08:00
|
|
|
let vec[cleanup] cleanups = vec();
|
2010-09-22 17:05:38 -07:00
|
|
|
let BasicBlockRef llbb =
|
2010-11-10 17:46:49 -08:00
|
|
|
llvm.LLVMAppendBasicBlock(cx.llfn,
|
2011-04-17 14:24:45 +02:00
|
|
|
_str.buf(cx.lcx.ccx.names.next(name)));
|
2010-11-10 17:46:49 -08:00
|
|
|
|
2010-09-27 15:38:34 -07:00
|
|
|
ret @rec(llbb=llbb,
|
2010-12-17 18:42:15 -08:00
|
|
|
build=new_builder(llbb),
|
2010-11-10 17:46:49 -08:00
|
|
|
parent=parent,
|
2011-01-24 15:26:10 -08:00
|
|
|
kind=kind,
|
2010-09-29 17:22:07 -07:00
|
|
|
mutable cleanups=cleanups,
|
2010-09-27 15:38:34 -07:00
|
|
|
fcx=cx);
|
|
|
|
}
|
|
|
|
|
2010-10-04 15:55:12 -07:00
|
|
|
// Use this when you're at the top block of a function or the like.
|
|
|
|
fn new_top_block_ctxt(@fn_ctxt fcx) -> @block_ctxt {
|
2011-03-28 11:10:47 -07:00
|
|
|
ret new_block_ctxt(fcx, parent_none, SCOPE_BLOCK,
|
|
|
|
"function top level");
|
2010-12-02 19:12:34 -08:00
|
|
|
}
|
2010-10-04 15:55:12 -07:00
|
|
|
|
2010-12-02 19:12:34 -08:00
|
|
|
// Use this when you're at a curly-brace or similar lexical scope.
|
|
|
|
fn new_scope_block_ctxt(@block_ctxt bcx, str n) -> @block_ctxt {
|
2011-01-24 15:26:10 -08:00
|
|
|
ret new_block_ctxt(bcx.fcx, parent_some(bcx), SCOPE_BLOCK, n);
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
|
|
|
|
2011-03-25 16:28:16 +01:00
|
|
|
fn new_loop_scope_block_ctxt(@block_ctxt bcx, option.t[@block_ctxt] _cont,
|
|
|
|
@block_ctxt _break, str n) -> @block_ctxt {
|
|
|
|
ret new_block_ctxt(bcx.fcx, parent_some(bcx),
|
|
|
|
LOOP_SCOPE_BLOCK(_cont, _break), n);
|
|
|
|
}
|
|
|
|
|
2010-12-02 19:12:34 -08:00
|
|
|
// Use this when you're making a general CFG BB within a scope.
|
2010-11-10 17:46:49 -08:00
|
|
|
fn new_sub_block_ctxt(@block_ctxt bcx, str n) -> @block_ctxt {
|
2011-01-24 15:26:10 -08:00
|
|
|
ret new_block_ctxt(bcx.fcx, parent_some(bcx), NON_SCOPE_BLOCK, n);
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
2010-09-29 17:22:07 -07:00
|
|
|
|
2010-11-10 17:46:49 -08:00
|
|
|
|
2010-11-14 10:48:44 -08:00
|
|
|
fn trans_block_cleanups(@block_ctxt cx,
|
|
|
|
@block_ctxt cleanup_cx) -> @block_ctxt {
|
2010-10-04 15:55:12 -07:00
|
|
|
auto bcx = cx;
|
2010-12-02 19:12:34 -08:00
|
|
|
|
2011-03-25 16:28:16 +01:00
|
|
|
if (cleanup_cx.kind == NON_SCOPE_BLOCK) {
|
2010-12-02 19:12:34 -08:00
|
|
|
check (_vec.len[cleanup](cleanup_cx.cleanups) == 0u);
|
|
|
|
}
|
|
|
|
|
2011-01-31 12:06:27 -08:00
|
|
|
auto i = _vec.len[cleanup](cleanup_cx.cleanups);
|
|
|
|
while (i > 0u) {
|
|
|
|
i -= 1u;
|
|
|
|
auto c = cleanup_cx.cleanups.(i);
|
2010-09-29 17:22:07 -07:00
|
|
|
alt (c) {
|
2010-09-30 17:39:37 -07:00
|
|
|
case (clean(?cfn)) {
|
2010-10-04 15:55:12 -07:00
|
|
|
bcx = cfn(bcx).bcx;
|
2010-09-29 17:22:07 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-10-04 15:55:12 -07:00
|
|
|
ret bcx;
|
|
|
|
}
|
|
|
|
|
2010-10-19 14:54:10 -07:00
|
|
|
iter block_locals(&ast.block b) -> @ast.local {
|
|
|
|
// FIXME: putting from inside an iter block doesn't work, so we can't
|
|
|
|
// use the index here.
|
|
|
|
for (@ast.stmt s in b.node.stmts) {
|
|
|
|
alt (s.node) {
|
2011-04-06 17:56:44 -07:00
|
|
|
case (ast.stmt_decl(?d,_)) {
|
2010-10-19 14:54:10 -07:00
|
|
|
alt (d.node) {
|
|
|
|
case (ast.decl_local(?local)) {
|
|
|
|
put local;
|
|
|
|
}
|
2010-12-01 17:08:46 -08:00
|
|
|
case (_) { /* fall through */ }
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
|
|
|
}
|
2010-12-01 17:08:46 -08:00
|
|
|
case (_) { /* fall through */ }
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-28 18:04:52 -07:00
|
|
|
fn llallocas_block_ctxt(@fn_ctxt fcx) -> @block_ctxt {
|
|
|
|
let vec[cleanup] cleanups = vec();
|
|
|
|
ret @rec(llbb=fcx.llallocas,
|
|
|
|
build=new_builder(fcx.llallocas),
|
|
|
|
parent=parent_none,
|
|
|
|
kind=SCOPE_BLOCK,
|
|
|
|
mutable cleanups=cleanups,
|
|
|
|
fcx=fcx);
|
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn alloc_ty(@block_ctxt cx, ty.t t) -> result {
|
2011-01-21 07:58:16 -08:00
|
|
|
auto val = C_int(0);
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_has_dynamic_size(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-03-28 18:04:52 -07:00
|
|
|
|
|
|
|
// 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);
|
2011-01-21 07:58:16 -08:00
|
|
|
} else {
|
2011-04-17 14:24:45 +02:00
|
|
|
val = alloca(cx, type_of(cx.fcx.lcx.ccx, t));
|
2011-01-21 07:58:16 -08:00
|
|
|
}
|
2011-03-28 18:04:52 -07:00
|
|
|
// 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.
|
|
|
|
ret res(cx, val);
|
2011-01-21 07:58:16 -08:00
|
|
|
}
|
|
|
|
|
2011-02-10 15:00:16 -08:00
|
|
|
fn alloc_local(@block_ctxt cx, @ast.local local) -> result {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto t = node_ann_type(cx.fcx.lcx.ccx, local.ann);
|
2011-02-10 15:00:16 -08:00
|
|
|
auto r = alloc_ty(cx, t);
|
|
|
|
r.bcx.fcx.lllocals.insert(local.id, r.val);
|
|
|
|
ret r;
|
|
|
|
}
|
|
|
|
|
2011-01-21 07:58:16 -08:00
|
|
|
fn trans_block(@block_ctxt cx, &ast.block b) -> result {
|
2010-10-04 15:55:12 -07:00
|
|
|
auto bcx = cx;
|
|
|
|
|
2010-10-19 14:54:10 -07:00
|
|
|
for each (@ast.local local in block_locals(b)) {
|
2011-01-21 07:58:16 -08:00
|
|
|
bcx = alloc_local(bcx, local).bcx;
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2010-11-10 17:46:49 -08:00
|
|
|
auto r = res(bcx, C_nil());
|
2010-10-19 14:54:10 -07:00
|
|
|
|
2010-10-18 18:19:16 -07:00
|
|
|
for (@ast.stmt s in b.node.stmts) {
|
2010-11-10 17:46:49 -08:00
|
|
|
r = trans_stmt(bcx, *s);
|
|
|
|
bcx = r.bcx;
|
2010-11-12 10:15:40 -08:00
|
|
|
// If we hit a terminator, control won't go any further so
|
|
|
|
// we're in dead-code land. Stop here.
|
|
|
|
if (is_terminated(bcx)) {
|
|
|
|
ret r;
|
|
|
|
}
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
2010-09-29 17:22:07 -07:00
|
|
|
|
2010-11-29 17:11:03 -08:00
|
|
|
alt (b.node.expr) {
|
|
|
|
case (some[@ast.expr](?e)) {
|
|
|
|
r = trans_expr(bcx, e);
|
|
|
|
bcx = r.bcx;
|
2011-03-31 21:20:10 -04:00
|
|
|
|
2010-11-29 17:11:03 -08:00
|
|
|
if (is_terminated(bcx)) {
|
|
|
|
ret r;
|
2011-03-31 21:20:10 -04:00
|
|
|
} else {
|
2011-04-20 18:52:04 -07:00
|
|
|
auto r_ty = ty.expr_ty(cx.fcx.lcx.ccx.tystore, e);
|
2011-04-22 17:00:46 -07:00
|
|
|
if (!ty.type_is_nil(cx.fcx.lcx.ccx.tystore, r_ty)) {
|
2011-03-31 23:11:26 -04:00
|
|
|
// The value resulting from the block gets copied into an
|
2011-04-01 00:00:20 -04:00
|
|
|
// alloca created in an outer scope and its refcount
|
2011-03-31 23:11:26 -04:00
|
|
|
// bumped so that it can escape this block. This means
|
|
|
|
// that it will definitely live until the end of the
|
|
|
|
// enclosing scope, even if nobody uses it, which may be
|
|
|
|
// something of a surprise.
|
|
|
|
|
|
|
|
// It's possible we never hit this block, so the alloca
|
|
|
|
// must be initialized to null, then when the potential
|
|
|
|
// value finally goes out of scope the drop glue will see
|
|
|
|
// that it was never used and ignore it.
|
|
|
|
|
|
|
|
// NB: Here we're building and initalizing the alloca in
|
|
|
|
// the alloca context, not this block's context.
|
2011-03-31 21:20:10 -04:00
|
|
|
auto res_alloca = alloc_ty(bcx, r_ty);
|
2011-04-05 23:42:33 -04:00
|
|
|
auto llbcx = llallocas_block_ctxt(bcx.fcx);
|
|
|
|
zero_alloca(llbcx, res_alloca.val, r_ty);
|
2011-03-31 23:11:26 -04:00
|
|
|
|
|
|
|
// Now we're working in our own block context again
|
2011-03-31 21:20:10 -04:00
|
|
|
auto res_copy = copy_ty(bcx, INIT,
|
|
|
|
res_alloca.val, r.val, r_ty);
|
|
|
|
bcx = res_copy.bcx;
|
|
|
|
|
|
|
|
fn drop_hoisted_ty(@block_ctxt cx,
|
|
|
|
ValueRef alloca_val,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t t) -> result {
|
2011-04-12 12:06:20 -07:00
|
|
|
auto reg_val = load_if_immediate(cx,
|
2011-03-31 21:20:10 -04:00
|
|
|
alloca_val, t);
|
|
|
|
ret drop_ty(cx, reg_val, t);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto cleanup = bind drop_hoisted_ty(_, res_alloca.val,
|
|
|
|
r_ty);
|
|
|
|
find_outer_scope_cx(bcx).cleanups += vec(clean(cleanup));
|
|
|
|
}
|
2010-11-29 17:11:03 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
case (none[@ast.expr]) {
|
|
|
|
r = res(bcx, C_nil());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-02 19:44:24 -08:00
|
|
|
bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
|
2010-11-10 17:46:49 -08:00
|
|
|
ret res(bcx, r.val);
|
2010-09-23 13:15:51 -07:00
|
|
|
}
|
|
|
|
|
2011-04-20 17:23:45 +02:00
|
|
|
fn new_local_ctxt(@crate_ctxt ccx) -> @local_ctxt {
|
|
|
|
let vec[str] pth = vec();
|
|
|
|
let vec[ast.ty_param] obj_typarams = vec();
|
|
|
|
let vec[ast.obj_field] obj_fields = vec();
|
|
|
|
ret @rec(path=pth,
|
|
|
|
module_path=vec(crate_name(ccx, "main")),
|
|
|
|
obj_typarams = obj_typarams,
|
|
|
|
obj_fields = obj_fields,
|
|
|
|
ccx = ccx);
|
|
|
|
}
|
|
|
|
|
2011-02-08 11:47:53 -08:00
|
|
|
// NB: must keep 4 fns in sync:
|
|
|
|
//
|
|
|
|
// - type_of_fn_full
|
|
|
|
// - create_llargs_for_fn_args.
|
|
|
|
// - new_fn_ctxt
|
|
|
|
// - trans_args
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
fn new_fn_ctxt(@local_ctxt cx,
|
2010-12-09 15:26:16 -08:00
|
|
|
ValueRef llfndecl) -> @fn_ctxt {
|
2010-10-21 18:13:57 -07:00
|
|
|
|
2011-02-08 11:47:53 -08:00
|
|
|
let ValueRef llretptr = llvm.LLVMGetParam(llfndecl, 0u);
|
|
|
|
let ValueRef lltaskptr = llvm.LLVMGetParam(llfndecl, 1u);
|
|
|
|
let ValueRef llenv = llvm.LLVMGetParam(llfndecl, 2u);
|
2010-10-21 18:13:57 -07:00
|
|
|
|
|
|
|
let hashmap[ast.def_id, ValueRef] llargs = new_def_hash[ValueRef]();
|
2010-12-30 17:01:20 -08:00
|
|
|
let hashmap[ast.def_id, ValueRef] llobjfields = new_def_hash[ValueRef]();
|
|
|
|
let hashmap[ast.def_id, ValueRef] lllocals = new_def_hash[ValueRef]();
|
2011-03-10 16:49:00 -08:00
|
|
|
let hashmap[ast.def_id, ValueRef] llupvars = new_def_hash[ValueRef]();
|
2010-10-21 18:13:57 -07:00
|
|
|
|
2011-03-28 18:04:52 -07:00
|
|
|
let BasicBlockRef llallocas =
|
|
|
|
llvm.LLVMAppendBasicBlock(llfndecl, _str.buf("allocas"));
|
|
|
|
|
2010-12-09 15:26:16 -08:00
|
|
|
ret @rec(llfn=llfndecl,
|
2010-09-27 15:38:34 -07:00
|
|
|
lltaskptr=lltaskptr,
|
2011-02-08 11:47:53 -08:00
|
|
|
llenv=llenv,
|
|
|
|
llretptr=llretptr,
|
2011-03-28 18:04:52 -07:00
|
|
|
mutable llallocas = llallocas,
|
2011-04-05 14:18:44 -07:00
|
|
|
mutable llself=none[self_vt],
|
2011-02-17 12:20:55 -08:00
|
|
|
mutable lliterbody=none[ValueRef],
|
2010-10-21 18:13:57 -07:00
|
|
|
llargs=llargs,
|
2010-12-30 17:01:20 -08:00
|
|
|
llobjfields=llobjfields,
|
2010-10-19 14:54:10 -07:00
|
|
|
lllocals=lllocals,
|
2011-03-10 16:49:00 -08:00
|
|
|
llupvars=llupvars,
|
2011-04-15 17:45:37 -07:00
|
|
|
mutable lltydescs=_vec.empty[ValueRef](),
|
2011-04-17 14:24:45 +02:00
|
|
|
lcx=cx);
|
2010-09-27 15:38:34 -07:00
|
|
|
}
|
|
|
|
|
2011-02-08 11:47:53 -08:00
|
|
|
// NB: must keep 4 fns in sync:
|
|
|
|
//
|
|
|
|
// - type_of_fn_full
|
|
|
|
// - create_llargs_for_fn_args.
|
|
|
|
// - new_fn_ctxt
|
|
|
|
// - trans_args
|
|
|
|
|
2010-12-23 17:31:16 -08:00
|
|
|
fn create_llargs_for_fn_args(&@fn_ctxt cx,
|
2011-02-18 17:30:57 -08:00
|
|
|
ast.proto proto,
|
2011-04-22 12:27:28 -07:00
|
|
|
option.t[tup(TypeRef, ty.t)] ty_self,
|
|
|
|
ty.t ret_ty,
|
2010-12-23 17:31:16 -08:00
|
|
|
&vec[ast.arg] args,
|
2010-12-20 14:33:11 -08:00
|
|
|
&vec[ast.ty_param] ty_params) {
|
2011-02-08 11:47:53 -08:00
|
|
|
|
|
|
|
auto arg_n = 3u;
|
2010-12-23 17:31:16 -08:00
|
|
|
|
2011-04-05 14:18:44 -07:00
|
|
|
alt (ty_self) {
|
2011-04-22 12:27:28 -07:00
|
|
|
case (some[tup(TypeRef, ty.t)](?tt)) {
|
2011-04-05 14:18:44 -07:00
|
|
|
cx.llself = some[self_vt](rec(v = cx.llenv, t = tt._1));
|
|
|
|
}
|
2011-04-22 12:27:28 -07:00
|
|
|
case (none[tup(TypeRef, ty.t)]) {
|
2011-04-12 15:09:50 -07:00
|
|
|
auto i = 0u;
|
2011-04-05 14:18:44 -07:00
|
|
|
for (ast.ty_param tp in ty_params) {
|
|
|
|
auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n);
|
|
|
|
check (llarg as int != 0);
|
2011-04-15 17:45:37 -07:00
|
|
|
cx.lltydescs += vec(llarg);
|
2011-04-05 14:18:44 -07:00
|
|
|
arg_n += 1u;
|
2011-04-12 15:09:50 -07:00
|
|
|
i += 1u;
|
2011-04-05 14:18:44 -07:00
|
|
|
}
|
2011-02-09 09:54:58 -08:00
|
|
|
}
|
2010-12-20 14:33:11 -08:00
|
|
|
}
|
|
|
|
|
2011-02-18 17:30:57 -08:00
|
|
|
if (proto == ast.proto_iter) {
|
2011-02-17 12:20:55 -08:00
|
|
|
auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n);
|
|
|
|
check (llarg as int != 0);
|
|
|
|
cx.lliterbody = some[ValueRef](llarg);
|
|
|
|
arg_n += 1u;
|
|
|
|
}
|
2010-12-23 17:31:16 -08:00
|
|
|
|
2010-12-09 17:38:17 -08:00
|
|
|
for (ast.arg arg in args) {
|
|
|
|
auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n);
|
|
|
|
check (llarg as int != 0);
|
|
|
|
cx.llargs.insert(arg.id, llarg);
|
|
|
|
arg_n += 1u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-26 17:47:27 -08:00
|
|
|
// 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.
|
|
|
|
|
2011-03-28 18:04:52 -07:00
|
|
|
fn copy_any_self_to_alloca(@fn_ctxt fcx,
|
2011-04-22 12:27:28 -07:00
|
|
|
option.t[tup(TypeRef, ty.t)] ty_self) {
|
2010-11-26 17:47:27 -08:00
|
|
|
|
2011-03-28 18:04:52 -07:00
|
|
|
auto bcx = llallocas_block_ctxt(fcx);
|
2010-11-26 17:47:27 -08:00
|
|
|
|
2011-03-28 18:04:52 -07:00
|
|
|
alt (fcx.llself) {
|
2011-04-05 14:18:44 -07:00
|
|
|
case (some[self_vt](?s_vt)) {
|
2010-12-30 17:01:20 -08:00
|
|
|
alt (ty_self) {
|
2011-04-22 12:27:28 -07:00
|
|
|
case (some[tup(TypeRef, ty.t)](?tt)) {
|
2011-04-05 14:18:44 -07:00
|
|
|
auto a = alloca(bcx, tt._0);
|
|
|
|
bcx.build.Store(s_vt.v, a);
|
|
|
|
fcx.llself = some[self_vt](rec(v = a, t = s_vt.t));
|
2010-12-30 17:01:20 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case (_) {
|
|
|
|
}
|
|
|
|
}
|
2011-03-28 18:04:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn copy_args_to_allocas(@fn_ctxt fcx,
|
|
|
|
vec[ast.arg] args,
|
|
|
|
vec[ty.arg] arg_tys) {
|
|
|
|
|
|
|
|
auto bcx = llallocas_block_ctxt(fcx);
|
|
|
|
|
|
|
|
let uint arg_n = 0u;
|
2010-12-30 17:01:20 -08:00
|
|
|
|
2010-12-03 18:20:41 -08:00
|
|
|
for (ast.arg aarg in args) {
|
2010-12-07 12:34:10 -08:00
|
|
|
if (aarg.mode != ast.alias) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto arg_t = type_of_arg(fcx.lcx, arg_tys.(arg_n));
|
2011-03-28 18:04:52 -07:00
|
|
|
auto a = alloca(bcx, arg_t);
|
|
|
|
auto argval = fcx.llargs.get(aarg.id);
|
|
|
|
bcx.build.Store(argval, a);
|
2010-12-07 12:34:10 -08:00
|
|
|
// Overwrite the llargs entry for this arg with its alloca.
|
2011-03-28 18:04:52 -07:00
|
|
|
fcx.llargs.insert(aarg.id, a);
|
2010-12-07 12:34:10 -08:00
|
|
|
}
|
|
|
|
|
2010-11-26 17:47:27 -08:00
|
|
|
arg_n += 1u;
|
|
|
|
}
|
2011-03-28 18:04:52 -07:00
|
|
|
|
|
|
|
fcx.llallocas = bcx.llbb;
|
2010-11-26 17:47:27 -08:00
|
|
|
}
|
|
|
|
|
2010-11-10 17:46:49 -08:00
|
|
|
fn is_terminated(@block_ctxt cx) -> bool {
|
|
|
|
auto inst = llvm.LLVMGetLastInstruction(cx.llbb);
|
|
|
|
ret llvm.LLVMIsATerminatorInst(inst) as int != 0;
|
|
|
|
}
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
fn arg_tys_of_fn(@crate_ctxt ccx, ast.ann ann) -> vec[ty.arg] {
|
|
|
|
alt (ty.struct(ccx.tystore, ty.ann_to_type(ann))) {
|
2011-02-18 17:30:57 -08:00
|
|
|
case (ty.ty_fn(_, ?arg_tys, _)) {
|
2010-12-06 11:22:08 -08:00
|
|
|
ret arg_tys;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fail;
|
|
|
|
}
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
fn ret_ty_of_fn_ty(@crate_ctxt ccx, ty.t t) -> ty.t {
|
|
|
|
alt (ty.struct(ccx.tystore, t)) {
|
2011-02-18 17:30:57 -08:00
|
|
|
case (ty.ty_fn(_, _, ?ret_ty)) {
|
2010-12-16 15:55:28 -08:00
|
|
|
ret ret_ty;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fail;
|
|
|
|
}
|
|
|
|
|
2011-01-07 15:12:23 -08:00
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
fn ret_ty_of_fn(@crate_ctxt ccx, ast.ann ann) -> ty.t {
|
|
|
|
ret ret_ty_of_fn_ty(ccx, ty.ann_to_type(ann));
|
2011-01-07 15:12:23 -08:00
|
|
|
}
|
|
|
|
|
2011-04-05 14:18:44 -07:00
|
|
|
fn populate_fn_ctxt_from_llself(@fn_ctxt fcx, self_vt llself) {
|
2011-03-28 18:04:52 -07:00
|
|
|
auto bcx = llallocas_block_ctxt(fcx);
|
2010-12-30 17:01:20 -08:00
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
let vec[ty.t] field_tys = vec();
|
2010-12-30 17:01:20 -08:00
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
for (ast.obj_field f in bcx.fcx.lcx.obj_fields) {
|
|
|
|
field_tys += vec(node_ann_type(bcx.fcx.lcx.ccx, f.ann));
|
2010-12-30 17:01:20 -08:00
|
|
|
}
|
|
|
|
|
2011-03-03 11:49:35 -08:00
|
|
|
// Synthesize a tuple type for the fields so that GEP_tup_like() can work
|
|
|
|
// its magic.
|
2011-04-20 18:52:04 -07:00
|
|
|
auto fields_tup_ty = ty.mk_imm_tup(fcx.lcx.ccx.tystore, field_tys);
|
2011-03-03 11:49:35 -08:00
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
auto n_typarams = _vec.len[ast.ty_param](bcx.fcx.lcx.obj_typarams);
|
|
|
|
let TypeRef llobj_box_ty = T_obj_ptr(bcx.fcx.lcx.ccx.tn, n_typarams);
|
2010-12-30 17:01:20 -08:00
|
|
|
|
|
|
|
auto box_cell =
|
2011-04-05 14:18:44 -07:00
|
|
|
bcx.build.GEP(llself.v,
|
2011-03-03 11:49:35 -08:00
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.obj_field_box)));
|
2010-12-30 17:01:20 -08:00
|
|
|
|
2011-03-03 11:49:35 -08:00
|
|
|
auto box_ptr = bcx.build.Load(box_cell);
|
2010-12-30 17:01:20 -08:00
|
|
|
|
2011-03-03 11:49:35 -08:00
|
|
|
box_ptr = bcx.build.PointerCast(box_ptr, llobj_box_ty);
|
2010-12-30 17:01:20 -08:00
|
|
|
|
2011-03-03 11:49:35 -08:00
|
|
|
auto obj_typarams = bcx.build.GEP(box_ptr,
|
2011-04-01 16:04:22 -07:00
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.box_rc_field_body),
|
|
|
|
C_int(abi.obj_body_elt_typarams)));
|
2011-02-03 14:40:57 -08:00
|
|
|
|
2011-03-03 11:49:35 -08:00
|
|
|
// The object fields immediately follow the type parameters, so we skip
|
|
|
|
// over them to get the pointer.
|
|
|
|
auto obj_fields = bcx.build.Add(vp2i(bcx, obj_typarams),
|
2011-04-01 16:04:22 -07:00
|
|
|
llsize_of(llvm.LLVMGetElementType(val_ty(obj_typarams))));
|
2011-03-03 11:49:35 -08:00
|
|
|
|
|
|
|
// 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 *.
|
2011-04-22 17:00:46 -07:00
|
|
|
if (!ty.type_has_dynamic_size(fcx.lcx.ccx.tystore, fields_tup_ty)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llfields_ty = type_of(fcx.lcx.ccx, fields_tup_ty);
|
2011-03-03 11:49:35 -08:00
|
|
|
obj_fields = vi2p(bcx, obj_fields, T_ptr(llfields_ty));
|
|
|
|
} else {
|
|
|
|
obj_fields = vi2p(bcx, obj_fields, T_ptr(T_i8()));
|
|
|
|
}
|
|
|
|
|
2010-12-30 17:01:20 -08:00
|
|
|
|
|
|
|
let int i = 0;
|
2011-02-03 14:40:57 -08:00
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
for (ast.ty_param p in fcx.lcx.obj_typarams) {
|
2011-03-03 11:49:35 -08:00
|
|
|
let ValueRef lltyparam = bcx.build.GEP(obj_typarams,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(i)));
|
|
|
|
lltyparam = bcx.build.Load(lltyparam);
|
2011-04-15 17:45:37 -07:00
|
|
|
fcx.lltydescs += vec(lltyparam);
|
2011-02-03 14:40:57 -08:00
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = 0;
|
2011-04-17 14:24:45 +02:00
|
|
|
for (ast.obj_field f in fcx.lcx.obj_fields) {
|
2011-03-03 11:49:35 -08:00
|
|
|
auto rslt = GEP_tup_like(bcx, fields_tup_ty, obj_fields, vec(0, i));
|
2011-03-28 18:04:52 -07:00
|
|
|
bcx = llallocas_block_ctxt(fcx);
|
2011-03-03 11:49:35 -08:00
|
|
|
auto llfield = rslt.val;
|
2011-03-28 18:04:52 -07:00
|
|
|
fcx.llobjfields.insert(f.id, llfield);
|
2010-12-30 17:01:20 -08:00
|
|
|
i += 1;
|
|
|
|
}
|
2011-03-03 11:49:35 -08:00
|
|
|
|
2011-03-28 18:04:52 -07:00
|
|
|
fcx.llallocas = bcx.llbb;
|
2010-12-30 17:01:20 -08:00
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
fn trans_fn(@local_ctxt cx, &ast._fn f, ast.def_id fid,
|
2011-04-22 12:27:28 -07:00
|
|
|
option.t[tup(TypeRef, ty.t)] ty_self,
|
2011-01-21 07:58:16 -08:00
|
|
|
&vec[ast.ty_param] ty_params, &ast.ann ann) {
|
2010-09-27 15:38:34 -07:00
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llfndecl = cx.ccx.item_ids.get(fid);
|
2010-12-09 15:26:16 -08:00
|
|
|
|
2011-03-04 14:53:52 -05:00
|
|
|
auto fcx = new_fn_ctxt(cx, llfndecl);
|
2011-02-25 12:08:21 -05:00
|
|
|
create_llargs_for_fn_args(fcx, f.proto,
|
2011-04-22 17:00:46 -07:00
|
|
|
ty_self, ret_ty_of_fn(cx.ccx, ann),
|
2011-02-04 11:10:04 -05:00
|
|
|
f.decl.inputs, ty_params);
|
2010-11-26 17:47:27 -08:00
|
|
|
|
2011-03-28 18:04:52 -07:00
|
|
|
copy_any_self_to_alloca(fcx, ty_self);
|
2010-12-30 17:01:20 -08:00
|
|
|
|
|
|
|
alt (fcx.llself) {
|
2011-04-05 14:18:44 -07:00
|
|
|
case (some[self_vt](?llself)) {
|
2011-03-28 18:04:52 -07:00
|
|
|
populate_fn_ctxt_from_llself(fcx, llself);
|
2010-12-30 17:01:20 -08:00
|
|
|
}
|
|
|
|
case (_) {
|
|
|
|
}
|
|
|
|
}
|
2010-11-26 17:47:27 -08:00
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
copy_args_to_allocas(fcx, f.decl.inputs, arg_tys_of_fn(fcx.lcx.ccx, ann));
|
2011-03-28 18:04:52 -07:00
|
|
|
|
|
|
|
auto bcx = new_top_block_ctxt(fcx);
|
|
|
|
auto lltop = bcx.llbb;
|
|
|
|
|
2010-11-10 17:46:49 -08:00
|
|
|
auto res = trans_block(bcx, f.body);
|
|
|
|
if (!is_terminated(res.bcx)) {
|
2010-11-14 13:04:01 -08:00
|
|
|
// FIXME: until LLVM has a unit type, we are moving around
|
|
|
|
// C_nil values rather than their void type.
|
2010-12-13 16:12:45 -08:00
|
|
|
res.bcx.build.RetVoid();
|
2010-11-10 17:46:49 -08:00
|
|
|
}
|
2011-03-28 18:04:52 -07:00
|
|
|
|
|
|
|
// Tie up the llallocas -> lltop edge.
|
|
|
|
new_builder(fcx.llallocas).Br(lltop);
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
fn trans_vtbl(@local_ctxt cx,
|
2011-04-05 14:18:44 -07:00
|
|
|
TypeRef llself_ty,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t self_ty,
|
2011-01-21 07:58:16 -08:00
|
|
|
&ast._obj ob,
|
|
|
|
&vec[ast.ty_param] ty_params) -> ValueRef {
|
2010-12-16 18:34:04 -08:00
|
|
|
let vec[ValueRef] methods = vec();
|
2010-12-30 17:01:20 -08:00
|
|
|
|
|
|
|
fn meth_lteq(&@ast.method a, &@ast.method b) -> bool {
|
|
|
|
ret _str.lteq(a.node.ident, b.node.ident);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto meths = std.sort.merge_sort[@ast.method](bind meth_lteq(_,_),
|
|
|
|
ob.methods);
|
|
|
|
|
|
|
|
for (@ast.method m in meths) {
|
2010-12-17 00:31:41 -08:00
|
|
|
|
2010-12-23 17:31:16 -08:00
|
|
|
auto llfnty = T_nil();
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.ccx.tystore, node_ann_type(cx.ccx, m.node.ann))) {
|
2011-02-18 17:30:57 -08:00
|
|
|
case (ty.ty_fn(?proto, ?inputs, ?output)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
llfnty = type_of_fn_full(cx.ccx, proto,
|
2011-04-05 14:18:44 -07:00
|
|
|
some[TypeRef](llself_ty),
|
2011-03-08 16:51:23 -08:00
|
|
|
inputs, output,
|
|
|
|
_vec.len[ast.ty_param](ty_params));
|
2010-12-23 17:31:16 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
let @local_ctxt mcx = extend_path(cx, m.node.ident);
|
2011-04-20 17:23:45 +02:00
|
|
|
let str s = mangle_name_by_seq(mcx.ccx, mcx.path, "method");
|
2011-04-17 14:24:45 +02:00
|
|
|
let ValueRef llfn = decl_internal_fastcall_fn(cx.ccx.llmod, s,
|
|
|
|
llfnty);
|
|
|
|
cx.ccx.item_ids.insert(m.node.id, llfn);
|
|
|
|
cx.ccx.item_symbols.insert(m.node.id, s);
|
2010-12-17 00:31:41 -08:00
|
|
|
|
2011-04-05 14:18:44 -07:00
|
|
|
trans_fn(mcx, m.node.meth, m.node.id,
|
2011-04-22 12:27:28 -07:00
|
|
|
some[tup(TypeRef, ty.t)](tup(llself_ty, self_ty)),
|
2010-12-30 17:01:20 -08:00
|
|
|
ty_params, m.node.ann);
|
2011-03-16 14:58:02 -07:00
|
|
|
methods += vec(llfn);
|
2010-12-16 18:34:04 -08:00
|
|
|
}
|
2010-12-20 11:41:22 -08:00
|
|
|
auto vtbl = C_struct(methods);
|
2011-04-20 17:23:45 +02:00
|
|
|
auto vtbl_name = mangle_name_by_seq(cx.ccx, cx.path, "vtbl");
|
2011-04-17 14:24:45 +02:00
|
|
|
auto gvar = llvm.LLVMAddGlobal(cx.ccx.llmod, val_ty(vtbl),
|
2011-03-26 17:36:47 -07:00
|
|
|
_str.buf(vtbl_name));
|
2010-12-20 11:41:22 -08:00
|
|
|
llvm.LLVMSetInitializer(gvar, vtbl);
|
|
|
|
llvm.LLVMSetGlobalConstant(gvar, True);
|
2011-04-01 15:01:46 -07:00
|
|
|
llvm.LLVMSetLinkage(gvar, lib.llvm.LLVMInternalLinkage
|
2011-01-05 15:31:35 -08:00
|
|
|
as llvm.Linkage);
|
2010-12-20 11:41:22 -08:00
|
|
|
ret gvar;
|
2010-12-16 18:34:04 -08:00
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
fn trans_dtor(@local_ctxt cx,
|
2011-04-14 16:50:48 -07:00
|
|
|
TypeRef llself_ty,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t self_ty,
|
2011-04-14 16:50:48 -07:00
|
|
|
&vec[ast.ty_param] ty_params,
|
|
|
|
&@ast.method dtor) -> ValueRef {
|
|
|
|
|
|
|
|
auto llfnty = T_nil();
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.ccx.tystore, node_ann_type(cx.ccx, dtor.node.ann))) {
|
2011-04-14 16:50:48 -07:00
|
|
|
case (ty.ty_fn(?proto, ?inputs, ?output)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
llfnty = type_of_fn_full(cx.ccx, proto,
|
2011-04-14 16:50:48 -07:00
|
|
|
some[TypeRef](llself_ty),
|
|
|
|
inputs, output,
|
|
|
|
_vec.len[ast.ty_param](ty_params));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
let @local_ctxt dcx = extend_path(cx, "drop");
|
2011-04-20 17:23:45 +02:00
|
|
|
let str s = mangle_name_by_seq(dcx.ccx, dcx.path, "drop");
|
2011-04-17 14:24:45 +02:00
|
|
|
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);
|
2011-04-14 16:50:48 -07:00
|
|
|
|
|
|
|
trans_fn(dcx, dtor.node.meth, dtor.node.id,
|
2011-04-22 12:27:28 -07:00
|
|
|
some[tup(TypeRef, ty.t)](tup(llself_ty, self_ty)),
|
2011-04-14 16:50:48 -07:00
|
|
|
ty_params, dtor.node.ann);
|
|
|
|
|
|
|
|
ret llfn;
|
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
fn trans_obj(@local_ctxt cx, &ast._obj ob, ast.def_id oid,
|
2011-01-21 07:58:16 -08:00
|
|
|
&vec[ast.ty_param] ty_params, &ast.ann ann) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto ccx = cx.ccx;
|
|
|
|
auto llctor_decl = ccx.item_ids.get(oid);
|
2010-12-16 15:55:28 -08:00
|
|
|
|
2010-12-22 13:56:51 -08:00
|
|
|
// Translate obj ctor args to function arguments.
|
2010-12-16 15:55:28 -08:00
|
|
|
let vec[ast.arg] fn_args = vec();
|
|
|
|
for (ast.obj_field f in ob.fields) {
|
|
|
|
fn_args += vec(rec(mode=ast.alias,
|
|
|
|
ty=f.ty,
|
|
|
|
ident=f.ident,
|
|
|
|
id=f.id));
|
|
|
|
}
|
|
|
|
|
2011-03-04 14:53:52 -05:00
|
|
|
auto fcx = new_fn_ctxt(cx, llctor_decl);
|
2011-02-18 17:30:57 -08:00
|
|
|
create_llargs_for_fn_args(fcx, ast.proto_fn,
|
2011-04-22 12:27:28 -07:00
|
|
|
none[tup(TypeRef, ty.t)],
|
2011-04-22 17:00:46 -07:00
|
|
|
ret_ty_of_fn(cx.ccx, ann),
|
2010-12-23 17:31:16 -08:00
|
|
|
fn_args, ty_params);
|
2010-12-16 15:55:28 -08:00
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
let vec[ty.arg] arg_tys = arg_tys_of_fn(cx.ccx, ann);
|
2011-03-28 18:04:52 -07:00
|
|
|
copy_args_to_allocas(fcx, fn_args, arg_tys);
|
|
|
|
|
|
|
|
auto bcx = new_top_block_ctxt(fcx);
|
|
|
|
auto lltop = bcx.llbb;
|
2010-12-16 15:55:28 -08:00
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
auto self_ty = ret_ty_of_fn(cx.ccx, ann);
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llself_ty = type_of(ccx, self_ty);
|
2011-02-08 11:47:53 -08:00
|
|
|
auto pair = bcx.fcx.llretptr;
|
2011-04-05 14:18:44 -07:00
|
|
|
auto vtbl = trans_vtbl(cx, llself_ty, self_ty, ob, ty_params);
|
2010-12-17 00:31:41 -08:00
|
|
|
auto pair_vtbl = bcx.build.GEP(pair,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.obj_field_vtbl)));
|
2010-12-20 17:28:07 -08:00
|
|
|
auto pair_box = bcx.build.GEP(pair,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.obj_field_box)));
|
2010-12-17 00:31:41 -08:00
|
|
|
bcx.build.Store(vtbl, pair_vtbl);
|
2010-12-20 17:28:07 -08:00
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
let TypeRef llbox_ty = T_opaque_obj_ptr(ccx.tn);
|
2011-02-03 14:40:57 -08:00
|
|
|
|
|
|
|
if (_vec.len[ast.ty_param](ty_params) == 0u &&
|
|
|
|
_vec.len[ty.arg](arg_tys) == 0u) {
|
|
|
|
// Store null into pair, if no args or typarams.
|
2010-12-22 13:56:51 -08:00
|
|
|
bcx.build.Store(C_null(llbox_ty), pair_box);
|
|
|
|
} else {
|
|
|
|
// Malloc a box for the body and copy args in.
|
2011-04-22 12:27:28 -07:00
|
|
|
let vec[ty.t] obj_fields = vec();
|
2010-12-22 13:56:51 -08:00
|
|
|
for (ty.arg a in arg_tys) {
|
2011-04-22 12:27:28 -07:00
|
|
|
_vec.push[ty.t](obj_fields, a.ty);
|
2010-12-22 13:56:51 -08:00
|
|
|
}
|
2010-12-22 16:09:59 -08:00
|
|
|
|
|
|
|
// Synthesize an obj body type.
|
2011-04-20 18:52:04 -07:00
|
|
|
auto tydesc_ty = ty.mk_type(cx.ccx.tystore);
|
2011-04-22 12:27:28 -07:00
|
|
|
let vec[ty.t] tps = vec();
|
2011-02-03 14:40:57 -08:00
|
|
|
for (ast.ty_param tp in ty_params) {
|
2011-04-22 12:27:28 -07:00
|
|
|
_vec.push[ty.t](tps, tydesc_ty);
|
2011-02-03 14:40:57 -08:00
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
let ty.t typarams_ty = ty.mk_imm_tup(cx.ccx.tystore, tps);
|
|
|
|
let ty.t fields_ty = ty.mk_imm_tup(cx.ccx.tystore, obj_fields);
|
|
|
|
let ty.t body_ty = ty.mk_imm_tup(cx.ccx.tystore,
|
2011-04-20 18:52:04 -07:00
|
|
|
vec(tydesc_ty,
|
2011-04-20 11:23:36 -07:00
|
|
|
typarams_ty,
|
|
|
|
fields_ty));
|
2011-04-22 12:27:28 -07:00
|
|
|
let ty.t boxed_body_ty = ty.mk_imm_box(cx.ccx.tystore, body_ty);
|
2011-02-01 14:57:03 -08:00
|
|
|
|
2010-12-22 16:09:59 -08:00
|
|
|
// Malloc a box for the body.
|
2011-03-07 14:05:16 -08:00
|
|
|
auto box = trans_malloc_boxed(bcx, body_ty);
|
2011-02-01 14:57:03 -08:00
|
|
|
bcx = box.bcx;
|
|
|
|
auto rc = GEP_tup_like(bcx, boxed_body_ty, box.val,
|
|
|
|
vec(0, abi.box_rc_field_refcnt));
|
|
|
|
bcx = rc.bcx;
|
|
|
|
auto body = GEP_tup_like(bcx, boxed_body_ty, box.val,
|
|
|
|
vec(0, abi.box_rc_field_body));
|
|
|
|
bcx = body.bcx;
|
|
|
|
bcx.build.Store(C_int(1), rc.val);
|
2010-12-20 17:28:07 -08:00
|
|
|
|
2010-12-22 16:09:59 -08:00
|
|
|
// Store body tydesc.
|
|
|
|
auto body_tydesc =
|
2011-02-01 14:57:03 -08:00
|
|
|
GEP_tup_like(bcx, body_ty, body.val,
|
|
|
|
vec(0, abi.obj_body_elt_tydesc));
|
|
|
|
bcx = body_tydesc.bcx;
|
2010-12-22 16:09:59 -08:00
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
auto dtor = C_null(T_ptr(T_glue_fn(ccx.tn)));
|
2011-04-14 16:50:48 -07:00
|
|
|
alt (ob.dtor) {
|
|
|
|
case (some[@ast.method](?d)) {
|
|
|
|
dtor = trans_dtor(cx, llself_ty, self_ty, ty_params, d);
|
|
|
|
}
|
|
|
|
case (none[@ast.method]) {}
|
|
|
|
}
|
|
|
|
|
2011-02-02 15:28:11 -08:00
|
|
|
auto body_td = get_tydesc(bcx, body_ty);
|
|
|
|
bcx = body_td.bcx;
|
|
|
|
bcx.build.Store(body_td.val, body_tydesc.val);
|
2010-12-22 16:09:59 -08:00
|
|
|
|
2011-02-03 14:40:57 -08:00
|
|
|
// Copy typarams into captured typarams.
|
|
|
|
auto body_typarams =
|
|
|
|
GEP_tup_like(bcx, body_ty, body.val,
|
|
|
|
vec(0, abi.obj_body_elt_typarams));
|
|
|
|
bcx = body_typarams.bcx;
|
|
|
|
let int i = 0;
|
|
|
|
for (ast.ty_param tp in ty_params) {
|
2011-04-15 17:45:37 -07:00
|
|
|
auto typaram = bcx.fcx.lltydescs.(i);
|
2011-02-03 14:40:57 -08:00
|
|
|
auto capture = GEP_tup_like(bcx, typarams_ty, body_typarams.val,
|
|
|
|
vec(0, i));
|
|
|
|
bcx = capture.bcx;
|
|
|
|
bcx = copy_ty(bcx, INIT, capture.val, typaram, tydesc_ty).bcx;
|
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
|
2010-12-22 16:09:59 -08:00
|
|
|
// Copy args into body fields.
|
|
|
|
auto body_fields =
|
2011-02-01 14:57:03 -08:00
|
|
|
GEP_tup_like(bcx, body_ty, body.val,
|
|
|
|
vec(0, abi.obj_body_elt_fields));
|
|
|
|
bcx = body_fields.bcx;
|
2010-12-22 16:09:59 -08:00
|
|
|
|
2011-02-03 14:40:57 -08:00
|
|
|
i = 0;
|
2010-12-22 16:09:59 -08:00
|
|
|
for (ast.obj_field f in ob.fields) {
|
2011-01-31 15:03:05 -08:00
|
|
|
auto arg = bcx.fcx.llargs.get(f.id);
|
2011-04-12 12:06:20 -07:00
|
|
|
arg = load_if_immediate(bcx, arg, arg_tys.(i).ty);
|
2011-02-01 14:57:03 -08:00
|
|
|
auto field = GEP_tup_like(bcx, fields_ty, body_fields.val,
|
|
|
|
vec(0, i));
|
|
|
|
bcx = field.bcx;
|
|
|
|
bcx = copy_ty(bcx, INIT, field.val, arg, arg_tys.(i).ty).bcx;
|
2010-12-22 16:09:59 -08:00
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
// Store box ptr in outer pair.
|
2011-02-01 14:57:03 -08:00
|
|
|
auto p = bcx.build.PointerCast(box.val, llbox_ty);
|
2011-01-31 15:03:05 -08:00
|
|
|
bcx.build.Store(p, pair_box);
|
2010-12-22 13:56:51 -08:00
|
|
|
}
|
2011-02-08 11:47:53 -08:00
|
|
|
bcx.build.RetVoid();
|
2011-03-28 18:04:52 -07:00
|
|
|
|
|
|
|
// Tie up the llallocas -> lltop edge.
|
|
|
|
new_builder(fcx.llallocas).Br(lltop);
|
2010-12-16 15:55:28 -08:00
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
fn trans_tag_variant(@local_ctxt cx, ast.def_id tag_id,
|
2010-12-20 14:33:11 -08:00
|
|
|
&ast.variant variant, int index,
|
|
|
|
&vec[ast.ty_param] ty_params) {
|
2011-03-29 12:46:55 +02:00
|
|
|
if (_vec.len[ast.variant_arg](variant.node.args) == 0u) {
|
2010-12-01 19:03:47 -08:00
|
|
|
ret; // nullary constructors are just constants
|
|
|
|
}
|
|
|
|
|
2010-12-06 16:50:24 -08:00
|
|
|
// Translate variant arguments to function arguments.
|
|
|
|
let vec[ast.arg] fn_args = vec();
|
|
|
|
auto i = 0u;
|
2011-03-29 12:46:55 +02:00
|
|
|
for (ast.variant_arg varg in variant.node.args) {
|
2010-12-06 16:50:24 -08:00
|
|
|
fn_args += vec(rec(mode=ast.alias,
|
|
|
|
ty=varg.ty,
|
|
|
|
ident="arg" + _uint.to_str(i, 10u),
|
|
|
|
id=varg.id));
|
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
check (cx.ccx.item_ids.contains_key(variant.node.id));
|
|
|
|
let ValueRef llfndecl = cx.ccx.item_ids.get(variant.node.id);
|
2010-12-09 15:26:16 -08:00
|
|
|
|
2011-03-04 14:53:52 -05:00
|
|
|
auto fcx = new_fn_ctxt(cx, llfndecl);
|
2011-03-28 18:04:52 -07:00
|
|
|
|
2011-02-18 17:30:57 -08:00
|
|
|
create_llargs_for_fn_args(fcx, ast.proto_fn,
|
2011-04-22 12:27:28 -07:00
|
|
|
none[tup(TypeRef, ty.t)],
|
2011-04-22 17:00:46 -07:00
|
|
|
ret_ty_of_fn(cx.ccx, variant.node.ann),
|
2010-12-29 19:04:57 -05:00
|
|
|
fn_args, ty_params);
|
2010-12-09 17:38:17 -08:00
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
let vec[ty.t] ty_param_substs = vec();
|
2011-04-12 15:09:50 -07:00
|
|
|
i = 0u;
|
2011-03-09 17:48:07 -08:00
|
|
|
for (ast.ty_param tp in ty_params) {
|
2011-04-20 18:52:04 -07:00
|
|
|
ty_param_substs += vec(ty.mk_param(cx.ccx.tystore, i));
|
2011-04-12 15:09:50 -07:00
|
|
|
i += 1u;
|
2011-03-09 17:48:07 -08:00
|
|
|
}
|
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
auto arg_tys = arg_tys_of_fn(cx.ccx, variant.node.ann);
|
2011-03-28 18:04:52 -07:00
|
|
|
copy_args_to_allocas(fcx, fn_args, arg_tys);
|
|
|
|
|
|
|
|
auto bcx = new_top_block_ctxt(fcx);
|
|
|
|
auto lltop = bcx.llbb;
|
2010-12-06 16:50:24 -08:00
|
|
|
|
2011-03-03 15:52:54 -08:00
|
|
|
// Cast the tag to a type we can GEP into.
|
|
|
|
auto lltagptr = bcx.build.PointerCast(fcx.llretptr,
|
2011-04-17 14:24:45 +02:00
|
|
|
T_opaque_tag_ptr(fcx.lcx.ccx.tn));
|
2011-03-03 15:52:54 -08:00
|
|
|
|
|
|
|
auto lldiscrimptr = bcx.build.GEP(lltagptr,
|
2011-02-08 11:47:53 -08:00
|
|
|
vec(C_int(0), C_int(0)));
|
2010-12-06 16:50:24 -08:00
|
|
|
bcx.build.Store(C_int(index), lldiscrimptr);
|
|
|
|
|
2011-03-03 15:52:54 -08:00
|
|
|
auto llblobptr = bcx.build.GEP(lltagptr,
|
2011-02-08 11:47:53 -08:00
|
|
|
vec(C_int(0), C_int(1)));
|
2010-12-06 16:50:24 -08:00
|
|
|
|
|
|
|
i = 0u;
|
2011-03-29 12:46:55 +02:00
|
|
|
for (ast.variant_arg va in variant.node.args) {
|
|
|
|
auto rslt = GEP_tag(bcx, llblobptr, tag_id, variant.node.id,
|
2011-03-09 17:48:07 -08:00
|
|
|
ty_param_substs, i as int);
|
2011-03-03 15:52:54 -08:00
|
|
|
bcx = rslt.bcx;
|
|
|
|
auto lldestptr = rslt.val;
|
2010-12-06 16:50:24 -08:00
|
|
|
|
2011-03-04 15:08:33 -08:00
|
|
|
// 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.
|
|
|
|
auto llargptr = bcx.build.PointerCast(fcx.llargs.get(va.id),
|
2011-04-01 16:04:22 -07:00
|
|
|
val_ty(lldestptr));
|
2011-03-04 15:08:33 -08:00
|
|
|
|
2011-03-04 18:05:48 -08:00
|
|
|
auto arg_ty = arg_tys.(i).ty;
|
|
|
|
auto llargval;
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_is_structural(cx.ccx.tystore, arg_ty) ||
|
|
|
|
ty.type_has_dynamic_size(cx.ccx.tystore, arg_ty)) {
|
2011-03-04 18:05:48 -08:00
|
|
|
llargval = llargptr;
|
|
|
|
} else {
|
|
|
|
llargval = bcx.build.Load(llargptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
rslt = copy_ty(bcx, INIT, lldestptr, llargval, arg_ty);
|
|
|
|
bcx = rslt.bcx;
|
|
|
|
|
2010-12-06 16:50:24 -08:00
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
|
|
|
|
bcx = trans_block_cleanups(bcx, find_scope_cx(bcx));
|
2011-02-08 11:47:53 -08:00
|
|
|
bcx.build.RetVoid();
|
2011-03-28 18:04:52 -07:00
|
|
|
|
|
|
|
// Tie up the llallocas -> lltop edge.
|
|
|
|
new_builder(fcx.llallocas).Br(lltop);
|
2010-12-01 19:03:47 -08:00
|
|
|
}
|
|
|
|
|
2011-01-21 12:09:25 -08:00
|
|
|
// 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?
|
|
|
|
|
|
|
|
fn trans_const_expr(@crate_ctxt cx, @ast.expr e) -> ValueRef {
|
|
|
|
alt (e.node) {
|
|
|
|
case (ast.expr_lit(?lit, ?ann)) {
|
|
|
|
ret trans_lit(cx, *lit, ann);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trans_const(@crate_ctxt cx, @ast.expr e,
|
|
|
|
&ast.def_id cid, &ast.ann ann) {
|
|
|
|
auto t = node_ann_type(cx, ann);
|
|
|
|
auto v = trans_const_expr(cx, e);
|
2011-03-18 16:22:59 -07:00
|
|
|
|
|
|
|
// The scalars come back as 1st class LLVM vals
|
|
|
|
// which we have to stick into global constants.
|
|
|
|
auto g = cx.consts.get(cid);
|
|
|
|
llvm.LLVMSetInitializer(g, v);
|
|
|
|
llvm.LLVMSetGlobalConstant(g, True);
|
2011-01-21 12:09:25 -08:00
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
fn trans_item(@local_ctxt cx, &ast.item item) {
|
2010-10-05 18:21:44 -07:00
|
|
|
alt (item.node) {
|
2010-12-20 14:33:11 -08:00
|
|
|
case (ast.item_fn(?name, ?f, ?tps, ?fid, ?ann)) {
|
2011-03-26 17:36:47 -07:00
|
|
|
auto sub_cx = extend_path(cx, name);
|
2011-04-22 12:27:28 -07:00
|
|
|
trans_fn(sub_cx, f, fid, none[tup(TypeRef, ty.t)], tps, ann);
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
2010-12-20 14:33:11 -08:00
|
|
|
case (ast.item_obj(?name, ?ob, ?tps, ?oid, ?ann)) {
|
2011-03-26 17:36:47 -07:00
|
|
|
auto sub_cx = @rec(obj_typarams=tps,
|
|
|
|
obj_fields=ob.fields with
|
|
|
|
*extend_path(cx, name));
|
2011-03-30 17:23:25 -07:00
|
|
|
trans_obj(sub_cx, ob, oid.ctor, tps, ann);
|
2010-12-16 15:55:28 -08:00
|
|
|
}
|
2010-10-18 18:19:16 -07:00
|
|
|
case (ast.item_mod(?name, ?m, _)) {
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
auto sub_cx = @rec(path = cx.path + vec(name),
|
|
|
|
module_path = cx.module_path + vec(name)
|
|
|
|
with *cx);
|
2010-10-06 15:41:14 -07:00
|
|
|
trans_mod(sub_cx, m);
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
2011-03-31 19:12:40 -07:00
|
|
|
case (ast.item_tag(?name, ?variants, ?tps, ?tag_id, _)) {
|
2011-03-26 17:36:47 -07:00
|
|
|
auto sub_cx = extend_path(cx, name);
|
2010-12-06 16:50:24 -08:00
|
|
|
auto i = 0;
|
2010-12-01 19:03:47 -08:00
|
|
|
for (ast.variant variant in variants) {
|
2010-12-20 14:33:11 -08:00
|
|
|
trans_tag_variant(sub_cx, tag_id, variant, i, tps);
|
2010-12-06 16:50:24 -08:00
|
|
|
i += 1;
|
2010-12-01 19:03:47 -08:00
|
|
|
}
|
|
|
|
}
|
2011-01-21 12:09:25 -08:00
|
|
|
case (ast.item_const(?name, _, ?expr, ?cid, ?ann)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
trans_const(cx.ccx, expr, cid, ann);
|
2011-01-21 12:09:25 -08:00
|
|
|
}
|
2010-12-01 17:08:46 -08:00
|
|
|
case (_) { /* fall through */ }
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
fn trans_mod(@local_ctxt cx, &ast._mod m) {
|
2010-10-18 18:19:16 -07:00
|
|
|
for (@ast.item item in m.items) {
|
|
|
|
trans_item(cx, *item);
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-07 15:12:23 -08:00
|
|
|
fn get_pair_fn_ty(TypeRef llpairty) -> TypeRef {
|
|
|
|
// Bit of a kludge: pick the fn typeref out of the pair.
|
|
|
|
let vec[TypeRef] pair_tys = vec(T_nil(), T_nil());
|
|
|
|
llvm.LLVMGetStructElementTypes(llpairty,
|
|
|
|
_vec.buf[TypeRef](pair_tys));
|
|
|
|
ret llvm.LLVMGetElementType(pair_tys.(0));
|
|
|
|
}
|
|
|
|
|
2011-04-20 17:23:45 +02:00
|
|
|
fn decl_fn_and_pair(@crate_ctxt ccx,
|
|
|
|
vec[str] path,
|
2011-03-26 17:36:47 -07:00
|
|
|
str flav,
|
2011-03-08 16:51:23 -08:00
|
|
|
vec[ast.ty_param] ty_params,
|
2011-01-05 15:31:35 -08:00
|
|
|
&ast.ann ann,
|
|
|
|
ast.def_id id) {
|
|
|
|
|
2011-03-08 16:51:23 -08:00
|
|
|
auto llfty;
|
|
|
|
auto llpairty;
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(ccx.tystore, node_ann_type(ccx, ann))) {
|
2011-03-08 16:51:23 -08:00
|
|
|
case (ty.ty_fn(?proto, ?inputs, ?output)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
llfty = type_of_fn(ccx, proto, inputs, output,
|
2011-03-08 16:51:23 -08:00
|
|
|
_vec.len[ast.ty_param](ty_params));
|
2011-04-17 14:24:45 +02:00
|
|
|
llpairty = T_fn_pair(ccx.tn, llfty);
|
2011-03-08 16:51:23 -08:00
|
|
|
}
|
|
|
|
case (_) {
|
2011-04-17 14:24:45 +02:00
|
|
|
ccx.sess.bug("decl_fn_and_pair(): fn item doesn't have fn type!");
|
2011-03-08 16:51:23 -08:00
|
|
|
fail;
|
|
|
|
}
|
|
|
|
}
|
2011-01-05 15:31:35 -08:00
|
|
|
|
|
|
|
// Declare the function itself.
|
2011-04-20 17:23:45 +02:00
|
|
|
let str s = mangle_name_by_seq(ccx, path, flav);
|
2011-04-17 14:24:45 +02:00
|
|
|
let ValueRef llfn = decl_internal_fastcall_fn(ccx.llmod, s, llfty);
|
2011-01-05 15:31:35 -08:00
|
|
|
|
|
|
|
// Declare the global constant pair that points to it.
|
2011-04-20 17:23:45 +02:00
|
|
|
let str ps = mangle_name_by_type(ccx, path, node_ann_type(ccx, ann));
|
2011-02-28 17:33:46 -05:00
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
register_fn_pair(ccx, ps, llpairty, llfn, id);
|
2011-02-28 17:33:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn register_fn_pair(@crate_ctxt cx, str ps, TypeRef llpairty, ValueRef llfn,
|
|
|
|
ast.def_id id) {
|
2011-01-05 15:31:35 -08:00
|
|
|
let ValueRef gvar = llvm.LLVMAddGlobal(cx.llmod, llpairty,
|
|
|
|
_str.buf(ps));
|
|
|
|
auto pair = C_struct(vec(llfn,
|
2011-02-17 18:16:51 -08:00
|
|
|
C_null(T_opaque_closure_ptr(cx.tn))));
|
2011-01-05 15:31:35 -08:00
|
|
|
|
|
|
|
llvm.LLVMSetInitializer(gvar, pair);
|
|
|
|
llvm.LLVMSetGlobalConstant(gvar, True);
|
2011-03-26 19:14:07 -07:00
|
|
|
llvm.LLVMSetVisibility(gvar,
|
|
|
|
lib.llvm.LLVMProtectedVisibility
|
|
|
|
as llvm.Visibility);
|
2011-01-05 15:31:35 -08:00
|
|
|
|
|
|
|
cx.item_ids.insert(id, llfn);
|
2011-03-23 15:43:18 -07:00
|
|
|
cx.item_symbols.insert(id, ps);
|
2011-01-05 15:31:35 -08:00
|
|
|
cx.fn_pairs.insert(id, gvar);
|
|
|
|
}
|
|
|
|
|
2011-03-08 16:51:23 -08:00
|
|
|
// Returns the number of type parameters that the given native function has.
|
|
|
|
fn native_fn_ty_param_count(@crate_ctxt cx, &ast.def_id id) -> uint {
|
|
|
|
auto count;
|
|
|
|
auto native_item = cx.native_items.get(id);
|
|
|
|
alt (native_item.node) {
|
|
|
|
case (ast.native_item_ty(_,_)) {
|
|
|
|
cx.sess.bug("decl_native_fn_and_pair(): native fn isn't " +
|
|
|
|
"actually a fn?!");
|
|
|
|
fail;
|
|
|
|
}
|
2011-03-20 20:18:19 -07:00
|
|
|
case (ast.native_item_fn(_, _, _, ?tps, _, _)) {
|
2011-03-08 16:51:23 -08:00
|
|
|
count = _vec.len[ast.ty_param](tps);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret count;
|
|
|
|
}
|
|
|
|
|
2011-04-22 12:27:28 -07:00
|
|
|
fn native_fn_wrapper_type(@crate_ctxt cx, uint ty_param_count, ty.t x)
|
2011-04-01 16:04:22 -07:00
|
|
|
-> TypeRef {
|
2011-04-22 17:00:46 -07:00
|
|
|
alt (ty.struct(cx.tystore, x)) {
|
2011-02-28 17:33:46 -05:00
|
|
|
case (ty.ty_native_fn(?abi, ?args, ?out)) {
|
2011-03-08 16:51:23 -08:00
|
|
|
ret type_of_fn(cx, ast.proto_fn, args, out, ty_param_count);
|
2011-02-28 17:33:46 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
fail;
|
|
|
|
}
|
|
|
|
|
2011-04-20 17:23:45 +02:00
|
|
|
fn decl_native_fn_and_pair(@crate_ctxt ccx,
|
|
|
|
vec[str] path,
|
2011-02-16 15:34:59 -05:00
|
|
|
str name,
|
|
|
|
&ast.ann ann,
|
|
|
|
ast.def_id id) {
|
2011-04-20 17:23:45 +02:00
|
|
|
auto num_ty_param = native_fn_ty_param_count(ccx, id);
|
2011-03-08 16:51:23 -08:00
|
|
|
|
2011-02-28 17:33:46 -05:00
|
|
|
// Declare the wrapper.
|
2011-04-17 14:24:45 +02:00
|
|
|
auto t = node_ann_type(ccx, ann);
|
|
|
|
auto wrapper_type = native_fn_wrapper_type(ccx, num_ty_param, t);
|
2011-04-20 17:23:45 +02:00
|
|
|
let str s = mangle_name_by_seq(ccx, path, "wrapper");
|
2011-04-17 14:24:45 +02:00
|
|
|
let ValueRef wrapper_fn = decl_internal_fastcall_fn(ccx.llmod, s,
|
|
|
|
wrapper_type);
|
2011-02-16 15:34:59 -05:00
|
|
|
|
2011-02-28 17:33:46 -05:00
|
|
|
// Declare the global constant pair that points to it.
|
2011-04-17 14:24:45 +02:00
|
|
|
auto wrapper_pair_type = T_fn_pair(ccx.tn, wrapper_type);
|
2011-04-20 17:23:45 +02:00
|
|
|
let str ps = mangle_name_by_type(ccx, path, node_ann_type(ccx, ann));
|
2011-02-16 15:34:59 -05:00
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
register_fn_pair(ccx, ps, wrapper_pair_type, wrapper_fn, id);
|
2011-02-28 17:33:46 -05:00
|
|
|
|
2011-03-07 15:37:40 -05:00
|
|
|
// Build the wrapper.
|
2011-04-20 17:23:45 +02:00
|
|
|
auto fcx = new_fn_ctxt(new_local_ctxt(ccx), wrapper_fn);
|
2011-03-07 15:37:40 -05:00
|
|
|
auto bcx = new_top_block_ctxt(fcx);
|
2011-03-28 18:04:52 -07:00
|
|
|
auto lltop = bcx.llbb;
|
2011-03-07 15:37:40 -05:00
|
|
|
|
2011-03-18 15:01:45 -07:00
|
|
|
// Declare the function itself.
|
2011-04-17 14:24:45 +02:00
|
|
|
auto item = ccx.native_items.get(id);
|
|
|
|
auto fn_type = node_ann_type(ccx, ann); // NB: has no type params
|
2011-03-18 15:01:45 -07:00
|
|
|
|
2011-04-22 17:00:46 -07:00
|
|
|
auto abi = ty.ty_fn_abi(ccx.tystore, fn_type);
|
|
|
|
auto llfnty = type_of_native_fn(ccx, abi,
|
|
|
|
ty.ty_fn_args(ccx.tystore, fn_type),
|
|
|
|
ty.ty_fn_ret(ccx.tystore, fn_type), num_ty_param);
|
2011-03-19 17:33:46 -07:00
|
|
|
|
2011-03-18 15:01:45 -07:00
|
|
|
let vec[ValueRef] call_args = vec();
|
2011-03-07 15:37:40 -05:00
|
|
|
auto arg_n = 3u;
|
2011-03-21 17:47:38 -04:00
|
|
|
auto pass_task;
|
|
|
|
|
2011-04-05 21:21:32 +00:00
|
|
|
auto lltaskptr = vp2i(bcx, fcx.lltaskptr);
|
2011-03-07 15:37:40 -05:00
|
|
|
alt (abi) {
|
|
|
|
case (ast.native_abi_rust) {
|
2011-03-21 17:47:38 -04:00
|
|
|
pass_task = true;
|
2011-03-23 16:31:30 -07:00
|
|
|
call_args += vec(lltaskptr);
|
2011-03-07 15:37:40 -05:00
|
|
|
for each (uint i in _uint.range(0u, num_ty_param)) {
|
|
|
|
auto llarg = llvm.LLVMGetParam(fcx.llfn, arg_n);
|
|
|
|
check (llarg as int != 0);
|
2011-04-05 21:21:32 +00:00
|
|
|
call_args += vec(vp2i(bcx, llarg));
|
2011-03-07 15:37:40 -05:00
|
|
|
arg_n += 1u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case (ast.native_abi_cdecl) {
|
2011-03-21 17:47:38 -04:00
|
|
|
pass_task = false;
|
2011-03-07 15:37:40 -05:00
|
|
|
}
|
2011-03-28 08:24:11 -07:00
|
|
|
case (ast.native_abi_llvm) {
|
|
|
|
pass_task = false;
|
|
|
|
// We handle this case below.
|
|
|
|
}
|
2011-03-07 15:37:40 -05:00
|
|
|
}
|
2011-03-28 08:24:11 -07:00
|
|
|
|
2011-04-05 21:21:32 +00:00
|
|
|
fn push_arg(@block_ctxt cx,
|
|
|
|
&mutable vec[ValueRef] args,
|
|
|
|
ValueRef v,
|
2011-04-22 12:27:28 -07:00
|
|
|
ty.t t) {
|
2011-04-22 17:00:46 -07:00
|
|
|
if (ty.type_is_integral(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-04-05 21:21:32 +00:00
|
|
|
auto lldsttype = T_int();
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llsrctype = type_of(cx.fcx.lcx.ccx, t);
|
2011-04-05 21:21:32 +00:00
|
|
|
if (llvm.LLVMGetIntTypeWidth(lldsttype) >
|
|
|
|
llvm.LLVMGetIntTypeWidth(llsrctype)) {
|
|
|
|
args += vec(cx.build.ZExtOrBitCast(v, T_int()));
|
|
|
|
} else {
|
|
|
|
args += vec(cx.build.TruncOrBitCast(v, T_int()));
|
|
|
|
}
|
2011-04-22 17:00:46 -07:00
|
|
|
} else if (ty.type_is_fp(cx.fcx.lcx.ccx.tystore, t)) {
|
2011-04-05 21:21:32 +00:00
|
|
|
args += vec(cx.build.FPToSI(v, T_int()));
|
|
|
|
} else {
|
|
|
|
args += vec(vp2i(cx, v));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-28 08:24:11 -07:00
|
|
|
auto r;
|
|
|
|
auto rptr;
|
2011-04-22 17:00:46 -07:00
|
|
|
auto args = ty.ty_fn_args(ccx.tystore, fn_type);
|
2011-03-28 08:24:11 -07:00
|
|
|
if (abi == ast.native_abi_llvm) {
|
|
|
|
let vec[ValueRef] call_args = vec();
|
|
|
|
let vec[TypeRef] call_arg_tys = vec();
|
|
|
|
auto i = 0u;
|
|
|
|
while (i < _vec.len[ty.arg](args)) {
|
|
|
|
auto call_arg = llvm.LLVMGetParam(fcx.llfn, i + 3u);
|
|
|
|
call_args += vec(call_arg);
|
|
|
|
call_arg_tys += vec(val_ty(call_arg));
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
auto llnativefnty = T_fn(call_arg_tys,
|
2011-04-22 17:00:46 -07:00
|
|
|
type_of(ccx,
|
|
|
|
ty.ty_fn_ret(ccx.tystore, fn_type)));
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llnativefn = get_extern_fn(ccx.externs, ccx.llmod, name,
|
2011-03-28 08:24:11 -07:00
|
|
|
lib.llvm.LLVMCCallConv, llnativefnty);
|
|
|
|
r = bcx.build.Call(llnativefn, call_args);
|
|
|
|
rptr = fcx.llretptr;
|
|
|
|
} else {
|
|
|
|
for (ty.arg arg in args) {
|
|
|
|
auto llarg = llvm.LLVMGetParam(fcx.llfn, arg_n);
|
|
|
|
check (llarg as int != 0);
|
2011-04-05 21:21:32 +00:00
|
|
|
push_arg(bcx, call_args, llarg, arg.ty);
|
2011-03-28 08:24:11 -07:00
|
|
|
arg_n += 1u;
|
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
r = trans_native_call(bcx.build, ccx.glues, lltaskptr, ccx.externs,
|
|
|
|
ccx.tn, ccx.llmod, name, pass_task, call_args);
|
2011-03-28 08:24:11 -07:00
|
|
|
rptr = bcx.build.BitCast(fcx.llretptr, T_ptr(T_i32()));
|
2011-03-07 15:37:40 -05:00
|
|
|
}
|
2011-03-08 16:51:23 -08:00
|
|
|
|
2011-03-21 17:47:38 -04:00
|
|
|
bcx.build.Store(r, rptr);
|
2011-03-07 15:37:40 -05:00
|
|
|
bcx.build.RetVoid();
|
2011-03-28 18:04:52 -07:00
|
|
|
|
|
|
|
// Tie up the llallocas -> lltop edge.
|
|
|
|
new_builder(fcx.llallocas).Br(lltop);
|
2011-02-16 15:34:59 -05:00
|
|
|
}
|
|
|
|
|
2011-04-20 17:23:45 +02:00
|
|
|
type walk_ctxt = rec(mutable vec[str] path);
|
2011-04-20 17:43:13 +02:00
|
|
|
fn new_walk_ctxt() -> @walk_ctxt {
|
|
|
|
let vec[str] path = vec();
|
|
|
|
ret @rec(mutable path=path);
|
|
|
|
}
|
2011-04-20 17:23:45 +02:00
|
|
|
|
|
|
|
fn enter_item(@walk_ctxt cx, @ast.item item) {
|
|
|
|
alt (item.node) {
|
|
|
|
case (ast.item_fn(?name, _, _, _, _)) {
|
|
|
|
_vec.push[str](cx.path, name);
|
2011-02-16 14:02:02 -05:00
|
|
|
}
|
2011-04-20 17:23:45 +02:00
|
|
|
case (ast.item_obj(?name, _, _, _, _)) {
|
|
|
|
_vec.push[str](cx.path, name);
|
|
|
|
}
|
|
|
|
case (ast.item_mod(?name, _, _)) {
|
|
|
|
_vec.push[str](cx.path, name);
|
2011-04-01 17:04:51 -07:00
|
|
|
}
|
2011-04-20 17:23:45 +02:00
|
|
|
case (_) { }
|
2011-02-16 14:02:02 -05:00
|
|
|
}
|
|
|
|
}
|
2010-09-27 13:43:53 -07:00
|
|
|
|
2011-04-20 17:23:45 +02:00
|
|
|
fn leave_item(@walk_ctxt cx, @ast.item item) {
|
|
|
|
alt (item.node) {
|
|
|
|
case (ast.item_fn(_, _, _, _, _)) {
|
|
|
|
_vec.pop[str](cx.path);
|
2011-03-26 17:36:47 -07:00
|
|
|
}
|
2011-04-20 17:23:45 +02:00
|
|
|
case (ast.item_obj(_, _, _, _, _)) {
|
|
|
|
_vec.pop[str](cx.path);
|
2011-03-26 17:36:47 -07:00
|
|
|
}
|
2011-04-20 17:23:45 +02:00
|
|
|
case (ast.item_mod(_, _, _)) {
|
|
|
|
_vec.pop[str](cx.path);
|
2011-03-26 17:36:47 -07:00
|
|
|
}
|
2011-04-20 17:23:45 +02:00
|
|
|
case (_) { }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn collect_native_item(@crate_ctxt ccx, @walk_ctxt wcx, @ast.native_item i) {
|
|
|
|
alt (i.node) {
|
|
|
|
case (ast.native_item_fn(?name, _, _, _, ?fid, ?ann)) {
|
|
|
|
ccx.native_items.insert(fid, i);
|
|
|
|
if (!ccx.obj_methods.contains_key(fid)) {
|
|
|
|
decl_native_fn_and_pair(ccx, wcx.path, name, ann, fid);
|
|
|
|
}
|
2011-03-26 17:36:47 -07:00
|
|
|
}
|
2011-04-20 17:23:45 +02:00
|
|
|
case (ast.native_item_ty(_, ?tid)) {
|
|
|
|
ccx.native_items.insert(tid, i);
|
2011-03-26 17:36:47 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-01-05 15:31:35 -08:00
|
|
|
|
2011-04-20 17:23:45 +02:00
|
|
|
fn collect_item_1(@crate_ctxt ccx, @walk_ctxt wcx, @ast.item i) {
|
|
|
|
enter_item(wcx, i);
|
|
|
|
|
2011-03-14 16:56:03 -04:00
|
|
|
alt (i.node) {
|
2011-03-18 16:22:59 -07:00
|
|
|
case (ast.item_const(?name, _, _, ?cid, ?ann)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
auto typ = node_ann_type(ccx, ann);
|
|
|
|
auto g = llvm.LLVMAddGlobal(ccx.llmod, type_of(ccx, typ),
|
|
|
|
_str.buf(ccx.names.next(name)));
|
2011-04-01 15:01:46 -07:00
|
|
|
llvm.LLVMSetLinkage(g, lib.llvm.LLVMInternalLinkage
|
2011-03-18 16:22:59 -07:00
|
|
|
as llvm.Linkage);
|
2011-04-17 14:24:45 +02:00
|
|
|
ccx.items.insert(cid, i);
|
|
|
|
ccx.consts.insert(cid, g);
|
2011-03-14 16:56:03 -04:00
|
|
|
}
|
|
|
|
case (ast.item_mod(?name, ?m, ?mid)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
ccx.items.insert(mid, i);
|
2011-03-14 16:56:03 -04:00
|
|
|
}
|
2011-03-29 18:15:59 -07:00
|
|
|
case (ast.item_ty(_, _, _, ?did, _)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
ccx.items.insert(did, i);
|
2011-03-29 18:15:59 -07:00
|
|
|
}
|
2011-03-31 19:12:40 -07:00
|
|
|
case (ast.item_tag(?name, ?variants, ?tps, ?tag_id, _)) {
|
2011-04-17 14:24:45 +02:00
|
|
|
ccx.items.insert(tag_id, i);
|
2011-03-14 16:56:03 -04:00
|
|
|
}
|
2011-04-20 17:23:45 +02:00
|
|
|
case (_) {}
|
2011-03-14 16:56:03 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-20 17:23:45 +02:00
|
|
|
fn collect_item_2(@crate_ctxt ccx, @walk_ctxt wcx, @ast.item i) {
|
|
|
|
enter_item(wcx, i);
|
|
|
|
|
2010-10-22 19:31:33 -07:00
|
|
|
alt (i.node) {
|
2011-03-08 16:51:23 -08:00
|
|
|
case (ast.item_fn(?name, ?f, ?tps, ?fid, ?ann)) {
|
2011-04-20 17:23:45 +02:00
|
|
|
ccx.items.insert(fid, i);
|
|
|
|
if (!ccx.obj_methods.contains_key(fid)) {
|
|
|
|
decl_fn_and_pair(ccx, wcx.path, "fn", tps, ann, fid);
|
2011-01-05 15:31:35 -08:00
|
|
|
}
|
2010-10-22 19:31:33 -07:00
|
|
|
}
|
2011-03-08 16:51:23 -08:00
|
|
|
case (ast.item_obj(?name, ?ob, ?tps, ?oid, ?ann)) {
|
2011-04-20 17:23:45 +02:00
|
|
|
ccx.items.insert(oid.ctor, i);
|
|
|
|
decl_fn_and_pair(ccx, wcx.path, "obj_ctor", tps, ann, oid.ctor);
|
2011-01-05 15:31:35 -08:00
|
|
|
for (@ast.method m in ob.methods) {
|
2011-04-20 17:23:45 +02:00
|
|
|
ccx.obj_methods.insert(m.node.id, ());
|
2011-01-05 15:31:35 -08:00
|
|
|
}
|
2010-12-16 10:23:47 -08:00
|
|
|
}
|
2011-04-20 17:23:45 +02:00
|
|
|
case (_) {}
|
2010-10-22 19:31:33 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-20 17:23:45 +02:00
|
|
|
fn collect_items(@crate_ctxt ccx, @ast.crate crate) {
|
2011-04-20 17:43:13 +02:00
|
|
|
auto wcx = new_walk_ctxt();
|
2011-04-20 17:23:45 +02:00
|
|
|
auto visitor0 = walk.default_visitor();
|
|
|
|
auto visitor1 = rec(visit_native_item_pre =
|
|
|
|
bind collect_native_item(ccx, wcx, _),
|
|
|
|
visit_item_pre = bind collect_item_1(ccx, wcx, _),
|
|
|
|
visit_item_post = bind leave_item(wcx, _)
|
|
|
|
with visitor0);
|
|
|
|
auto visitor2 = rec(visit_item_pre = bind collect_item_2(ccx, wcx, _),
|
|
|
|
visit_item_post = bind leave_item(wcx, _)
|
|
|
|
with visitor0);
|
|
|
|
walk.walk_crate(visitor1, *crate);
|
|
|
|
walk.walk_crate(visitor2, *crate);
|
2010-10-22 19:31:33 -07:00
|
|
|
}
|
|
|
|
|
2011-04-20 17:43:13 +02:00
|
|
|
fn collect_tag_ctor(@crate_ctxt ccx, @walk_ctxt wcx, @ast.item i) {
|
|
|
|
enter_item(wcx, i);
|
2011-01-05 15:31:35 -08:00
|
|
|
|
|
|
|
alt (i.node) {
|
2011-03-31 19:12:40 -07:00
|
|
|
case (ast.item_tag(_, ?variants, ?tps, _, _)) {
|
2011-01-05 15:31:35 -08:00
|
|
|
for (ast.variant variant in variants) {
|
2011-03-29 12:46:55 +02:00
|
|
|
if (_vec.len[ast.variant_arg](variant.node.args) != 0u) {
|
2011-04-20 17:43:13 +02:00
|
|
|
decl_fn_and_pair(ccx, wcx.path + vec(variant.node.name),
|
2011-03-29 12:46:55 +02:00
|
|
|
"tag", tps, variant.node.ann,
|
|
|
|
variant.node.id);
|
2011-01-05 15:31:35 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
case (_) { /* fall through */ }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-20 17:43:13 +02:00
|
|
|
fn collect_tag_ctors(@crate_ctxt ccx, @ast.crate crate) {
|
|
|
|
auto wcx = new_walk_ctxt();
|
|
|
|
auto visitor = rec(visit_item_pre = bind collect_tag_ctor(ccx, wcx, _),
|
|
|
|
visit_item_post = bind leave_item(wcx, _)
|
|
|
|
with walk.default_visitor());
|
|
|
|
walk.walk_crate(visitor, *crate);
|
2011-01-05 15:31:35 -08:00
|
|
|
}
|
|
|
|
|
2010-12-02 19:30:06 -08:00
|
|
|
// The constant translation pass.
|
|
|
|
|
2011-04-20 17:43:13 +02:00
|
|
|
fn trans_constant(@crate_ctxt ccx, @walk_ctxt wcx, @ast.item it) {
|
|
|
|
enter_item(wcx, it);
|
|
|
|
|
2010-12-02 19:30:06 -08:00
|
|
|
alt (it.node) {
|
2011-04-07 11:42:40 -07:00
|
|
|
case (ast.item_tag(?ident, ?variants, _, ?tag_id, _)) {
|
2010-12-02 19:30:06 -08:00
|
|
|
auto i = 0u;
|
2011-02-25 18:16:50 -08:00
|
|
|
auto n_variants = _vec.len[ast.variant](variants);
|
|
|
|
while (i < n_variants) {
|
|
|
|
auto variant = variants.(i);
|
2011-02-28 16:08:05 -08:00
|
|
|
|
|
|
|
auto discrim_val = C_int(i as int);
|
|
|
|
|
2011-04-20 17:43:13 +02:00
|
|
|
auto s = mangle_name_by_seq(ccx, wcx.path,
|
2011-04-07 11:42:40 -07:00
|
|
|
#fmt("_rust_tag_discrim_%s_%u",
|
|
|
|
ident, i));
|
2011-04-20 17:43:13 +02:00
|
|
|
auto discrim_gvar = llvm.LLVMAddGlobal(ccx.llmod, T_int(),
|
2011-03-23 15:43:18 -07:00
|
|
|
_str.buf(s));
|
2011-02-28 16:08:05 -08:00
|
|
|
|
|
|
|
llvm.LLVMSetInitializer(discrim_gvar, discrim_val);
|
|
|
|
llvm.LLVMSetGlobalConstant(discrim_gvar, True);
|
|
|
|
|
2011-04-20 17:43:13 +02:00
|
|
|
ccx.discrims.insert(variant.node.id, discrim_gvar);
|
|
|
|
ccx.discrim_symbols.insert(variant.node.id, s);
|
2010-12-02 19:30:06 -08:00
|
|
|
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
}
|
2010-12-09 14:37:50 -08:00
|
|
|
|
|
|
|
case (ast.item_const(?name, _, ?expr, ?cid, ?ann)) {
|
|
|
|
// FIXME: The whole expr-translation system needs cloning to deal
|
|
|
|
// with consts.
|
|
|
|
auto v = C_int(1);
|
2011-04-20 17:43:13 +02:00
|
|
|
ccx.item_ids.insert(cid, v);
|
|
|
|
auto s = mangle_name_by_type(ccx, wcx.path + vec(name),
|
|
|
|
node_ann_type(ccx, ann));
|
|
|
|
ccx.item_symbols.insert(cid, s);
|
2010-12-09 14:37:50 -08:00
|
|
|
}
|
|
|
|
|
2011-04-20 17:43:13 +02:00
|
|
|
case (_) {}
|
2010-12-02 19:30:06 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-20 17:43:13 +02:00
|
|
|
fn trans_constants(@crate_ctxt ccx, @ast.crate crate) {
|
|
|
|
auto wcx = new_walk_ctxt();
|
|
|
|
auto visitor = rec(visit_item_pre = bind trans_constant(ccx, wcx, _),
|
|
|
|
visit_item_post = bind leave_item(wcx, _)
|
|
|
|
with walk.default_visitor());
|
|
|
|
walk.walk_crate(visitor, *crate);
|
2010-12-02 19:30:06 -08:00
|
|
|
}
|
|
|
|
|
2011-03-02 16:42:09 -08:00
|
|
|
|
|
|
|
fn vp2i(@block_ctxt cx, ValueRef v) -> ValueRef {
|
|
|
|
ret cx.build.PtrToInt(v, T_int());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn vi2p(@block_ctxt cx, ValueRef v, TypeRef t) -> ValueRef {
|
|
|
|
ret cx.build.IntToPtr(v, t);
|
|
|
|
}
|
|
|
|
|
2010-09-27 13:43:53 -07:00
|
|
|
fn p2i(ValueRef v) -> ValueRef {
|
|
|
|
ret llvm.LLVMConstPtrToInt(v, T_int());
|
|
|
|
}
|
|
|
|
|
2011-02-01 14:57:03 -08:00
|
|
|
fn i2p(ValueRef v, TypeRef t) -> ValueRef {
|
|
|
|
ret llvm.LLVMConstIntToPtr(v, t);
|
|
|
|
}
|
|
|
|
|
2011-03-10 17:25:11 -08:00
|
|
|
fn trans_exit_task_glue(@glue_fns glues,
|
2011-03-25 15:48:00 -07:00
|
|
|
&hashmap[str, ValueRef] externs,
|
2011-03-10 17:25:11 -08:00
|
|
|
type_names tn, ModuleRef llmod) {
|
2010-09-27 15:38:34 -07:00
|
|
|
let vec[TypeRef] T_args = vec();
|
|
|
|
let vec[ValueRef] V_args = vec();
|
|
|
|
|
2011-03-10 17:25:11 -08:00
|
|
|
auto llfn = glues.exit_task_glue;
|
2011-03-30 13:04:18 -07:00
|
|
|
let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 4u);
|
2010-09-27 15:38:34 -07:00
|
|
|
|
2011-03-10 17:25:11 -08:00
|
|
|
auto entrybb = llvm.LLVMAppendBasicBlock(llfn, _str.buf("entry"));
|
|
|
|
auto build = new_builder(entrybb);
|
2011-03-21 11:11:22 -04:00
|
|
|
auto tptr = build.PtrToInt(lltaskptr, T_int());
|
2011-03-21 11:59:14 -04:00
|
|
|
auto V_args2 = vec(tptr) + V_args;
|
2011-03-29 13:21:36 -07:00
|
|
|
trans_native_call(build, glues, lltaskptr,
|
|
|
|
externs, tn, llmod, "upcall_exit", true, V_args2);
|
2011-03-10 17:25:11 -08:00
|
|
|
build.RetVoid();
|
2010-09-27 15:38:34 -07:00
|
|
|
}
|
|
|
|
|
2010-12-10 16:29:41 -08:00
|
|
|
fn create_typedefs(@crate_ctxt cx) {
|
2011-02-17 18:16:51 -08:00
|
|
|
llvm.LLVMAddTypeName(cx.llmod, _str.buf("crate"), T_crate(cx.tn));
|
|
|
|
llvm.LLVMAddTypeName(cx.llmod, _str.buf("task"), T_task(cx.tn));
|
|
|
|
llvm.LLVMAddTypeName(cx.llmod, _str.buf("tydesc"), T_tydesc(cx.tn));
|
2010-12-10 16:29:41 -08:00
|
|
|
}
|
|
|
|
|
2011-04-18 16:18:55 +02:00
|
|
|
fn create_crate_constant(ValueRef crate_ptr, @glue_fns glues) {
|
2010-09-24 16:41:01 -07:00
|
|
|
|
2011-03-10 17:25:11 -08:00
|
|
|
let ValueRef crate_addr = p2i(crate_ptr);
|
2010-09-24 16:41:01 -07:00
|
|
|
|
|
|
|
let ValueRef activate_glue_off =
|
2011-03-10 17:25:11 -08:00
|
|
|
llvm.LLVMConstSub(p2i(glues.activate_glue), crate_addr);
|
2010-09-24 16:41:01 -07:00
|
|
|
|
|
|
|
let ValueRef yield_glue_off =
|
2011-03-10 17:25:11 -08:00
|
|
|
llvm.LLVMConstSub(p2i(glues.yield_glue), crate_addr);
|
2010-09-24 16:41:01 -07:00
|
|
|
|
2010-09-27 15:38:34 -07:00
|
|
|
let ValueRef exit_task_glue_off =
|
2011-03-10 17:25:11 -08:00
|
|
|
llvm.LLVMConstSub(p2i(glues.exit_task_glue), crate_addr);
|
2010-09-24 16:41:01 -07:00
|
|
|
|
|
|
|
let ValueRef crate_val =
|
|
|
|
C_struct(vec(C_null(T_int()), // ptrdiff_t image_base_off
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
p2i(crate_ptr), // uintptr_t self_addr
|
2010-09-24 16:41:01 -07:00
|
|
|
C_null(T_int()), // ptrdiff_t debug_abbrev_off
|
|
|
|
C_null(T_int()), // size_t debug_abbrev_sz
|
|
|
|
C_null(T_int()), // ptrdiff_t debug_info_off
|
|
|
|
C_null(T_int()), // size_t debug_info_sz
|
|
|
|
activate_glue_off, // size_t activate_glue_off
|
|
|
|
yield_glue_off, // size_t yield_glue_off
|
|
|
|
C_null(T_int()), // size_t unwind_glue_off
|
|
|
|
C_null(T_int()), // size_t gc_glue_off
|
|
|
|
exit_task_glue_off, // size_t main_exit_task_glue_off
|
|
|
|
C_null(T_int()), // int n_rust_syms
|
|
|
|
C_null(T_int()), // int n_c_syms
|
2011-02-22 16:37:01 -08:00
|
|
|
C_null(T_int()), // int n_libs
|
2011-04-18 16:18:55 +02:00
|
|
|
C_int(abi.abi_x86_rustc_fastcall) // uintptr_t abi_tag
|
2010-09-24 16:41:01 -07:00
|
|
|
));
|
|
|
|
|
2011-03-10 17:25:11 -08:00
|
|
|
llvm.LLVMSetInitializer(crate_ptr, crate_val);
|
2010-09-24 16:41:01 -07:00
|
|
|
}
|
|
|
|
|
2011-02-21 17:42:23 -08:00
|
|
|
fn find_main_fn(@crate_ctxt cx) -> ValueRef {
|
|
|
|
auto e = sep() + "main";
|
|
|
|
let ValueRef v = C_nil();
|
|
|
|
let uint n = 0u;
|
2011-03-26 17:36:47 -07:00
|
|
|
for each (@tup(ast.def_id, str) i in cx.item_symbols.items()) {
|
|
|
|
if (_str.ends_with(i._1, e)) {
|
2011-02-21 17:42:23 -08:00
|
|
|
n += 1u;
|
2011-03-26 17:36:47 -07:00
|
|
|
v = cx.item_ids.get(i._0);
|
2011-02-21 17:42:23 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
alt (n) {
|
|
|
|
case (0u) {
|
|
|
|
cx.sess.err("main fn not found");
|
|
|
|
}
|
|
|
|
case (1u) {
|
|
|
|
ret v;
|
|
|
|
}
|
|
|
|
case (_) {
|
|
|
|
cx.sess.err("multiple main fns found");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fail;
|
|
|
|
}
|
|
|
|
|
2011-04-18 16:18:55 +02:00
|
|
|
fn trans_main_fn(@local_ctxt cx, ValueRef llcrate, ValueRef crate_map) {
|
2010-09-27 13:43:53 -07:00
|
|
|
auto T_main_args = vec(T_int(), T_int());
|
2011-04-18 16:18:55 +02:00
|
|
|
auto T_rust_start_args = vec(T_int(), T_int(), T_int(), T_int(), T_int());
|
2010-09-27 13:43:53 -07:00
|
|
|
|
2010-11-05 18:28:51 -07:00
|
|
|
auto main_name;
|
|
|
|
if (_str.eq(std.os.target_os(), "win32")) {
|
|
|
|
main_name = "WinMain@16";
|
|
|
|
} else {
|
|
|
|
main_name = "main";
|
|
|
|
}
|
|
|
|
|
2010-09-27 13:43:53 -07:00
|
|
|
auto llmain =
|
2011-04-17 14:24:45 +02:00
|
|
|
decl_cdecl_fn(cx.ccx.llmod, main_name, T_fn(T_main_args, T_int()));
|
2010-09-27 13:43:53 -07:00
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llrust_start = decl_cdecl_fn(cx.ccx.llmod, "rust_start",
|
2010-11-03 16:43:12 -07:00
|
|
|
T_fn(T_rust_start_args, T_int()));
|
2010-09-27 13:43:53 -07:00
|
|
|
|
|
|
|
auto llargc = llvm.LLVMGetParam(llmain, 0u);
|
|
|
|
auto llargv = llvm.LLVMGetParam(llmain, 1u);
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llrust_main = find_main_fn(cx.ccx);
|
2010-09-27 13:43:53 -07:00
|
|
|
|
|
|
|
//
|
|
|
|
// Emit the moral equivalent of:
|
|
|
|
//
|
|
|
|
// main(int argc, char **argv) {
|
|
|
|
// rust_start(&_rust.main, &crate, argc, argv);
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
|
|
|
|
let BasicBlockRef llbb =
|
|
|
|
llvm.LLVMAppendBasicBlock(llmain, _str.buf(""));
|
2010-12-17 18:42:15 -08:00
|
|
|
auto b = new_builder(llbb);
|
2010-09-27 13:43:53 -07:00
|
|
|
|
2011-04-18 16:18:55 +02:00
|
|
|
auto start_args = vec(p2i(llrust_main), p2i(llcrate), llargc, llargv,
|
|
|
|
p2i(crate_map));
|
2010-09-27 13:43:53 -07:00
|
|
|
|
|
|
|
b.Ret(b.Call(llrust_start, start_args));
|
|
|
|
}
|
|
|
|
|
2010-11-25 17:45:26 -08:00
|
|
|
fn declare_intrinsics(ModuleRef llmod) -> hashmap[str,ValueRef] {
|
|
|
|
|
2010-11-14 11:21:49 -08:00
|
|
|
let vec[TypeRef] T_trap_args = vec();
|
2010-11-25 17:45:26 -08:00
|
|
|
auto trap = decl_cdecl_fn(llmod, "llvm.trap",
|
|
|
|
T_fn(T_trap_args, T_void()));
|
|
|
|
|
|
|
|
auto intrinsics = new_str_hash[ValueRef]();
|
|
|
|
intrinsics.insert("llvm.trap", trap);
|
|
|
|
ret intrinsics;
|
2010-11-14 11:21:49 -08:00
|
|
|
}
|
|
|
|
|
2011-02-02 15:23:49 -08:00
|
|
|
|
|
|
|
fn trace_str(@block_ctxt cx, str s) {
|
2011-04-17 14:24:45 +02:00
|
|
|
trans_upcall(cx, "upcall_trace_str", vec(p2i(C_cstr(cx.fcx.lcx.ccx, s))));
|
2011-02-02 15:23:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn trace_word(@block_ctxt cx, ValueRef v) {
|
|
|
|
trans_upcall(cx, "upcall_trace_word", vec(v));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trace_ptr(@block_ctxt cx, ValueRef v) {
|
|
|
|
trace_word(cx, cx.build.PtrToInt(v, T_int()));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trap(@block_ctxt bcx) {
|
|
|
|
let vec[ValueRef] v = vec();
|
2011-04-17 14:24:45 +02:00
|
|
|
bcx.build.Call(bcx.fcx.lcx.ccx.intrinsics.get("llvm.trap"), v);
|
2011-02-02 15:23:49 -08:00
|
|
|
}
|
2011-04-15 17:35:46 -04:00
|
|
|
tag output_type {
|
|
|
|
output_type_none;
|
|
|
|
output_type_bitcode;
|
|
|
|
output_type_assembly;
|
2011-04-18 10:02:34 -04:00
|
|
|
output_type_object;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_object_or_assembly(output_type ot) -> bool {
|
|
|
|
if (ot == output_type_assembly) {
|
|
|
|
ret true;
|
|
|
|
}
|
|
|
|
if (ot == output_type_object) {
|
|
|
|
ret true;
|
|
|
|
}
|
|
|
|
ret false;
|
2011-04-15 17:35:46 -04:00
|
|
|
}
|
2011-02-02 15:23:49 -08:00
|
|
|
|
2011-04-19 18:31:27 -07:00
|
|
|
fn run_passes(ModuleRef llmod, bool opt, bool verify, str output,
|
2011-04-15 17:35:46 -04:00
|
|
|
output_type ot) {
|
2010-12-06 17:17:49 -08:00
|
|
|
auto pm = mk_pass_manager();
|
|
|
|
|
|
|
|
// TODO: run the linter here also, once there are llvm-c bindings for it.
|
2011-04-07 12:12:21 -04:00
|
|
|
|
|
|
|
// FIXME: This is mostly a copy of the bits of opt's -O2 that are
|
|
|
|
// available in the C api.
|
|
|
|
// FIXME2: We might want to add optmization levels like -O1, -O2, -Os, etc
|
|
|
|
// FIXME3: Should we expose and use the pass lists used by the opt tool?
|
|
|
|
if (opt) {
|
|
|
|
auto fpm = mk_pass_manager();
|
|
|
|
|
|
|
|
// createStandardFunctionPasses
|
2011-04-13 13:53:19 -04:00
|
|
|
llvm.LLVMAddTypeBasedAliasAnalysisPass(fpm.llpm);
|
|
|
|
llvm.LLVMAddBasicAliasAnalysisPass(fpm.llpm);
|
2011-04-07 12:12:21 -04:00
|
|
|
llvm.LLVMAddCFGSimplificationPass(fpm.llpm);
|
|
|
|
llvm.LLVMAddScalarReplAggregatesPass(fpm.llpm);
|
2011-04-12 15:33:39 -04:00
|
|
|
llvm.LLVMAddEarlyCSEPass(fpm.llpm);
|
2011-04-07 12:12:21 -04:00
|
|
|
|
|
|
|
llvm.LLVMRunPassManager(fpm.llpm, llmod);
|
|
|
|
|
|
|
|
// createStandardModulePasses
|
2011-04-13 13:53:19 -04:00
|
|
|
llvm.LLVMAddTypeBasedAliasAnalysisPass(pm.llpm);
|
|
|
|
llvm.LLVMAddBasicAliasAnalysisPass(pm.llpm);
|
2011-04-07 12:12:21 -04:00
|
|
|
llvm.LLVMAddGlobalOptimizerPass(pm.llpm);
|
|
|
|
llvm.LLVMAddIPSCCPPass(pm.llpm);
|
|
|
|
llvm.LLVMAddDeadArgEliminationPass(pm.llpm);
|
|
|
|
llvm.LLVMAddInstructionCombiningPass(pm.llpm);
|
|
|
|
llvm.LLVMAddCFGSimplificationPass(pm.llpm);
|
|
|
|
llvm.LLVMAddPruneEHPass(pm.llpm);
|
|
|
|
llvm.LLVMAddFunctionInliningPass(pm.llpm);
|
2011-04-13 13:53:19 -04:00
|
|
|
llvm.LLVMAddFunctionAttrsPass(pm.llpm);
|
2011-04-12 15:33:39 -04:00
|
|
|
llvm.LLVMAddScalarReplAggregatesPassSSA(pm.llpm);
|
|
|
|
llvm.LLVMAddEarlyCSEPass(pm.llpm);
|
2011-04-07 12:12:21 -04:00
|
|
|
llvm.LLVMAddSimplifyLibCallsPass(pm.llpm);
|
|
|
|
llvm.LLVMAddJumpThreadingPass(pm.llpm);
|
2011-04-12 15:33:39 -04:00
|
|
|
llvm.LLVMAddCorrelatedValuePropagationPass(pm.llpm);
|
2011-04-07 12:12:21 -04:00
|
|
|
llvm.LLVMAddCFGSimplificationPass(pm.llpm);
|
|
|
|
llvm.LLVMAddInstructionCombiningPass(pm.llpm);
|
|
|
|
llvm.LLVMAddTailCallEliminationPass(pm.llpm);
|
|
|
|
llvm.LLVMAddCFGSimplificationPass(pm.llpm);
|
|
|
|
llvm.LLVMAddReassociatePass(pm.llpm);
|
|
|
|
llvm.LLVMAddLoopRotatePass(pm.llpm);
|
|
|
|
llvm.LLVMAddLICMPass(pm.llpm);
|
|
|
|
llvm.LLVMAddLoopUnswitchPass(pm.llpm);
|
|
|
|
llvm.LLVMAddInstructionCombiningPass(pm.llpm);
|
|
|
|
llvm.LLVMAddIndVarSimplifyPass(pm.llpm);
|
2011-04-12 15:33:39 -04:00
|
|
|
llvm.LLVMAddLoopIdiomPass(pm.llpm);
|
2011-04-07 12:12:21 -04:00
|
|
|
llvm.LLVMAddLoopDeletionPass(pm.llpm);
|
|
|
|
llvm.LLVMAddLoopUnrollPass(pm.llpm);
|
|
|
|
llvm.LLVMAddInstructionCombiningPass(pm.llpm);
|
|
|
|
llvm.LLVMAddGVNPass(pm.llpm);
|
|
|
|
llvm.LLVMAddMemCpyOptPass(pm.llpm);
|
|
|
|
llvm.LLVMAddSCCPPass(pm.llpm);
|
|
|
|
llvm.LLVMAddInstructionCombiningPass(pm.llpm);
|
|
|
|
llvm.LLVMAddJumpThreadingPass(pm.llpm);
|
2011-04-12 15:33:39 -04:00
|
|
|
llvm.LLVMAddCorrelatedValuePropagationPass(pm.llpm);
|
2011-04-07 12:12:21 -04:00
|
|
|
llvm.LLVMAddDeadStoreEliminationPass(pm.llpm);
|
|
|
|
llvm.LLVMAddAggressiveDCEPass(pm.llpm);
|
|
|
|
llvm.LLVMAddCFGSimplificationPass(pm.llpm);
|
|
|
|
llvm.LLVMAddStripDeadPrototypesPass(pm.llpm);
|
|
|
|
llvm.LLVMAddDeadTypeEliminationPass(pm.llpm);
|
|
|
|
llvm.LLVMAddConstantMergePass(pm.llpm);
|
|
|
|
}
|
2011-04-19 18:31:27 -07:00
|
|
|
|
|
|
|
if (verify) {
|
|
|
|
llvm.LLVMAddVerifierPass(pm.llpm);
|
|
|
|
}
|
2011-04-15 17:35:46 -04:00
|
|
|
|
2011-04-18 10:02:34 -04:00
|
|
|
if (is_object_or_assembly(ot)) {
|
|
|
|
let int LLVMAssemblyFile = 0;
|
|
|
|
let int LLVMObjectFile = 1;
|
|
|
|
let int LLVMNullFile = 2;
|
|
|
|
auto FileType;
|
|
|
|
if (ot == output_type_object) {
|
|
|
|
FileType = LLVMObjectFile;
|
|
|
|
} else {
|
|
|
|
FileType = LLVMAssemblyFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm.LLVMRustWriteOutputFile(pm.llpm, llmod,
|
|
|
|
_str.buf(x86.get_target_triple()),
|
|
|
|
_str.buf(output),
|
|
|
|
FileType);
|
2011-04-22 12:01:45 -04:00
|
|
|
llvm.LLVMDisposeModule(llmod);
|
2011-04-15 17:35:46 -04:00
|
|
|
ret;
|
|
|
|
}
|
|
|
|
|
2011-04-07 12:12:21 -04:00
|
|
|
llvm.LLVMRunPassManager(pm.llpm, llmod);
|
2011-04-15 17:35:46 -04:00
|
|
|
|
|
|
|
llvm.LLVMWriteBitcodeToFile(llmod, _str.buf(output));
|
|
|
|
llvm.LLVMDisposeModule(llmod);
|
2010-12-06 17:17:49 -08:00
|
|
|
}
|
|
|
|
|
2011-03-10 17:25:11 -08:00
|
|
|
fn decl_no_op_type_glue(ModuleRef llmod, type_names tn) -> ValueRef {
|
2011-02-17 18:16:51 -08:00
|
|
|
auto ty = T_fn(vec(T_taskptr(tn), T_ptr(T_i8())), T_void());
|
2011-03-10 17:25:11 -08:00
|
|
|
ret decl_fastcall_fn(llmod, abi.no_op_type_glue_name(), ty);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn make_no_op_type_glue(ValueRef fun) {
|
2010-12-17 18:40:04 -08:00
|
|
|
auto bb_name = _str.buf("_rust_no_op_type_glue_bb");
|
|
|
|
auto llbb = llvm.LLVMAppendBasicBlock(fun, bb_name);
|
2010-12-17 18:42:15 -08:00
|
|
|
new_builder(llbb).RetVoid();
|
2010-12-17 18:40:04 -08:00
|
|
|
}
|
|
|
|
|
2011-03-10 17:25:11 -08:00
|
|
|
fn decl_memcpy_glue(ModuleRef llmod) -> ValueRef {
|
2011-01-17 17:24:33 -08:00
|
|
|
auto p8 = T_ptr(T_i8());
|
|
|
|
|
|
|
|
auto ty = T_fn(vec(p8, p8, T_int()), T_void());
|
2011-03-10 17:25:11 -08:00
|
|
|
ret decl_fastcall_fn(llmod, abi.memcpy_glue_name(), ty);
|
|
|
|
}
|
2011-01-17 17:24:33 -08:00
|
|
|
|
2011-03-10 17:25:11 -08:00
|
|
|
fn make_memcpy_glue(ValueRef fun) {
|
|
|
|
// We're not using the LLVM memcpy intrinsic. It appears to call through
|
|
|
|
// to the platform memcpy in some cases, which is not terribly safe to run
|
|
|
|
// on a rust stack.
|
2011-01-17 17:24:33 -08:00
|
|
|
auto initbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("init"));
|
|
|
|
auto hdrbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("hdr"));
|
|
|
|
auto loopbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("loop"));
|
|
|
|
auto endbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("end"));
|
|
|
|
|
|
|
|
auto dst = llvm.LLVMGetParam(fun, 0u);
|
|
|
|
auto src = llvm.LLVMGetParam(fun, 1u);
|
|
|
|
auto count = llvm.LLVMGetParam(fun, 2u);
|
|
|
|
|
|
|
|
// Init block.
|
|
|
|
auto ib = new_builder(initbb);
|
|
|
|
auto ip = ib.Alloca(T_int());
|
|
|
|
ib.Store(C_int(0), ip);
|
|
|
|
ib.Br(hdrbb);
|
|
|
|
|
|
|
|
// Loop-header block
|
|
|
|
auto hb = new_builder(hdrbb);
|
|
|
|
auto i = hb.Load(ip);
|
|
|
|
hb.CondBr(hb.ICmp(lib.llvm.LLVMIntEQ, count, i), endbb, loopbb);
|
|
|
|
|
|
|
|
// Loop-body block
|
|
|
|
auto lb = new_builder(loopbb);
|
|
|
|
i = lb.Load(ip);
|
|
|
|
lb.Store(lb.Load(lb.GEP(src, vec(i))),
|
|
|
|
lb.GEP(dst, vec(i)));
|
|
|
|
lb.Store(lb.Add(i, C_int(1)), ip);
|
|
|
|
lb.Br(hdrbb);
|
|
|
|
|
|
|
|
// End block
|
|
|
|
auto eb = new_builder(endbb);
|
|
|
|
eb.RetVoid();
|
|
|
|
}
|
|
|
|
|
2011-03-10 17:25:11 -08:00
|
|
|
fn decl_bzero_glue(ModuleRef llmod) -> ValueRef {
|
2011-01-18 15:38:35 -08:00
|
|
|
auto p8 = T_ptr(T_i8());
|
|
|
|
|
|
|
|
auto ty = T_fn(vec(p8, T_int()), T_void());
|
2011-03-10 17:25:11 -08:00
|
|
|
ret decl_fastcall_fn(llmod, abi.bzero_glue_name(), ty);
|
|
|
|
}
|
2011-01-18 15:38:35 -08:00
|
|
|
|
2011-03-26 19:14:07 -07:00
|
|
|
fn make_bzero_glue(ValueRef fun) -> ValueRef {
|
2011-03-10 17:25:11 -08:00
|
|
|
// We're not using the LLVM memset intrinsic. Same as with memcpy.
|
2011-01-18 15:38:35 -08:00
|
|
|
auto initbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("init"));
|
|
|
|
auto hdrbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("hdr"));
|
|
|
|
auto loopbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("loop"));
|
|
|
|
auto endbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("end"));
|
|
|
|
|
|
|
|
auto dst = llvm.LLVMGetParam(fun, 0u);
|
|
|
|
auto count = llvm.LLVMGetParam(fun, 1u);
|
|
|
|
|
|
|
|
// Init block.
|
|
|
|
auto ib = new_builder(initbb);
|
|
|
|
auto ip = ib.Alloca(T_int());
|
|
|
|
ib.Store(C_int(0), ip);
|
|
|
|
ib.Br(hdrbb);
|
|
|
|
|
|
|
|
// Loop-header block
|
|
|
|
auto hb = new_builder(hdrbb);
|
|
|
|
auto i = hb.Load(ip);
|
|
|
|
hb.CondBr(hb.ICmp(lib.llvm.LLVMIntEQ, count, i), endbb, loopbb);
|
|
|
|
|
|
|
|
// Loop-body block
|
|
|
|
auto lb = new_builder(loopbb);
|
|
|
|
i = lb.Load(ip);
|
|
|
|
lb.Store(C_integral(0, T_i8()), lb.GEP(dst, vec(i)));
|
|
|
|
lb.Store(lb.Add(i, C_int(1)), ip);
|
|
|
|
lb.Br(hdrbb);
|
|
|
|
|
|
|
|
// End block
|
|
|
|
auto eb = new_builder(endbb);
|
|
|
|
eb.RetVoid();
|
|
|
|
ret fun;
|
|
|
|
}
|
|
|
|
|
2011-03-03 18:18:51 -08:00
|
|
|
fn make_vec_append_glue(ModuleRef llmod, type_names tn) -> ValueRef {
|
2011-03-02 16:42:09 -08:00
|
|
|
/*
|
2011-03-03 18:18:51 -08:00
|
|
|
* Args to vec_append_glue:
|
2011-03-02 16:42:09 -08:00
|
|
|
*
|
|
|
|
* 0. (Implicit) task ptr
|
|
|
|
*
|
|
|
|
* 1. Pointer to the tydesc of the vec, so that we can tell if it's gc
|
|
|
|
* mem, and have a tydesc to pass to malloc if we're allocating anew.
|
|
|
|
*
|
|
|
|
* 2. Pointer to the tydesc of the vec's stored element type, so that
|
|
|
|
* elements can be copied to a newly alloc'ed vec if one must be
|
|
|
|
* created.
|
|
|
|
*
|
2011-03-06 12:46:33 -08:00
|
|
|
* 3. Dst vec ptr (i.e. ptr to ptr to rust_vec).
|
2011-03-03 18:18:51 -08:00
|
|
|
*
|
|
|
|
* 4. Src vec (i.e. ptr to rust_vec).
|
2011-03-02 16:42:09 -08:00
|
|
|
*
|
2011-03-03 18:18:51 -08:00
|
|
|
* 5. Flag indicating whether to skip trailing null on dst.
|
2011-03-02 16:42:09 -08:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
auto ty = T_fn(vec(T_taskptr(tn),
|
|
|
|
T_ptr(T_tydesc(tn)),
|
|
|
|
T_ptr(T_tydesc(tn)),
|
2011-03-06 12:46:33 -08:00
|
|
|
T_ptr(T_opaque_vec_ptr()),
|
|
|
|
T_opaque_vec_ptr(), T_bool()),
|
|
|
|
T_void());
|
2011-03-02 16:42:09 -08:00
|
|
|
|
2011-03-03 18:18:51 -08:00
|
|
|
auto llfn = decl_fastcall_fn(llmod, abi.vec_append_glue_name(), ty);
|
2011-03-02 16:42:09 -08:00
|
|
|
ret llfn;
|
|
|
|
}
|
|
|
|
|
2011-03-09 20:14:19 -08:00
|
|
|
|
|
|
|
fn vec_fill(@block_ctxt bcx, ValueRef v) -> ValueRef {
|
|
|
|
ret bcx.build.Load(bcx.build.GEP(v, vec(C_int(0),
|
|
|
|
C_int(abi.vec_elt_fill))));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn put_vec_fill(@block_ctxt bcx, ValueRef v, ValueRef fill) -> ValueRef {
|
|
|
|
ret bcx.build.Store(fill,
|
|
|
|
bcx.build.GEP(v,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.vec_elt_fill))));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn vec_fill_adjusted(@block_ctxt bcx, ValueRef v,
|
|
|
|
ValueRef skipnull) -> ValueRef {
|
|
|
|
auto f = bcx.build.Load(bcx.build.GEP(v,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.vec_elt_fill))));
|
|
|
|
ret bcx.build.Select(skipnull, bcx.build.Sub(f, C_int(1)), f);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn vec_p0(@block_ctxt bcx, ValueRef v) -> ValueRef {
|
|
|
|
auto p = bcx.build.GEP(v, vec(C_int(0),
|
|
|
|
C_int(abi.vec_elt_data)));
|
|
|
|
ret bcx.build.PointerCast(p, T_ptr(T_i8()));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn vec_p1(@block_ctxt bcx, ValueRef v) -> ValueRef {
|
|
|
|
auto len = vec_fill(bcx, v);
|
|
|
|
ret bcx.build.GEP(vec_p0(bcx, v), vec(len));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn vec_p1_adjusted(@block_ctxt bcx, ValueRef v,
|
|
|
|
ValueRef skipnull) -> ValueRef {
|
|
|
|
auto len = vec_fill_adjusted(bcx, v, skipnull);
|
|
|
|
ret bcx.build.GEP(vec_p0(bcx, v), vec(len));
|
|
|
|
}
|
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
fn trans_vec_append_glue(@local_ctxt cx) {
|
2011-03-02 16:42:09 -08:00
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
auto llfn = cx.ccx.glues.vec_append_glue;
|
2011-03-02 16:42:09 -08:00
|
|
|
|
|
|
|
let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 0u);
|
|
|
|
let ValueRef llvec_tydesc = llvm.LLVMGetParam(llfn, 1u);
|
|
|
|
let ValueRef llelt_tydesc = llvm.LLVMGetParam(llfn, 2u);
|
2011-03-03 18:18:51 -08:00
|
|
|
let ValueRef lldst_vec_ptr = llvm.LLVMGetParam(llfn, 3u);
|
|
|
|
let ValueRef llsrc_vec = llvm.LLVMGetParam(llfn, 4u);
|
|
|
|
let ValueRef llskipnull = llvm.LLVMGetParam(llfn, 5u);
|
2011-03-02 16:42:09 -08:00
|
|
|
|
2011-03-28 18:04:52 -07:00
|
|
|
let BasicBlockRef llallocas =
|
|
|
|
llvm.LLVMAppendBasicBlock(llfn, _str.buf("allocas"));
|
|
|
|
|
2011-03-02 16:42:09 -08:00
|
|
|
auto fcx = @rec(llfn=llfn,
|
|
|
|
lltaskptr=lltaskptr,
|
|
|
|
llenv=C_null(T_ptr(T_nil())),
|
|
|
|
llretptr=C_null(T_ptr(T_nil())),
|
2011-03-28 18:04:52 -07:00
|
|
|
mutable llallocas = llallocas,
|
2011-04-05 14:18:44 -07:00
|
|
|
mutable llself=none[self_vt],
|
2011-03-02 16:42:09 -08:00
|
|
|
mutable lliterbody=none[ValueRef],
|
|
|
|
llargs=new_def_hash[ValueRef](),
|
|
|
|
llobjfields=new_def_hash[ValueRef](),
|
|
|
|
lllocals=new_def_hash[ValueRef](),
|
2011-03-10 16:49:00 -08:00
|
|
|
llupvars=new_def_hash[ValueRef](),
|
2011-04-15 17:45:37 -07:00
|
|
|
mutable lltydescs=_vec.empty[ValueRef](),
|
2011-04-17 14:24:45 +02:00
|
|
|
lcx=cx);
|
2011-03-02 16:42:09 -08:00
|
|
|
|
|
|
|
auto bcx = new_top_block_ctxt(fcx);
|
2011-03-28 18:04:52 -07:00
|
|
|
auto lltop = bcx.llbb;
|
2011-03-02 16:42:09 -08:00
|
|
|
|
2011-03-06 22:37:14 -08:00
|
|
|
auto lldst_vec = bcx.build.Load(lldst_vec_ptr);
|
|
|
|
|
2011-03-03 18:18:51 -08:00
|
|
|
// First the dst vec needs to grow to accommodate the src vec.
|
|
|
|
// To do this we have to figure out how many bytes to add.
|
2011-03-02 16:42:09 -08:00
|
|
|
|
2011-03-28 18:04:52 -07:00
|
|
|
auto llcopy_dst_ptr = alloca(bcx, T_int());
|
2011-03-02 16:42:09 -08:00
|
|
|
auto llnew_vec_res =
|
|
|
|
trans_upcall(bcx, "upcall_vec_grow",
|
2011-03-06 22:37:14 -08:00
|
|
|
vec(vp2i(bcx, lldst_vec),
|
|
|
|
vec_fill_adjusted(bcx, llsrc_vec, llskipnull),
|
|
|
|
vp2i(bcx, llcopy_dst_ptr),
|
2011-03-02 16:42:09 -08:00
|
|
|
vp2i(bcx, llvec_tydesc)));
|
|
|
|
|
|
|
|
bcx = llnew_vec_res.bcx;
|
2011-03-06 12:46:33 -08:00
|
|
|
auto llnew_vec = vi2p(bcx, llnew_vec_res.val,
|
|
|
|
T_opaque_vec_ptr());
|
2011-03-02 16:42:09 -08:00
|
|
|
|
2011-03-06 22:37:14 -08:00
|
|
|
put_vec_fill(bcx, llnew_vec, C_int(0));
|
2011-03-03 18:18:51 -08:00
|
|
|
|
2011-03-06 22:37:14 -08:00
|
|
|
auto copy_dst_cx = new_sub_block_ctxt(bcx, "copy new <- dst");
|
|
|
|
auto copy_src_cx = new_sub_block_ctxt(bcx, "copy new <- src");
|
2011-03-02 16:42:09 -08:00
|
|
|
|
2011-03-28 18:04:52 -07:00
|
|
|
auto pp0 = alloca(bcx, T_ptr(T_i8()));
|
2011-03-06 22:37:14 -08:00
|
|
|
bcx.build.Store(vec_p0(bcx, llnew_vec), pp0);
|
|
|
|
|
|
|
|
bcx.build.CondBr(bcx.build.TruncOrBitCast
|
|
|
|
(bcx.build.Load(llcopy_dst_ptr),
|
|
|
|
T_i1()),
|
|
|
|
copy_dst_cx.llbb,
|
|
|
|
copy_src_cx.llbb);
|
|
|
|
|
|
|
|
|
|
|
|
fn copy_elts(@block_ctxt cx,
|
|
|
|
ValueRef elt_tydesc,
|
|
|
|
ValueRef dst,
|
|
|
|
ValueRef src,
|
|
|
|
ValueRef n_bytes) -> result {
|
|
|
|
|
|
|
|
auto src_lim = cx.build.GEP(src, vec(n_bytes));
|
|
|
|
|
|
|
|
auto elt_llsz =
|
|
|
|
cx.build.Load(cx.build.GEP(elt_tydesc,
|
|
|
|
vec(C_int(0),
|
|
|
|
C_int(abi.tydesc_field_size))));
|
|
|
|
|
|
|
|
fn take_one(ValueRef elt_tydesc,
|
2011-03-09 20:14:19 -08:00
|
|
|
@block_ctxt cx,
|
|
|
|
ValueRef dst, ValueRef src) -> result {
|
|
|
|
call_tydesc_glue_full(cx, src,
|
2011-03-06 22:37:14 -08:00
|
|
|
elt_tydesc,
|
2011-04-09 00:54:46 +00:00
|
|
|
abi.tydesc_field_take_glue);
|
2011-03-09 20:14:19 -08:00
|
|
|
ret res(cx, src);
|
2011-03-06 22:37:14 -08:00
|
|
|
}
|
|
|
|
|
2011-03-09 20:14:19 -08:00
|
|
|
auto bcx = iter_sequence_raw(cx, dst, src, src_lim,
|
2011-03-06 22:37:14 -08:00
|
|
|
elt_llsz, bind take_one(elt_tydesc,
|
2011-03-09 20:14:19 -08:00
|
|
|
_, _, _)).bcx;
|
2011-03-06 22:37:14 -08:00
|
|
|
|
|
|
|
ret call_memcpy(bcx, dst, src, n_bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy any dst elements in, omitting null if doing str.
|
|
|
|
auto n_bytes = vec_fill_adjusted(copy_dst_cx, lldst_vec, llskipnull);
|
|
|
|
copy_dst_cx = copy_elts(copy_dst_cx,
|
|
|
|
llelt_tydesc,
|
|
|
|
copy_dst_cx.build.Load(pp0),
|
|
|
|
vec_p0(copy_dst_cx, lldst_vec),
|
|
|
|
n_bytes).bcx;
|
|
|
|
|
|
|
|
put_vec_fill(copy_dst_cx, llnew_vec, n_bytes);
|
2011-03-06 23:06:01 -08:00
|
|
|
copy_dst_cx.build.Store(vec_p1(copy_dst_cx, llnew_vec), pp0);
|
2011-03-06 22:37:14 -08:00
|
|
|
copy_dst_cx.build.Br(copy_src_cx.llbb);
|
|
|
|
|
|
|
|
|
|
|
|
// Copy any src elements in, carrying along null if doing str.
|
|
|
|
n_bytes = vec_fill(copy_src_cx, llsrc_vec);
|
|
|
|
copy_src_cx = copy_elts(copy_src_cx,
|
|
|
|
llelt_tydesc,
|
|
|
|
copy_src_cx.build.Load(pp0),
|
|
|
|
vec_p0(copy_src_cx, llsrc_vec),
|
|
|
|
n_bytes).bcx;
|
|
|
|
|
|
|
|
put_vec_fill(copy_src_cx, llnew_vec,
|
|
|
|
copy_src_cx.build.Add(vec_fill(copy_src_cx,
|
|
|
|
llnew_vec),
|
2011-04-01 16:04:22 -07:00
|
|
|
n_bytes));
|
2011-03-06 22:37:14 -08:00
|
|
|
|
|
|
|
// Write new_vec back through the alias we were given.
|
|
|
|
copy_src_cx.build.Store(llnew_vec, lldst_vec_ptr);
|
|
|
|
copy_src_cx.build.RetVoid();
|
2011-03-28 18:04:52 -07:00
|
|
|
|
|
|
|
// Tie up the llallocas -> lltop edge.
|
|
|
|
new_builder(fcx.llallocas).Br(lltop);
|
2011-03-02 16:42:09 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-17 18:16:51 -08:00
|
|
|
fn make_glues(ModuleRef llmod, type_names tn) -> @glue_fns {
|
|
|
|
ret @rec(activate_glue = decl_glue(llmod, tn, abi.activate_glue_name()),
|
|
|
|
yield_glue = decl_glue(llmod, tn, abi.yield_glue_name()),
|
2010-12-17 18:40:04 -08:00
|
|
|
/*
|
|
|
|
* Note: the signature passed to decl_cdecl_fn here looks unusual
|
2011-03-25 15:48:00 -07:00
|
|
|
* because it is. It corresponds neither to a native signature
|
2010-12-17 18:40:04 -08:00
|
|
|
* nor a normal rust-ABI signature. In fact it is a fake
|
|
|
|
* signature, that exists solely to acquire the task pointer as
|
|
|
|
* an argument to the upcall. It so happens that the runtime sets
|
|
|
|
* up the task pointer as the sole incoming argument to the frame
|
|
|
|
* that we return into when returning to the exit task glue. So
|
|
|
|
* this is the signature required to retrieve it.
|
|
|
|
*/
|
|
|
|
exit_task_glue = decl_cdecl_fn(llmod, abi.exit_task_glue_name(),
|
2011-02-22 16:37:01 -08:00
|
|
|
T_fn(vec(T_int(),
|
2011-03-30 13:04:18 -07:00
|
|
|
T_int(),
|
2011-02-22 16:37:01 -08:00
|
|
|
T_int(),
|
|
|
|
T_int(),
|
|
|
|
T_taskptr(tn)),
|
2011-02-17 18:16:51 -08:00
|
|
|
T_void())),
|
2010-12-17 18:40:04 -08:00
|
|
|
|
2011-03-25 15:48:00 -07:00
|
|
|
native_glues_rust =
|
|
|
|
_vec.init_fn[ValueRef](bind decl_native_glue(llmod, tn, true,
|
2011-03-21 17:47:38 -04:00
|
|
|
_),
|
2011-03-25 15:48:00 -07:00
|
|
|
abi.n_native_glues + 1 as uint),
|
|
|
|
native_glues_cdecl =
|
|
|
|
_vec.init_fn[ValueRef](bind decl_native_glue(llmod, tn, false,
|
2011-03-21 17:47:38 -04:00
|
|
|
_),
|
2011-03-25 15:48:00 -07:00
|
|
|
abi.n_native_glues + 1 as uint),
|
2011-03-10 17:25:11 -08:00
|
|
|
no_op_type_glue = decl_no_op_type_glue(llmod, tn),
|
|
|
|
memcpy_glue = decl_memcpy_glue(llmod),
|
|
|
|
bzero_glue = decl_bzero_glue(llmod),
|
2011-03-03 18:18:51 -08:00
|
|
|
vec_append_glue = make_vec_append_glue(llmod, tn));
|
2010-12-17 18:40:04 -08:00
|
|
|
}
|
|
|
|
|
2011-04-19 18:31:27 -07:00
|
|
|
fn make_common_glue(str output, bool optimize, bool verify,
|
2011-04-15 17:35:46 -04:00
|
|
|
output_type ot) {
|
2011-03-10 17:25:11 -08:00
|
|
|
// FIXME: part of this is repetitive and is probably a good idea
|
|
|
|
// to autogen it, but things like the memcpy implementation are not
|
|
|
|
// and it might be better to just check in a .ll file.
|
2010-09-22 15:21:06 -07:00
|
|
|
auto llmod =
|
|
|
|
llvm.LLVMModuleCreateWithNameInContext(_str.buf("rust_out"),
|
|
|
|
llvm.LLVMGetGlobalContext());
|
|
|
|
|
2010-12-03 13:51:46 -08:00
|
|
|
llvm.LLVMSetDataLayout(llmod, _str.buf(x86.get_data_layout()));
|
|
|
|
llvm.LLVMSetTarget(llmod, _str.buf(x86.get_target_triple()));
|
2010-12-03 16:55:59 -08:00
|
|
|
auto td = mk_target_data(x86.get_data_layout());
|
2011-02-17 18:16:51 -08:00
|
|
|
auto tn = mk_type_names();
|
2011-04-18 16:18:55 +02:00
|
|
|
let ValueRef crate_ptr =
|
|
|
|
llvm.LLVMAddGlobal(llmod, T_crate(tn), _str.buf("rust_crate"));
|
2011-03-08 13:20:16 -08:00
|
|
|
|
2011-03-10 17:25:11 -08:00
|
|
|
auto intrinsics = declare_intrinsics(llmod);
|
|
|
|
|
2011-03-08 13:20:16 -08:00
|
|
|
llvm.LLVMSetModuleInlineAsm(llmod, _str.buf(x86.get_module_asm()));
|
2010-09-23 15:46:31 -07:00
|
|
|
|
2011-03-10 17:25:11 -08:00
|
|
|
auto glues = make_glues(llmod, tn);
|
2011-04-18 16:18:55 +02:00
|
|
|
create_crate_constant(crate_ptr, glues);
|
2011-03-10 17:25:11 -08:00
|
|
|
make_memcpy_glue(glues.memcpy_glue);
|
2011-03-26 19:14:07 -07:00
|
|
|
make_bzero_glue(glues.bzero_glue);
|
2011-03-10 17:25:11 -08:00
|
|
|
|
|
|
|
trans_exit_task_glue(glues, new_str_hash[ValueRef](), tn, llmod);
|
|
|
|
|
2011-04-19 18:31:27 -07:00
|
|
|
run_passes(llmod, optimize, verify, output, ot);
|
2011-03-10 17:25:11 -08:00
|
|
|
}
|
|
|
|
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
fn create_module_map(@crate_ctxt ccx) -> ValueRef {
|
|
|
|
auto elttype = T_struct(vec(T_int(), T_int()));
|
|
|
|
auto maptype = T_array(elttype, ccx.module_data.size() + 1u);
|
|
|
|
auto map = llvm.LLVMAddGlobal(ccx.llmod, maptype,
|
|
|
|
_str.buf("_rust_mod_map"));
|
|
|
|
llvm.LLVMSetLinkage(map, lib.llvm.LLVMInternalLinkage as llvm.Linkage);
|
|
|
|
let vec[ValueRef] elts = vec();
|
|
|
|
for each (@tup(str, ValueRef) item in ccx.module_data.items()) {
|
|
|
|
auto elt = C_struct(vec(p2i(C_cstr(ccx, item._0)), p2i(item._1)));
|
|
|
|
_vec.push[ValueRef](elts, elt);
|
|
|
|
}
|
|
|
|
auto term = C_struct(vec(C_int(0), C_int(0)));
|
|
|
|
_vec.push[ValueRef](elts, term);
|
|
|
|
llvm.LLVMSetInitializer(map, C_array(elttype, elts));
|
|
|
|
ret map;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn crate_name(@crate_ctxt ccx, str deflt) -> str {
|
|
|
|
for (@ast.meta_item item in ccx.sess.get_metadata()) {
|
|
|
|
if (_str.eq(item.node.name, "name")) {
|
|
|
|
ret item.node.value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret deflt;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME use hashed metadata instead of crate names once we have that
|
|
|
|
fn create_crate_map(@crate_ctxt ccx) -> ValueRef {
|
|
|
|
let vec[ValueRef] subcrates = vec();
|
|
|
|
auto i = 1;
|
|
|
|
while (ccx.sess.has_external_crate(i)) {
|
|
|
|
auto name = ccx.sess.get_external_crate(i).name;
|
|
|
|
auto cr = llvm.LLVMAddGlobal(ccx.llmod, T_int(),
|
|
|
|
_str.buf("_rust_crate_map_" + name));
|
|
|
|
_vec.push[ValueRef](subcrates, p2i(cr));
|
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
_vec.push[ValueRef](subcrates, C_int(0));
|
|
|
|
auto sym_name = "_rust_crate_map_" + crate_name(ccx, "__none__");
|
|
|
|
auto arrtype = T_array(T_int(), _vec.len[ValueRef](subcrates));
|
|
|
|
auto maptype = T_struct(vec(T_int(), arrtype));
|
|
|
|
auto map = llvm.LLVMAddGlobal(ccx.llmod, maptype, _str.buf(sym_name));
|
|
|
|
llvm.LLVMSetLinkage(map, lib.llvm.LLVMExternalLinkage as llvm.Linkage);
|
|
|
|
llvm.LLVMSetInitializer(map, C_struct(vec(p2i(create_module_map(ccx)),
|
|
|
|
C_array(T_int(), subcrates))));
|
|
|
|
ret map;
|
|
|
|
}
|
|
|
|
|
2011-04-20 18:52:04 -07:00
|
|
|
fn trans_crate(session.session sess, @ast.crate crate, @ty.type_store tystore,
|
2011-04-07 15:42:06 -04:00
|
|
|
&ty.type_cache type_cache, str output, bool shared,
|
2011-04-19 18:31:27 -07:00
|
|
|
bool optimize, bool verify, output_type ot) {
|
2011-03-10 17:25:11 -08:00
|
|
|
auto llmod =
|
|
|
|
llvm.LLVMModuleCreateWithNameInContext(_str.buf("rust_out"),
|
|
|
|
llvm.LLVMGetGlobalContext());
|
|
|
|
|
|
|
|
llvm.LLVMSetDataLayout(llmod, _str.buf(x86.get_data_layout()));
|
|
|
|
llvm.LLVMSetTarget(llmod, _str.buf(x86.get_target_triple()));
|
|
|
|
auto td = mk_target_data(x86.get_data_layout());
|
|
|
|
auto tn = mk_type_names();
|
|
|
|
let ValueRef crate_ptr =
|
|
|
|
llvm.LLVMAddGlobal(llmod, T_crate(tn), _str.buf("rust_crate"));
|
|
|
|
|
2010-11-25 17:45:26 -08:00
|
|
|
auto intrinsics = declare_intrinsics(llmod);
|
2010-11-14 11:21:49 -08:00
|
|
|
|
2011-02-17 18:16:51 -08:00
|
|
|
auto glues = make_glues(llmod, tn);
|
2010-12-21 12:13:51 -08:00
|
|
|
auto hasher = ty.hash_ty;
|
|
|
|
auto eqer = ty.eq_ty;
|
2011-04-22 12:27:28 -07:00
|
|
|
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);
|
2010-12-10 15:02:23 -08:00
|
|
|
|
2011-04-17 14:24:45 +02:00
|
|
|
auto ccx = @rec(sess = sess,
|
|
|
|
llmod = llmod,
|
|
|
|
td = td,
|
|
|
|
tn = tn,
|
|
|
|
crate_ptr = crate_ptr,
|
|
|
|
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](),
|
|
|
|
type_cache = type_cache,
|
|
|
|
item_symbols = new_def_hash[str](),
|
|
|
|
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,
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
module_data = new_str_hash[ValueRef](),
|
2011-04-19 16:40:46 -07:00
|
|
|
lltypes = lltypes,
|
2011-04-17 14:24:45 +02:00
|
|
|
glues = glues,
|
|
|
|
names = namegen(0),
|
2011-04-20 18:52:04 -07:00
|
|
|
sha = std.sha1.mk_sha1(),
|
|
|
|
tystore = tystore);
|
2011-04-20 17:23:45 +02:00
|
|
|
auto cx = new_local_ctxt(ccx);
|
2010-09-23 18:38:37 -07:00
|
|
|
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
create_typedefs(ccx);
|
2010-12-10 16:29:41 -08:00
|
|
|
|
2011-04-20 17:23:45 +02:00
|
|
|
collect_items(ccx, crate);
|
2011-04-20 17:43:13 +02:00
|
|
|
collect_tag_ctors(ccx, crate);
|
|
|
|
trans_constants(ccx, crate);
|
2010-10-05 18:21:44 -07:00
|
|
|
trans_mod(cx, crate.node.module);
|
2011-03-03 18:18:51 -08:00
|
|
|
trans_vec_append_glue(cx);
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
auto crate_map = create_crate_map(ccx);
|
2010-12-29 11:21:16 -05:00
|
|
|
if (!shared) {
|
2011-04-18 16:18:55 +02:00
|
|
|
trans_main_fn(cx, crate_ptr, crate_map);
|
2010-12-29 11:21:16 -05:00
|
|
|
}
|
2010-09-27 13:43:53 -07:00
|
|
|
|
2011-03-11 15:35:20 -08:00
|
|
|
// Translate the metadata.
|
2011-04-17 14:24:45 +02:00
|
|
|
middle.metadata.write_metadata(cx.ccx, crate);
|
2011-03-11 15:35:20 -08:00
|
|
|
|
2011-04-19 18:31:27 -07:00
|
|
|
run_passes(llmod, optimize, verify, output, ot);
|
2010-09-22 15:21:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Local Variables:
|
|
|
|
// mode: rust
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
2011-03-25 15:07:27 -07:00
|
|
|
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
2010-09-22 15:21:06 -07:00
|
|
|
// End:
|
|
|
|
//
|