refactor: Move the LLVM type and constant constructors into a new module.
This commit is contained in:
parent
e2fcd29bbd
commit
8afb1a7c63
@ -1,22 +1,22 @@
|
||||
|
||||
import middle::trans;
|
||||
import trans::decl_cdecl_fn;
|
||||
import trans::T_f32;
|
||||
import trans::T_f64;
|
||||
import trans::T_fn;
|
||||
import trans::T_bool;
|
||||
import trans::T_i8;
|
||||
import trans::T_i32;
|
||||
import trans::T_int;
|
||||
import trans::T_nil;
|
||||
import trans::T_opaque_chan_ptr;
|
||||
import trans::T_opaque_ivec;
|
||||
import trans::T_opaque_port_ptr;
|
||||
import trans::T_opaque_vec_ptr;
|
||||
import trans::T_ptr;
|
||||
import trans::T_size_t;
|
||||
import trans::T_str;
|
||||
import trans::T_void;
|
||||
import middle::trans_common::T_f32;
|
||||
import middle::trans_common::T_f64;
|
||||
import middle::trans_common::T_fn;
|
||||
import middle::trans_common::T_bool;
|
||||
import middle::trans_common::T_i8;
|
||||
import middle::trans_common::T_i32;
|
||||
import middle::trans_common::T_int;
|
||||
import middle::trans_common::T_nil;
|
||||
import middle::trans_common::T_opaque_chan_ptr;
|
||||
import middle::trans_common::T_opaque_ivec;
|
||||
import middle::trans_common::T_opaque_port_ptr;
|
||||
import middle::trans_common::T_opaque_vec_ptr;
|
||||
import middle::trans_common::T_ptr;
|
||||
import middle::trans_common::T_size_t;
|
||||
import middle::trans_common::T_str;
|
||||
import middle::trans_common::T_void;
|
||||
import lib::llvm::type_names;
|
||||
import lib::llvm::llvm::ModuleRef;
|
||||
import lib::llvm::llvm::ValueRef;
|
||||
|
@ -65,6 +65,8 @@ import util::ppaux::ty_to_short_str;
|
||||
import syntax::print::pprust::expr_to_str;
|
||||
import syntax::print::pprust::path_to_str;
|
||||
|
||||
import trans_common::*;
|
||||
|
||||
obj namegen(mutable int i) {
|
||||
fn next(str prefix) -> str { i += 1; ret prefix + int::str(i); }
|
||||
}
|
||||
@ -399,330 +401,6 @@ fn struct_elt(TypeRef llstructty, uint n) -> TypeRef {
|
||||
}
|
||||
|
||||
|
||||
// LLVM type constructors.
|
||||
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.
|
||||
|
||||
ret llvm::LLVMVoidType();
|
||||
}
|
||||
|
||||
fn T_nil() -> TypeRef {
|
||||
// NB: See above in T_void().
|
||||
|
||||
ret llvm::LLVMInt1Type();
|
||||
}
|
||||
|
||||
fn T_i1() -> TypeRef { ret llvm::LLVMInt1Type(); }
|
||||
|
||||
fn T_i8() -> TypeRef { ret llvm::LLVMInt8Type(); }
|
||||
|
||||
fn T_i16() -> TypeRef { ret llvm::LLVMInt16Type(); }
|
||||
|
||||
fn T_i32() -> TypeRef { ret llvm::LLVMInt32Type(); }
|
||||
|
||||
fn T_i64() -> TypeRef { ret llvm::LLVMInt64Type(); }
|
||||
|
||||
fn T_f32() -> TypeRef { ret llvm::LLVMFloatType(); }
|
||||
|
||||
fn T_f64() -> TypeRef { ret llvm::LLVMDoubleType(); }
|
||||
|
||||
fn T_bool() -> TypeRef { ret T_i1(); }
|
||||
|
||||
fn T_int() -> TypeRef {
|
||||
// FIXME: switch on target type.
|
||||
|
||||
ret T_i32();
|
||||
}
|
||||
|
||||
fn T_float() -> TypeRef {
|
||||
// FIXME: switch on target type.
|
||||
|
||||
ret T_f64();
|
||||
}
|
||||
|
||||
fn T_char() -> TypeRef { ret T_i32(); }
|
||||
|
||||
fn T_size_t() -> TypeRef {
|
||||
// FIXME: switch on target type.
|
||||
|
||||
ret T_i32();
|
||||
}
|
||||
|
||||
fn T_fn(&TypeRef[] inputs, TypeRef output) -> TypeRef {
|
||||
ret llvm::LLVMFunctionType(output, std::ivec::to_ptr(inputs),
|
||||
std::ivec::len[TypeRef](inputs), False);
|
||||
}
|
||||
|
||||
fn T_fn_pair(&crate_ctxt cx, TypeRef tfn) -> TypeRef {
|
||||
ret T_struct(~[T_ptr(tfn), T_opaque_closure_ptr(cx)]);
|
||||
}
|
||||
|
||||
fn T_ptr(TypeRef t) -> TypeRef { ret llvm::LLVMPointerType(t, 0u); }
|
||||
|
||||
fn T_struct(&TypeRef[] elts) -> TypeRef {
|
||||
ret llvm::LLVMStructType(std::ivec::to_ptr(elts), std::ivec::len(elts),
|
||||
False);
|
||||
}
|
||||
|
||||
fn T_named_struct(&str name) -> TypeRef {
|
||||
auto c = llvm::LLVMGetGlobalContext();
|
||||
ret llvm::LLVMStructCreateNamed(c, str::buf(name));
|
||||
}
|
||||
|
||||
fn set_struct_body(TypeRef t, &TypeRef[] elts) {
|
||||
llvm::LLVMStructSetBody(t, std::ivec::to_ptr(elts), std::ivec::len(elts),
|
||||
False);
|
||||
}
|
||||
|
||||
fn T_empty_struct() -> TypeRef { ret T_struct(~[]); }
|
||||
|
||||
fn T_rust_object() -> TypeRef {
|
||||
auto t = T_named_struct("rust_object");
|
||||
auto e = T_ptr(T_empty_struct());
|
||||
set_struct_body(t, ~[e,e]);
|
||||
ret t;
|
||||
}
|
||||
|
||||
fn T_task() -> TypeRef {
|
||||
auto t = T_named_struct("task");
|
||||
|
||||
auto elems = ~[T_int(), // Refcount
|
||||
T_int(), // Delegate pointer
|
||||
T_int(), // Stack segment pointer
|
||||
T_int(), // Runtime SP
|
||||
T_int(), // Rust SP
|
||||
T_int(), // GC chain
|
||||
|
||||
T_int(), // Domain pointer
|
||||
// Crate cache pointer
|
||||
T_int()];
|
||||
set_struct_body(t, elems);
|
||||
ret t;
|
||||
}
|
||||
|
||||
fn T_tydesc_field(&crate_ctxt cx, int field) -> TypeRef {
|
||||
// Bit of a kludge: pick the fn typeref out of the tydesc..
|
||||
|
||||
let TypeRef[] tydesc_elts =
|
||||
std::ivec::init_elt[TypeRef](T_nil(), abi::n_tydesc_fields as uint);
|
||||
llvm::LLVMGetStructElementTypes(cx.tydesc_type,
|
||||
std::ivec::to_ptr[TypeRef](tydesc_elts));
|
||||
auto t = llvm::LLVMGetElementType(tydesc_elts.(field));
|
||||
ret t;
|
||||
}
|
||||
|
||||
fn T_glue_fn(&crate_ctxt cx) -> TypeRef {
|
||||
auto s = "glue_fn";
|
||||
if (cx.tn.name_has_type(s)) { ret cx.tn.get_type(s); }
|
||||
auto t = T_tydesc_field(cx, abi::tydesc_field_drop_glue);
|
||||
cx.tn.associate(s, t);
|
||||
ret t;
|
||||
}
|
||||
|
||||
fn T_dtor(&@crate_ctxt ccx, &span sp) -> TypeRef {
|
||||
ret type_of_fn_full(ccx, sp, ast::proto_fn, true,
|
||||
~[], ty::mk_nil(ccx.tcx), 0u);
|
||||
}
|
||||
|
||||
fn T_cmp_glue_fn(&crate_ctxt cx) -> TypeRef {
|
||||
auto s = "cmp_glue_fn";
|
||||
if (cx.tn.name_has_type(s)) { ret cx.tn.get_type(s); }
|
||||
auto t = T_tydesc_field(cx, abi::tydesc_field_cmp_glue);
|
||||
cx.tn.associate(s, t);
|
||||
ret t;
|
||||
}
|
||||
|
||||
fn T_tydesc(TypeRef taskptr_type) -> TypeRef {
|
||||
auto tydesc = T_named_struct("tydesc");
|
||||
auto tydescpp = T_ptr(T_ptr(tydesc));
|
||||
auto pvoid = T_ptr(T_i8());
|
||||
auto glue_fn_ty =
|
||||
T_ptr(T_fn(~[T_ptr(T_nil()), taskptr_type, T_ptr(T_nil()), tydescpp,
|
||||
pvoid], T_void()));
|
||||
auto cmp_glue_fn_ty =
|
||||
T_ptr(T_fn(~[T_ptr(T_i1()), taskptr_type, T_ptr(T_nil()), tydescpp,
|
||||
pvoid, pvoid, T_i8()], T_void()));
|
||||
|
||||
auto elems = ~[tydescpp, // first_param
|
||||
T_int(), // size
|
||||
T_int(), // align
|
||||
glue_fn_ty, // copy_glue
|
||||
glue_fn_ty, // drop_glue
|
||||
glue_fn_ty, // free_glue
|
||||
glue_fn_ty, // sever_glue
|
||||
glue_fn_ty, // mark_glue
|
||||
glue_fn_ty, // obj_drop_glue
|
||||
glue_fn_ty, // is_stateful
|
||||
cmp_glue_fn_ty];
|
||||
set_struct_body(tydesc, elems);
|
||||
ret tydesc;
|
||||
}
|
||||
|
||||
fn T_array(TypeRef t, uint n) -> TypeRef { ret llvm::LLVMArrayType(t, n); }
|
||||
|
||||
fn T_vec(TypeRef t) -> TypeRef {
|
||||
ret T_struct(~[T_int(), // Refcount
|
||||
T_int(), // Alloc
|
||||
T_int(), // Fill
|
||||
|
||||
T_int(), // Pad
|
||||
// Body elements
|
||||
T_array(t, 0u)]);
|
||||
}
|
||||
|
||||
fn T_opaque_vec_ptr() -> TypeRef { ret T_ptr(T_vec(T_int())); }
|
||||
|
||||
|
||||
// Interior vector.
|
||||
//
|
||||
// TODO: Support user-defined vector sizes.
|
||||
fn T_ivec(TypeRef t) -> TypeRef {
|
||||
ret T_struct(~[T_int(), // Length ("fill"; if zero, heapified)
|
||||
T_int(), // Alloc
|
||||
T_array(t, abi::ivec_default_length)]); // Body elements
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Note that the size of this one is in bytes.
|
||||
fn T_opaque_ivec() -> TypeRef {
|
||||
ret T_struct(~[T_int(), // Length ("fill"; if zero, heapified)
|
||||
T_int(), // Alloc
|
||||
T_array(T_i8(), 0u)]); // Body elements
|
||||
|
||||
}
|
||||
|
||||
fn T_ivec_heap_part(TypeRef t) -> TypeRef {
|
||||
ret T_struct(~[T_int(), // Real length
|
||||
T_array(t, 0u)]); // Body elements
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Interior vector on the heap, also known as the "stub". Cast to this when
|
||||
// the allocated length (second element of T_ivec above) is zero.
|
||||
fn T_ivec_heap(TypeRef t) -> TypeRef {
|
||||
ret T_struct(~[T_int(), // Length (zero)
|
||||
T_int(), // Alloc
|
||||
T_ptr(T_ivec_heap_part(t))]); // Pointer
|
||||
|
||||
}
|
||||
|
||||
fn T_opaque_ivec_heap_part() -> TypeRef {
|
||||
ret T_struct(~[T_int(), // Real length
|
||||
T_array(T_i8(), 0u)]); // Body elements
|
||||
|
||||
}
|
||||
|
||||
fn T_opaque_ivec_heap() -> TypeRef {
|
||||
ret T_struct(~[T_int(), // Length (zero)
|
||||
T_int(), // Alloc
|
||||
T_ptr(T_opaque_ivec_heap_part())]); // Pointer
|
||||
|
||||
}
|
||||
|
||||
fn T_str() -> TypeRef { ret T_vec(T_i8()); }
|
||||
|
||||
fn T_box(TypeRef t) -> TypeRef { ret T_struct(~[T_int(), t]); }
|
||||
|
||||
fn T_port(TypeRef t) -> TypeRef {
|
||||
ret T_struct(~[T_int()]); // Refcount
|
||||
|
||||
}
|
||||
|
||||
fn T_chan(TypeRef t) -> TypeRef {
|
||||
ret T_struct(~[T_int()]); // Refcount
|
||||
|
||||
}
|
||||
|
||||
fn T_taskptr(&crate_ctxt cx) -> TypeRef { ret T_ptr(cx.task_type); }
|
||||
|
||||
|
||||
// This type must never be used directly; it must always be cast away.
|
||||
fn T_typaram(&type_names tn) -> TypeRef {
|
||||
auto s = "typaram";
|
||||
if (tn.name_has_type(s)) { ret tn.get_type(s); }
|
||||
auto t = T_i8();
|
||||
tn.associate(s, t);
|
||||
ret t;
|
||||
}
|
||||
|
||||
fn T_typaram_ptr(&type_names tn) -> TypeRef { ret T_ptr(T_typaram(tn)); }
|
||||
|
||||
fn T_closure_ptr(&crate_ctxt cx, TypeRef lltarget_ty, TypeRef llbindings_ty,
|
||||
uint n_ty_params) -> TypeRef {
|
||||
// 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.
|
||||
|
||||
ret T_ptr(T_box(T_struct(~[T_ptr(cx.tydesc_type), lltarget_ty,
|
||||
llbindings_ty,
|
||||
T_captured_tydescs(cx, n_ty_params)])));
|
||||
}
|
||||
|
||||
fn T_opaque_closure_ptr(&crate_ctxt cx) -> TypeRef {
|
||||
auto s = "*closure";
|
||||
if (cx.tn.name_has_type(s)) { ret cx.tn.get_type(s); }
|
||||
auto t =
|
||||
T_closure_ptr(cx,
|
||||
T_struct(~[T_ptr(T_nil()), T_ptr(T_nil())]),
|
||||
T_nil(),
|
||||
0u);
|
||||
cx.tn.associate(s, t);
|
||||
ret t;
|
||||
}
|
||||
|
||||
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(~[T_int(), T_array(T_i8(), size)]);
|
||||
tn.associate(s, t);
|
||||
ret t;
|
||||
}
|
||||
|
||||
fn T_opaque_tag(&type_names tn) -> TypeRef {
|
||||
auto s = "opaque_tag";
|
||||
if (tn.name_has_type(s)) { ret tn.get_type(s); }
|
||||
auto t = T_struct(~[T_int(), T_i8()]);
|
||||
tn.associate(s, t);
|
||||
ret t;
|
||||
}
|
||||
|
||||
fn T_opaque_tag_ptr(&type_names tn) -> TypeRef {
|
||||
ret T_ptr(T_opaque_tag(tn));
|
||||
}
|
||||
|
||||
fn T_captured_tydescs(&crate_ctxt cx, uint n) -> TypeRef {
|
||||
ret T_struct(std::ivec::init_elt[TypeRef](T_ptr(cx.tydesc_type), n));
|
||||
}
|
||||
|
||||
fn T_obj_ptr(&crate_ctxt cx, 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(&crate_ctxt cx, uint n_captured_tydescs) -> TypeRef {
|
||||
ret T_struct(~[T_ptr(cx.tydesc_type),
|
||||
T_captured_tydescs(cx, n_captured_tydescs)]);
|
||||
}
|
||||
ret T_ptr(T_box(T_obj(cx, n_captured_tydescs)));
|
||||
}
|
||||
|
||||
fn T_opaque_obj_ptr(&crate_ctxt cx) -> TypeRef { ret T_obj_ptr(cx, 0u); }
|
||||
|
||||
fn T_opaque_port_ptr() -> TypeRef { ret T_ptr(T_i8()); }
|
||||
|
||||
fn T_opaque_chan_ptr() -> TypeRef { ret T_ptr(T_i8()); }
|
||||
|
||||
|
||||
// This function now fails if called on a type with dynamic size (as its
|
||||
// return value was always meaningless in that case anyhow). Beware!
|
||||
//
|
||||
@ -1009,106 +687,6 @@ fn sanitize(&str s) -> str {
|
||||
}
|
||||
|
||||
|
||||
// LLVM constant constructors.
|
||||
fn C_null(TypeRef t) -> ValueRef { ret llvm::LLVMConstNull(t); }
|
||||
|
||||
fn C_integral(TypeRef t, uint u, Bool sign_extend) -> ValueRef {
|
||||
// FIXME: We can't use LLVM::ULongLong with our existing minimal native
|
||||
// API, which only knows word-sized args.
|
||||
//
|
||||
// ret llvm::LLVMConstInt(T_int(), t as LLVM::ULongLong, False);
|
||||
//
|
||||
|
||||
ret llvm::LLVMRustConstSmallInt(t, u, sign_extend);
|
||||
}
|
||||
|
||||
fn C_float(&str s) -> ValueRef {
|
||||
ret llvm::LLVMConstRealOfString(T_float(), str::buf(s));
|
||||
}
|
||||
|
||||
fn C_floating(&str s, TypeRef t) -> ValueRef {
|
||||
ret llvm::LLVMConstRealOfString(t, str::buf(s));
|
||||
}
|
||||
|
||||
fn C_nil() -> ValueRef {
|
||||
// NB: See comment above in T_void().
|
||||
|
||||
ret C_integral(T_i1(), 0u, False);
|
||||
}
|
||||
|
||||
fn C_bool(bool b) -> ValueRef {
|
||||
if (b) {
|
||||
ret C_integral(T_bool(), 1u, False);
|
||||
} else { ret C_integral(T_bool(), 0u, False); }
|
||||
}
|
||||
|
||||
fn C_int(int i) -> ValueRef { ret C_integral(T_int(), i as uint, True); }
|
||||
|
||||
fn C_uint(uint i) -> ValueRef { ret C_integral(T_int(), i, False); }
|
||||
|
||||
fn C_u8(uint i) -> ValueRef { ret C_integral(T_i8(), i, False); }
|
||||
|
||||
|
||||
// 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 {
|
||||
auto sc = llvm::LLVMConstString(str::buf(s), str::byte_len(s), False);
|
||||
auto g =
|
||||
llvm::LLVMAddGlobal(cx.llmod, val_ty(sc),
|
||||
str::buf(cx.names.next("str")));
|
||||
llvm::LLVMSetInitializer(g, sc);
|
||||
llvm::LLVMSetGlobalConstant(g, True);
|
||||
llvm::LLVMSetLinkage(g, lib::llvm::LLVMInternalLinkage as llvm::Linkage);
|
||||
ret g;
|
||||
}
|
||||
|
||||
|
||||
// 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(~[C_int(abi::const_refcount as int),
|
||||
C_int(len + 1u as int), // 'alloc'
|
||||
C_int(len + 1u as int), // 'fill'
|
||||
C_int(0), // 'pad'
|
||||
llvm::LLVMConstString(str::buf(s), len, False)]);
|
||||
auto g =
|
||||
llvm::LLVMAddGlobal(cx.llmod, val_ty(box),
|
||||
str::buf(cx.names.next("str")));
|
||||
llvm::LLVMSetInitializer(g, box);
|
||||
llvm::LLVMSetGlobalConstant(g, True);
|
||||
llvm::LLVMSetLinkage(g, lib::llvm::LLVMInternalLinkage as llvm::Linkage);
|
||||
ret llvm::LLVMConstPointerCast(g, T_ptr(T_str()));
|
||||
}
|
||||
|
||||
// Returns a Plain Old LLVM String:
|
||||
fn C_postr(&str s) -> ValueRef {
|
||||
ret llvm::LLVMConstString(str::buf(s), str::byte_len(s), False);
|
||||
}
|
||||
|
||||
fn C_zero_byte_arr(uint size) -> ValueRef {
|
||||
auto i = 0u;
|
||||
let ValueRef[] elts = ~[];
|
||||
while (i < size) { elts += ~[C_u8(0u)]; i += 1u; }
|
||||
ret llvm::LLVMConstArray(T_i8(), std::ivec::to_ptr(elts),
|
||||
std::ivec::len(elts));
|
||||
}
|
||||
|
||||
fn C_struct(&ValueRef[] elts) -> ValueRef {
|
||||
ret llvm::LLVMConstStruct(std::ivec::to_ptr(elts), std::ivec::len(elts),
|
||||
False);
|
||||
}
|
||||
|
||||
fn C_named_struct(TypeRef T, &ValueRef[] elts) -> ValueRef {
|
||||
ret llvm::LLVMConstNamedStruct(T, std::ivec::to_ptr(elts),
|
||||
std::ivec::len(elts));
|
||||
}
|
||||
|
||||
fn C_array(TypeRef ty, &ValueRef[] elts) -> ValueRef {
|
||||
ret llvm::LLVMConstArray(ty, std::ivec::to_ptr(elts),
|
||||
std::ivec::len(elts));
|
||||
}
|
||||
|
||||
fn decl_fn(ModuleRef llmod, &str name, uint cc, TypeRef llty) -> ValueRef {
|
||||
let ValueRef llfn = llvm::LLVMAddFunction(llmod, str::buf(name), llty);
|
||||
llvm::LLVMSetFunctionCallConv(llfn, cc);
|
||||
@ -9250,7 +8828,7 @@ fn create_crate_map(&@crate_ctxt ccx) -> ValueRef {
|
||||
fn write_metadata(&@trans::crate_ctxt cx, &@ast::crate crate) {
|
||||
if (!cx.sess.get_opts().library) { ret; }
|
||||
auto llmeta = C_postr(metadata::encoder::encode_metadata(cx, crate));
|
||||
auto llconst = trans::C_struct(~[llmeta]);
|
||||
auto llconst = trans_common::C_struct(~[llmeta]);
|
||||
auto llglobal =
|
||||
llvm::LLVMAddGlobal(cx.llmod, trans::val_ty(llconst),
|
||||
str::buf("rust_metadata"));
|
||||
|
@ -16,9 +16,6 @@ import trans::block_ctxt;
|
||||
import trans::new_sub_block_ctxt;
|
||||
import trans::new_scope_block_ctxt;
|
||||
import trans::load_if_immediate;
|
||||
import trans::C_int;
|
||||
import trans::C_uint;
|
||||
import trans::C_nil;
|
||||
import trans::val_ty;
|
||||
import ty::pat_ty;
|
||||
import syntax::ast;
|
||||
@ -26,6 +23,8 @@ import syntax::ast::def_id;
|
||||
import syntax::codemap::span;
|
||||
import util::common::lit_eq;
|
||||
|
||||
import trans_common::*;
|
||||
|
||||
// An option identifying a branch (either a literal or a tag variant)
|
||||
tag opt {
|
||||
lit(@ast::lit);
|
||||
@ -201,7 +200,7 @@ fn extract_variant_args(@block_ctxt bcx, ast::node_id pat_id,
|
||||
(ccx.tcx, vdefs._0, vdefs._1).args);
|
||||
if (size > 0u && ivec::len(variants) != 1u) {
|
||||
auto tagptr = bcx.build.PointerCast
|
||||
(val, trans::T_opaque_tag_ptr(ccx.tn));
|
||||
(val, trans_common::T_opaque_tag_ptr(ccx.tn));
|
||||
blobptr = bcx.build.GEP(tagptr, ~[C_int(0), C_int(1)]);
|
||||
}
|
||||
auto i = 0u;
|
||||
@ -315,7 +314,7 @@ fn compile_submatch(@block_ctxt bcx, &match m, ValueRef[] vals, &mk_fail f,
|
||||
kind = single;
|
||||
} else {
|
||||
auto tagptr = bcx.build.PointerCast
|
||||
(val, trans::T_opaque_tag_ptr(ccx.tn));
|
||||
(val, trans_common::T_opaque_tag_ptr(ccx.tn));
|
||||
auto discrimptr = bcx.build.GEP
|
||||
(tagptr, ~[C_int(0), C_int(0)]);
|
||||
test_val = bcx.build.Load(discrimptr);
|
||||
|
487
src/comp/middle/trans_common.rs
Normal file
487
src/comp/middle/trans_common.rs
Normal file
@ -0,0 +1,487 @@
|
||||
/**
|
||||
Code that is useful in various trans modules.
|
||||
|
||||
*/
|
||||
|
||||
import std::int;
|
||||
import std::str;
|
||||
import std::uint;
|
||||
import std::str::rustrt::sbuf;
|
||||
import std::map;
|
||||
import std::map::hashmap;
|
||||
import std::option;
|
||||
import std::option::some;
|
||||
import std::option::none;
|
||||
import std::fs;
|
||||
import syntax::ast;
|
||||
import syntax::walk;
|
||||
import driver::session;
|
||||
import middle::ty;
|
||||
import back::link;
|
||||
import back::x86;
|
||||
import back::abi;
|
||||
import back::upcall;
|
||||
import syntax::visit;
|
||||
import visit::vt;
|
||||
import util::common;
|
||||
import util::common::*;
|
||||
import std::map::new_int_hash;
|
||||
import std::map::new_str_hash;
|
||||
import syntax::codemap::span;
|
||||
import lib::llvm::llvm;
|
||||
import lib::llvm::builder;
|
||||
import lib::llvm::target_data;
|
||||
import lib::llvm::type_names;
|
||||
import lib::llvm::mk_target_data;
|
||||
import lib::llvm::mk_type_names;
|
||||
import lib::llvm::llvm::ModuleRef;
|
||||
import lib::llvm::llvm::ValueRef;
|
||||
import lib::llvm::llvm::TypeRef;
|
||||
import lib::llvm::llvm::TypeHandleRef;
|
||||
import lib::llvm::llvm::BuilderRef;
|
||||
import lib::llvm::llvm::BasicBlockRef;
|
||||
import lib::llvm::False;
|
||||
import lib::llvm::True;
|
||||
import lib::llvm::Bool;
|
||||
import link::mangle_internal_name_by_type_only;
|
||||
import link::mangle_internal_name_by_seq;
|
||||
import link::mangle_internal_name_by_path;
|
||||
import link::mangle_internal_name_by_path_and_seq;
|
||||
import link::mangle_exported_name;
|
||||
import metadata::creader;
|
||||
import metadata::csearch;
|
||||
import metadata::cstore;
|
||||
import util::ppaux::ty_to_str;
|
||||
import util::ppaux::ty_to_short_str;
|
||||
import syntax::print::pprust::expr_to_str;
|
||||
import syntax::print::pprust::path_to_str;
|
||||
|
||||
// FIXME: These should probably be pulled in here too.
|
||||
import trans::crate_ctxt;
|
||||
import trans::type_of_fn_full;
|
||||
import trans::val_ty;
|
||||
|
||||
// LLVM type constructors.
|
||||
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.
|
||||
|
||||
ret llvm::LLVMVoidType();
|
||||
}
|
||||
|
||||
fn T_nil() -> TypeRef {
|
||||
// NB: See above in T_void().
|
||||
|
||||
ret llvm::LLVMInt1Type();
|
||||
}
|
||||
|
||||
fn T_i1() -> TypeRef { ret llvm::LLVMInt1Type(); }
|
||||
|
||||
fn T_i8() -> TypeRef { ret llvm::LLVMInt8Type(); }
|
||||
|
||||
fn T_i16() -> TypeRef { ret llvm::LLVMInt16Type(); }
|
||||
|
||||
fn T_i32() -> TypeRef { ret llvm::LLVMInt32Type(); }
|
||||
|
||||
fn T_i64() -> TypeRef { ret llvm::LLVMInt64Type(); }
|
||||
|
||||
fn T_f32() -> TypeRef { ret llvm::LLVMFloatType(); }
|
||||
|
||||
fn T_f64() -> TypeRef { ret llvm::LLVMDoubleType(); }
|
||||
|
||||
fn T_bool() -> TypeRef { ret T_i1(); }
|
||||
|
||||
fn T_int() -> TypeRef {
|
||||
// FIXME: switch on target type.
|
||||
|
||||
ret T_i32();
|
||||
}
|
||||
|
||||
fn T_float() -> TypeRef {
|
||||
// FIXME: switch on target type.
|
||||
|
||||
ret T_f64();
|
||||
}
|
||||
|
||||
fn T_char() -> TypeRef { ret T_i32(); }
|
||||
|
||||
fn T_size_t() -> TypeRef {
|
||||
// FIXME: switch on target type.
|
||||
|
||||
ret T_i32();
|
||||
}
|
||||
|
||||
fn T_fn(&TypeRef[] inputs, TypeRef output) -> TypeRef {
|
||||
ret llvm::LLVMFunctionType(output, std::ivec::to_ptr(inputs),
|
||||
std::ivec::len[TypeRef](inputs), False);
|
||||
}
|
||||
|
||||
fn T_fn_pair(&crate_ctxt cx, TypeRef tfn) -> TypeRef {
|
||||
ret T_struct(~[T_ptr(tfn), T_opaque_closure_ptr(cx)]);
|
||||
}
|
||||
|
||||
fn T_ptr(TypeRef t) -> TypeRef { ret llvm::LLVMPointerType(t, 0u); }
|
||||
|
||||
fn T_struct(&TypeRef[] elts) -> TypeRef {
|
||||
ret llvm::LLVMStructType(std::ivec::to_ptr(elts), std::ivec::len(elts),
|
||||
False);
|
||||
}
|
||||
|
||||
fn T_named_struct(&str name) -> TypeRef {
|
||||
auto c = llvm::LLVMGetGlobalContext();
|
||||
ret llvm::LLVMStructCreateNamed(c, str::buf(name));
|
||||
}
|
||||
|
||||
fn set_struct_body(TypeRef t, &TypeRef[] elts) {
|
||||
llvm::LLVMStructSetBody(t, std::ivec::to_ptr(elts), std::ivec::len(elts),
|
||||
False);
|
||||
}
|
||||
|
||||
fn T_empty_struct() -> TypeRef { ret T_struct(~[]); }
|
||||
|
||||
fn T_rust_object() -> TypeRef {
|
||||
auto t = T_named_struct("rust_object");
|
||||
auto e = T_ptr(T_empty_struct());
|
||||
set_struct_body(t, ~[e,e]);
|
||||
ret t;
|
||||
}
|
||||
|
||||
fn T_task() -> TypeRef {
|
||||
auto t = T_named_struct("task");
|
||||
|
||||
auto elems = ~[T_int(), // Refcount
|
||||
T_int(), // Delegate pointer
|
||||
T_int(), // Stack segment pointer
|
||||
T_int(), // Runtime SP
|
||||
T_int(), // Rust SP
|
||||
T_int(), // GC chain
|
||||
|
||||
T_int(), // Domain pointer
|
||||
// Crate cache pointer
|
||||
T_int()];
|
||||
set_struct_body(t, elems);
|
||||
ret t;
|
||||
}
|
||||
|
||||
fn T_tydesc_field(&crate_ctxt cx, int field) -> TypeRef {
|
||||
// Bit of a kludge: pick the fn typeref out of the tydesc..
|
||||
|
||||
let TypeRef[] tydesc_elts =
|
||||
std::ivec::init_elt[TypeRef](T_nil(), abi::n_tydesc_fields as uint);
|
||||
llvm::LLVMGetStructElementTypes(cx.tydesc_type,
|
||||
std::ivec::to_ptr[TypeRef](tydesc_elts));
|
||||
auto t = llvm::LLVMGetElementType(tydesc_elts.(field));
|
||||
ret t;
|
||||
}
|
||||
|
||||
fn T_glue_fn(&crate_ctxt cx) -> TypeRef {
|
||||
auto s = "glue_fn";
|
||||
if (cx.tn.name_has_type(s)) { ret cx.tn.get_type(s); }
|
||||
auto t = T_tydesc_field(cx, abi::tydesc_field_drop_glue);
|
||||
cx.tn.associate(s, t);
|
||||
ret t;
|
||||
}
|
||||
|
||||
fn T_dtor(&@crate_ctxt ccx, &span sp) -> TypeRef {
|
||||
ret type_of_fn_full(ccx, sp, ast::proto_fn, true,
|
||||
~[], ty::mk_nil(ccx.tcx), 0u);
|
||||
}
|
||||
|
||||
fn T_cmp_glue_fn(&crate_ctxt cx) -> TypeRef {
|
||||
auto s = "cmp_glue_fn";
|
||||
if (cx.tn.name_has_type(s)) { ret cx.tn.get_type(s); }
|
||||
auto t = T_tydesc_field(cx, abi::tydesc_field_cmp_glue);
|
||||
cx.tn.associate(s, t);
|
||||
ret t;
|
||||
}
|
||||
|
||||
fn T_tydesc(TypeRef taskptr_type) -> TypeRef {
|
||||
auto tydesc = T_named_struct("tydesc");
|
||||
auto tydescpp = T_ptr(T_ptr(tydesc));
|
||||
auto pvoid = T_ptr(T_i8());
|
||||
auto glue_fn_ty =
|
||||
T_ptr(T_fn(~[T_ptr(T_nil()), taskptr_type, T_ptr(T_nil()), tydescpp,
|
||||
pvoid], T_void()));
|
||||
auto cmp_glue_fn_ty =
|
||||
T_ptr(T_fn(~[T_ptr(T_i1()), taskptr_type, T_ptr(T_nil()), tydescpp,
|
||||
pvoid, pvoid, T_i8()], T_void()));
|
||||
|
||||
auto elems = ~[tydescpp, // first_param
|
||||
T_int(), // size
|
||||
T_int(), // align
|
||||
glue_fn_ty, // copy_glue
|
||||
glue_fn_ty, // drop_glue
|
||||
glue_fn_ty, // free_glue
|
||||
glue_fn_ty, // sever_glue
|
||||
glue_fn_ty, // mark_glue
|
||||
glue_fn_ty, // obj_drop_glue
|
||||
glue_fn_ty, // is_stateful
|
||||
cmp_glue_fn_ty];
|
||||
set_struct_body(tydesc, elems);
|
||||
ret tydesc;
|
||||
}
|
||||
|
||||
fn T_array(TypeRef t, uint n) -> TypeRef { ret llvm::LLVMArrayType(t, n); }
|
||||
|
||||
fn T_vec(TypeRef t) -> TypeRef {
|
||||
ret T_struct(~[T_int(), // Refcount
|
||||
T_int(), // Alloc
|
||||
T_int(), // Fill
|
||||
|
||||
T_int(), // Pad
|
||||
// Body elements
|
||||
T_array(t, 0u)]);
|
||||
}
|
||||
|
||||
fn T_opaque_vec_ptr() -> TypeRef { ret T_ptr(T_vec(T_int())); }
|
||||
|
||||
|
||||
// Interior vector.
|
||||
//
|
||||
// TODO: Support user-defined vector sizes.
|
||||
fn T_ivec(TypeRef t) -> TypeRef {
|
||||
ret T_struct(~[T_int(), // Length ("fill"; if zero, heapified)
|
||||
T_int(), // Alloc
|
||||
T_array(t, abi::ivec_default_length)]); // Body elements
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Note that the size of this one is in bytes.
|
||||
fn T_opaque_ivec() -> TypeRef {
|
||||
ret T_struct(~[T_int(), // Length ("fill"; if zero, heapified)
|
||||
T_int(), // Alloc
|
||||
T_array(T_i8(), 0u)]); // Body elements
|
||||
|
||||
}
|
||||
|
||||
fn T_ivec_heap_part(TypeRef t) -> TypeRef {
|
||||
ret T_struct(~[T_int(), // Real length
|
||||
T_array(t, 0u)]); // Body elements
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Interior vector on the heap, also known as the "stub". Cast to this when
|
||||
// the allocated length (second element of T_ivec above) is zero.
|
||||
fn T_ivec_heap(TypeRef t) -> TypeRef {
|
||||
ret T_struct(~[T_int(), // Length (zero)
|
||||
T_int(), // Alloc
|
||||
T_ptr(T_ivec_heap_part(t))]); // Pointer
|
||||
|
||||
}
|
||||
|
||||
fn T_opaque_ivec_heap_part() -> TypeRef {
|
||||
ret T_struct(~[T_int(), // Real length
|
||||
T_array(T_i8(), 0u)]); // Body elements
|
||||
|
||||
}
|
||||
|
||||
fn T_opaque_ivec_heap() -> TypeRef {
|
||||
ret T_struct(~[T_int(), // Length (zero)
|
||||
T_int(), // Alloc
|
||||
T_ptr(T_opaque_ivec_heap_part())]); // Pointer
|
||||
|
||||
}
|
||||
|
||||
fn T_str() -> TypeRef { ret T_vec(T_i8()); }
|
||||
|
||||
fn T_box(TypeRef t) -> TypeRef { ret T_struct(~[T_int(), t]); }
|
||||
|
||||
fn T_port(TypeRef t) -> TypeRef {
|
||||
ret T_struct(~[T_int()]); // Refcount
|
||||
|
||||
}
|
||||
|
||||
fn T_chan(TypeRef t) -> TypeRef {
|
||||
ret T_struct(~[T_int()]); // Refcount
|
||||
|
||||
}
|
||||
|
||||
fn T_taskptr(&crate_ctxt cx) -> TypeRef { ret T_ptr(cx.task_type); }
|
||||
|
||||
|
||||
// This type must never be used directly; it must always be cast away.
|
||||
fn T_typaram(&type_names tn) -> TypeRef {
|
||||
auto s = "typaram";
|
||||
if (tn.name_has_type(s)) { ret tn.get_type(s); }
|
||||
auto t = T_i8();
|
||||
tn.associate(s, t);
|
||||
ret t;
|
||||
}
|
||||
|
||||
fn T_typaram_ptr(&type_names tn) -> TypeRef { ret T_ptr(T_typaram(tn)); }
|
||||
|
||||
fn T_closure_ptr(&crate_ctxt cx, TypeRef lltarget_ty, TypeRef llbindings_ty,
|
||||
uint n_ty_params) -> TypeRef {
|
||||
// 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.
|
||||
|
||||
ret T_ptr(T_box(T_struct(~[T_ptr(cx.tydesc_type), lltarget_ty,
|
||||
llbindings_ty,
|
||||
T_captured_tydescs(cx, n_ty_params)])));
|
||||
}
|
||||
|
||||
fn T_opaque_closure_ptr(&crate_ctxt cx) -> TypeRef {
|
||||
auto s = "*closure";
|
||||
if (cx.tn.name_has_type(s)) { ret cx.tn.get_type(s); }
|
||||
auto t =
|
||||
T_closure_ptr(cx,
|
||||
T_struct(~[T_ptr(T_nil()), T_ptr(T_nil())]),
|
||||
T_nil(),
|
||||
0u);
|
||||
cx.tn.associate(s, t);
|
||||
ret t;
|
||||
}
|
||||
|
||||
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(~[T_int(), T_array(T_i8(), size)]);
|
||||
tn.associate(s, t);
|
||||
ret t;
|
||||
}
|
||||
|
||||
fn T_opaque_tag(&type_names tn) -> TypeRef {
|
||||
auto s = "opaque_tag";
|
||||
if (tn.name_has_type(s)) { ret tn.get_type(s); }
|
||||
auto t = T_struct(~[T_int(), T_i8()]);
|
||||
tn.associate(s, t);
|
||||
ret t;
|
||||
}
|
||||
|
||||
fn T_opaque_tag_ptr(&type_names tn) -> TypeRef {
|
||||
ret T_ptr(T_opaque_tag(tn));
|
||||
}
|
||||
|
||||
fn T_captured_tydescs(&crate_ctxt cx, uint n) -> TypeRef {
|
||||
ret T_struct(std::ivec::init_elt[TypeRef](T_ptr(cx.tydesc_type), n));
|
||||
}
|
||||
|
||||
fn T_obj_ptr(&crate_ctxt cx, 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(&crate_ctxt cx, uint n_captured_tydescs) -> TypeRef {
|
||||
ret T_struct(~[T_ptr(cx.tydesc_type),
|
||||
T_captured_tydescs(cx, n_captured_tydescs)]);
|
||||
}
|
||||
ret T_ptr(T_box(T_obj(cx, n_captured_tydescs)));
|
||||
}
|
||||
|
||||
fn T_opaque_obj_ptr(&crate_ctxt cx) -> TypeRef { ret T_obj_ptr(cx, 0u); }
|
||||
|
||||
fn T_opaque_port_ptr() -> TypeRef { ret T_ptr(T_i8()); }
|
||||
|
||||
fn T_opaque_chan_ptr() -> TypeRef { ret T_ptr(T_i8()); }
|
||||
|
||||
|
||||
// LLVM constant constructors.
|
||||
fn C_null(TypeRef t) -> ValueRef { ret llvm::LLVMConstNull(t); }
|
||||
|
||||
fn C_integral(TypeRef t, uint u, Bool sign_extend) -> ValueRef {
|
||||
// FIXME: We can't use LLVM::ULongLong with our existing minimal native
|
||||
// API, which only knows word-sized args.
|
||||
//
|
||||
// ret llvm::LLVMConstInt(T_int(), t as LLVM::ULongLong, False);
|
||||
//
|
||||
|
||||
ret llvm::LLVMRustConstSmallInt(t, u, sign_extend);
|
||||
}
|
||||
|
||||
fn C_float(&str s) -> ValueRef {
|
||||
ret llvm::LLVMConstRealOfString(T_float(), str::buf(s));
|
||||
}
|
||||
|
||||
fn C_floating(&str s, TypeRef t) -> ValueRef {
|
||||
ret llvm::LLVMConstRealOfString(t, str::buf(s));
|
||||
}
|
||||
|
||||
fn C_nil() -> ValueRef {
|
||||
// NB: See comment above in T_void().
|
||||
|
||||
ret C_integral(T_i1(), 0u, False);
|
||||
}
|
||||
|
||||
fn C_bool(bool b) -> ValueRef {
|
||||
if (b) {
|
||||
ret C_integral(T_bool(), 1u, False);
|
||||
} else { ret C_integral(T_bool(), 0u, False); }
|
||||
}
|
||||
|
||||
fn C_int(int i) -> ValueRef { ret C_integral(T_int(), i as uint, True); }
|
||||
|
||||
fn C_uint(uint i) -> ValueRef { ret C_integral(T_int(), i, False); }
|
||||
|
||||
fn C_u8(uint i) -> ValueRef { ret C_integral(T_i8(), i, False); }
|
||||
|
||||
|
||||
// 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 {
|
||||
auto sc = llvm::LLVMConstString(str::buf(s), str::byte_len(s), False);
|
||||
auto g =
|
||||
llvm::LLVMAddGlobal(cx.llmod, val_ty(sc),
|
||||
str::buf(cx.names.next("str")));
|
||||
llvm::LLVMSetInitializer(g, sc);
|
||||
llvm::LLVMSetGlobalConstant(g, True);
|
||||
llvm::LLVMSetLinkage(g, lib::llvm::LLVMInternalLinkage as llvm::Linkage);
|
||||
ret g;
|
||||
}
|
||||
|
||||
|
||||
// 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(~[C_int(abi::const_refcount as int),
|
||||
C_int(len + 1u as int), // 'alloc'
|
||||
C_int(len + 1u as int), // 'fill'
|
||||
C_int(0), // 'pad'
|
||||
llvm::LLVMConstString(str::buf(s), len, False)]);
|
||||
auto g =
|
||||
llvm::LLVMAddGlobal(cx.llmod, val_ty(box),
|
||||
str::buf(cx.names.next("str")));
|
||||
llvm::LLVMSetInitializer(g, box);
|
||||
llvm::LLVMSetGlobalConstant(g, True);
|
||||
llvm::LLVMSetLinkage(g, lib::llvm::LLVMInternalLinkage as llvm::Linkage);
|
||||
ret llvm::LLVMConstPointerCast(g, T_ptr(T_str()));
|
||||
}
|
||||
|
||||
// Returns a Plain Old LLVM String:
|
||||
fn C_postr(&str s) -> ValueRef {
|
||||
ret llvm::LLVMConstString(str::buf(s), str::byte_len(s), False);
|
||||
}
|
||||
|
||||
fn C_zero_byte_arr(uint size) -> ValueRef {
|
||||
auto i = 0u;
|
||||
let ValueRef[] elts = ~[];
|
||||
while (i < size) { elts += ~[C_u8(0u)]; i += 1u; }
|
||||
ret llvm::LLVMConstArray(T_i8(), std::ivec::to_ptr(elts),
|
||||
std::ivec::len(elts));
|
||||
}
|
||||
|
||||
fn C_struct(&ValueRef[] elts) -> ValueRef {
|
||||
ret llvm::LLVMConstStruct(std::ivec::to_ptr(elts), std::ivec::len(elts),
|
||||
False);
|
||||
}
|
||||
|
||||
fn C_named_struct(TypeRef T, &ValueRef[] elts) -> ValueRef {
|
||||
ret llvm::LLVMConstNamedStruct(T, std::ivec::to_ptr(elts),
|
||||
std::ivec::len(elts));
|
||||
}
|
||||
|
||||
fn C_array(TypeRef ty, &ValueRef[] elts) -> ValueRef {
|
||||
ret llvm::LLVMConstArray(ty, std::ivec::to_ptr(elts),
|
||||
std::ivec::len(elts));
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ use std (name = "std",
|
||||
url = "http://rust-lang.org/src/std");
|
||||
|
||||
mod middle {
|
||||
mod trans_common;
|
||||
mod trans;
|
||||
mod trans_alt;
|
||||
mod ty;
|
||||
|
Loading…
x
Reference in New Issue
Block a user