From 8afb1a7c639d2d2959cdc79c544fac7dd5730897 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Thu, 14 Jul 2011 17:08:22 -0700 Subject: [PATCH] refactor: Move the LLVM type and constant constructors into a new module. --- src/comp/back/upcall.rs | 32 +-- src/comp/middle/trans.rs | 428 +--------------------------- src/comp/middle/trans_alt.rs | 9 +- src/comp/middle/trans_common.rs | 487 ++++++++++++++++++++++++++++++++ src/comp/rustc.rc | 1 + 5 files changed, 511 insertions(+), 446 deletions(-) create mode 100644 src/comp/middle/trans_common.rs diff --git a/src/comp/back/upcall.rs b/src/comp/back/upcall.rs index 53a30999a5b..6d95b25b95b 100644 --- a/src/comp/back/upcall.rs +++ b/src/comp/back/upcall.rs @@ -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; diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 5bedca727fd..fa107924546 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -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")); diff --git a/src/comp/middle/trans_alt.rs b/src/comp/middle/trans_alt.rs index 9bd453943fb..bc9a7fe235c 100644 --- a/src/comp/middle/trans_alt.rs +++ b/src/comp/middle/trans_alt.rs @@ -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); diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs new file mode 100644 index 00000000000..65c1bfb956e --- /dev/null +++ b/src/comp/middle/trans_common.rs @@ -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)); +} + diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc index 1968cafbe14..817ed6e071b 100644 --- a/src/comp/rustc.rc +++ b/src/comp/rustc.rc @@ -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;