From 3b2d23b2cdc270715f559d7fc0cfe4019011a7de Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Thu, 21 Jul 2011 17:27:34 -0700 Subject: [PATCH] Move a bunch of trans into trans_common, including the context structures. Probably more should be moved or split off into other files. My algorithm was something along the lines of: move the contexts and their transitive dependencies along with some functions to work with them. I stopped when I was going to have to start pulling glue generation, which really should go into a trans_glue file. --- src/comp/back/link.rs | 3 +- src/comp/metadata/encoder.rs | 2 +- src/comp/middle/trans.rs | 350 +------------------------------ src/comp/middle/trans_alt.rs | 5 - src/comp/middle/trans_common.rs | 354 +++++++++++++++++++++++++++++++- src/comp/middle/trans_dps.rs | 35 +--- src/comp/middle/trans_vec.rs | 8 +- 7 files changed, 369 insertions(+), 388 deletions(-) diff --git a/src/comp/back/link.rs b/src/comp/back/link.rs index ab9f47e3cc0..2b61ca6078e 100644 --- a/src/comp/back/link.rs +++ b/src/comp/back/link.rs @@ -2,9 +2,9 @@ import driver::session; import lib::llvm::llvm; import front::attr; -import middle::trans; import middle::ty; import metadata::encoder; +import middle::trans_common::crate_ctxt; import std::str; import std::fs; import std::ivec; @@ -13,7 +13,6 @@ import option::none; import std::sha1::sha1; import std::sort; -import trans::crate_ctxt; import syntax::ast; import syntax::print::pprust; import lib::llvm::llvm::ModuleRef; diff --git a/src/comp/metadata/encoder.rs b/src/comp/metadata/encoder.rs index e0c9d544742..2896fa57ddf 100644 --- a/src/comp/metadata/encoder.rs +++ b/src/comp/metadata/encoder.rs @@ -11,7 +11,7 @@ import std::map; import syntax::ast::*; import common::*; -import middle::trans::crate_ctxt; +import middle::trans_common::crate_ctxt; import middle::ty; import middle::ty::node_id_to_monotype; import front::attr; diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 06734b0b362..c6b90092881 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -75,341 +75,6 @@ import trans_comm::trans_send; import trans_comm::trans_recv; -obj namegen(mutable int i) { - fn next(str prefix) -> str { i += 1; ret prefix + int::str(i); } -} - -type derived_tydesc_info = rec(ValueRef lltydesc, bool escapes); - -type glue_fns = rec(ValueRef no_op_type_glue); - -type tydesc_info = - rec(ty::t ty, - ValueRef tydesc, - ValueRef size, - ValueRef align, - mutable option::t[ValueRef] copy_glue, - mutable option::t[ValueRef] drop_glue, - mutable option::t[ValueRef] free_glue, - mutable option::t[ValueRef] cmp_glue, - uint[] ty_params); - - -/* - * 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 an extern that references C code. Called with cdecl. - * - * 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. - * - */ -type stats = - rec(mutable uint n_static_tydescs, - mutable uint n_derived_tydescs, - mutable uint n_glues_created, - mutable uint n_null_glues, - mutable uint n_real_glues, - @mutable (tup(str,int)[]) fn_times); - - -// Crate context. Every crate we compile has one of these. -type crate_ctxt = - rec(session::session sess, - ModuleRef llmod, - target_data td, - type_names tn, - hashmap[str, ValueRef] externs, - hashmap[str, ValueRef] intrinsics, - - // A mapping from the def_id of each item in this crate to the address - // of the first instruction of the item's definition in the executable - // we're generating. - hashmap[ast::node_id, ValueRef] item_ids, - ast_map::map ast_map, - hashmap[ast::node_id, str] item_symbols, - mutable option::t[ValueRef] main_fn, - link::link_meta link_meta, - - // TODO: hashmap[tup(tag_id,subtys), @tag_info] - hashmap[ty::t, uint] tag_sizes, - hashmap[ast::node_id, ValueRef] discrims, - hashmap[ast::node_id, str] discrim_symbols, - hashmap[ast::node_id, ValueRef] fn_pairs, - hashmap[ast::node_id, ValueRef] consts, - hashmap[ast::node_id, ()] obj_methods, - hashmap[ty::t, @tydesc_info] tydescs, - hashmap[str, ValueRef] module_data, - hashmap[ty::t, TypeRef] lltypes, - @glue_fns glues, - namegen names, - std::sha1::sha1 sha, - hashmap[ty::t, str] type_sha1s, - hashmap[ty::t, str] type_short_names, - ty::ctxt tcx, - stats stats, - @upcall::upcalls upcalls, - TypeRef rust_object_type, - TypeRef tydesc_type, - TypeRef task_type); - -type local_ctxt = - rec(str[] path, - str[] module_path, - ast::ty_param[] obj_typarams, - ast::obj_field[] obj_fields, - @crate_ctxt ccx); - - -// Types used for llself. -type val_self_pair = rec(ValueRef v, ty::t t); - - -// Function context. Every LLVM function we create will have one of these. -type fn_ctxt = - rec( - // The ValueRef returned from a call to llvm::LLVMAddFunction; the - // address of the first instruction in the sequence of instructions - // for this function that will go in the .text section of the - // executable we're generating. - ValueRef llfn, - - // The three implicit arguments that arrive in the function we're - // creating. For instance, foo(int, int) is really foo(ret*, task*, - // env*, int, int). These are also available via - // llvm::LLVMGetParam(llfn, uint) where uint = 1, 2, 0 respectively, - // but we unpack them into these fields for convenience. - - // Points to the current task. - ValueRef lltaskptr, - - // Points to the current environment (bindings of variables to - // values), if this is a regular function; points to the current - // object, if this is a method. - ValueRef llenv, - - // Points to where the return value of this function should end up. - ValueRef llretptr, - - // The next three elements: "hoisted basic blocks" containing - // administrative activities that have to happen in only one place in - // the function, due to LLVM's quirks. - - // A block for all the function's static allocas, so that LLVM will - // coalesce them into a single alloca call. - mutable BasicBlockRef llstaticallocas, - - // A block containing code that copies incoming arguments to space - // already allocated by code in one of the llallocas blocks. (LLVM - // requires that arguments be copied to local allocas before allowing - // most any operation to be performed on them.) - mutable BasicBlockRef llcopyargs, - - // The first block containing derived tydescs received from the - // runtime. See description of derived_tydescs, below. - mutable BasicBlockRef llderivedtydescs_first, - - // The last block of the llderivedtydescs group. - mutable BasicBlockRef llderivedtydescs, - - // A block for all of the dynamically sized allocas. This must be - // after llderivedtydescs, because these sometimes depend on - // information computed from derived tydescs. - mutable BasicBlockRef lldynamicallocas, - - // FIXME: Is llcopyargs actually the block containing the allocas for - // incoming function arguments? Or is it merely the block containing - // code that copies incoming args to space already alloca'd by code in - // llallocas? - - // The 'self' object currently in use in this function, if there is - // one. - mutable option::t[val_self_pair] llself, - - // If this function is actually a iter, a block containing the code - // called whenever the iter calls 'put'. - mutable option::t[ValueRef] lliterbody, - - // The next four items: hash tables mapping from AST def_ids to - // LLVM-stuff-in-the-frame. - - // Maps arguments to allocas created for them in llallocas. - hashmap[ast::node_id, ValueRef] llargs, - - // Maps fields in objects to pointers into the interior of llself's - // body. - hashmap[ast::node_id, ValueRef] llobjfields, - - // Maps the def_ids for local variables to the allocas created for - // them in llallocas. - hashmap[ast::node_id, ValueRef] lllocals, - - // The same as above, but for variables accessed via the frame pointer - // we pass into an iter, for access to the static environment of the - // iter-calling frame. - hashmap[ast::node_id, ValueRef] llupvars, - - // For convenience, a vector of the incoming tydescs for each of this - // functions type parameters, fetched via llvm::LLVMGetParam. For - // example, for a function foo[A, B, C](), lltydescs contains the - // ValueRefs for the tydescs for A, B, and C. - mutable ValueRef[] lltydescs, - - // Derived tydescs are tydescs created at runtime, for types that - // involve type parameters inside type constructors. For example, - // suppose a function parameterized by T creates a vector of type - // [T]. The function doesn't know what T is until runtime, and the - // function's caller knows T but doesn't know that a vector is - // involved. So a tydesc for [T] can't be created until runtime, - // when information about both "[T]" and "T" are available. When such - // a tydesc is created, we cache it in the derived_tydescs table for - // the next time that such a tydesc is needed. - hashmap[ty::t, derived_tydesc_info] derived_tydescs, - - // The source span where this function comes from, for error - // reporting. - span sp, - - // This function's enclosing local context. - @local_ctxt lcx); - -tag cleanup { - clean(fn(&@block_ctxt) -> result); - clean_temp(ValueRef, fn(&@block_ctxt) -> result); -} - -fn add_clean(&@block_ctxt cx, ValueRef val, ty::t ty) { - find_scope_cx(cx).cleanups += ~[clean(bind drop_slot(_, val, ty))]; -} -fn add_clean_temp(&@block_ctxt cx, ValueRef val, ty::t ty) { - find_scope_cx(cx).cleanups += ~[clean_temp(val, - bind drop_ty(_, val, ty))]; -} - -// Note that this only works for temporaries. We should, at some point, move -// to a system where we can also cancel the cleanup on local variables, but -// this will be more involved. For now, we simply zero out the local, and the -// drop glue checks whether it is zero. -fn revoke_clean(&@block_ctxt cx, ValueRef val) { - auto sc_cx = find_scope_cx(cx); - auto found = -1; - auto i = 0; - for (cleanup c in sc_cx.cleanups) { - alt (c) { - case (clean_temp(?v, _)) { - if (v as uint == val as uint) { found = i; break; } - } - case (_) {} - } - i += 1; - } - // The value does not have a cleanup associated with it. Might be a - // constant or some immediate value. - if (found == -1) { ret; } - // We found the cleanup and remove it - sc_cx.cleanups = std::ivec::slice(sc_cx.cleanups, 0u, found as uint) + - std::ivec::slice(sc_cx.cleanups, found as uint + 1u, - std::ivec::len(sc_cx.cleanups)); -} - -tag block_kind { - - // A scope block is a basic block created by translating a block { ... } - // the the source language. Since these blocks create variable scope, any - // variables created in them that are still live at the end of the block - // must be dropped and cleaned up when the block ends. - SCOPE_BLOCK; - - // A basic block created from the body of a loop. Contains pointers to - // which block to jump to in the case of "continue" or "break", with the - // "continue" block optional, because "while" and "do while" don't support - // "continue" (TODO: is this intentional?) - LOOP_SCOPE_BLOCK(option::t[@block_ctxt], @block_ctxt); - - // A non-scope block is a basic block created as a translation artifact - // from translating code that expresses conditional logic rather than by - // explicit { ... } block structure in the source language. It's called a - // non-scope block because it doesn't introduce a new variable scope. - NON_SCOPE_BLOCK; -} - - -// Basic block context. We create a block context for each basic block -// (single-entry, single-exit sequence of instructions) we generate from Rust -// code. Each basic block we generate is attached to a function, typically -// with many basic blocks per function. All the basic blocks attached to a -// function are organized as a directed graph. -type block_ctxt = - rec( - // The BasicBlockRef returned from a call to - // llvm::LLVMAppendBasicBlock(llfn, name), which adds a basic block to - // the function pointed to by llfn. We insert instructions into that - // block by way of this block context. - BasicBlockRef llbb, - - // The llvm::builder object serving as an interface to LLVM's - // LLVMBuild* functions. - builder build, - - // The block pointing to this one in the function's digraph. - block_parent parent, - - // The 'kind' of basic block this is. - block_kind kind, - - // A list of functions that run at the end of translating this block, - // cleaning up any variables that were introduced in the block and - // need to go out of scope at the end of it. - mutable cleanup[] cleanups, - - // The source span where this block comes from, for error reporting. - span sp, - - // The function context for the function to which this block is - // attached. - @fn_ctxt fcx); - - -// 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); } - -type result = rec(@block_ctxt bcx, ValueRef val); -type result_t = rec(@block_ctxt bcx, ValueRef val, ty::t ty); - -fn extend_path(@local_ctxt cx, &str name) -> @local_ctxt { - ret @rec(path=cx.path + ~[name] with *cx); -} - -fn rslt(@block_ctxt bcx, ValueRef val) -> result { - ret rec(bcx=bcx, val=val); -} - -fn ty_str(type_names tn, TypeRef t) -> str { - ret lib::llvm::type_to_str(tn, t); -} - -fn val_ty(ValueRef v) -> TypeRef { ret llvm::LLVMTypeOf(v); } - -fn val_str(type_names tn, ValueRef v) -> str { ret ty_str(tn, val_ty(v)); } - - -// Returns the nth element of the given LLVM structure type. -fn struct_elt(TypeRef llstructty, uint n) -> TypeRef { - auto elt_count = llvm::LLVMCountStructElementTypes(llstructty); - assert (n < elt_count); - auto elt_tys = std::ivec::init_elt(T_nil(), elt_count); - llvm::LLVMGetStructElementTypes(llstructty, std::ivec::to_ptr(elt_tys)); - ret llvm::LLVMGetElementType(elt_tys.(n)); -} - - // This function now fails if called on a type with dynamic size (as its // return value was always meaningless in that case anyhow). Beware! // @@ -783,17 +448,6 @@ fn trans_shared_free(&@block_ctxt cx, ValueRef v) -> result { ret rslt(cx, C_int(0)); } -fn find_scope_cx(&@block_ctxt cx) -> @block_ctxt { - if (cx.kind != NON_SCOPE_BLOCK) { ret cx; } - alt (cx.parent) { - case (parent_some(?b)) { ret find_scope_cx(b); } - case (parent_none) { - cx.fcx.lcx.ccx.sess.bug("trans::find_scope_cx() " + - "called on parentless block_ctxt"); - } - } -} - 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); @@ -8518,12 +8172,12 @@ fn create_crate_map(&@crate_ctxt ccx) -> ValueRef { ret map; } -fn write_metadata(&@trans::crate_ctxt cx, &@ast::crate crate) { +fn write_metadata(&@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_common::C_struct(~[llmeta]); auto llglobal = - llvm::LLVMAddGlobal(cx.llmod, trans::val_ty(llconst), + llvm::LLVMAddGlobal(cx.llmod, val_ty(llconst), str::buf("rust_metadata")); llvm::LLVMSetInitializer(llglobal, llconst); llvm::LLVMSetSection(llglobal, str::buf(x86::get_meta_sect_name())); diff --git a/src/comp/middle/trans_alt.rs b/src/comp/middle/trans_alt.rs index 6ca0caeeef1..fa53c868536 100644 --- a/src/comp/middle/trans_alt.rs +++ b/src/comp/middle/trans_alt.rs @@ -9,14 +9,9 @@ import lib::llvm::llvm::ValueRef; import lib::llvm::llvm::TypeRef; import lib::llvm::llvm::BasicBlockRef; -import trans::result; -import trans::rslt; -import trans::crate_ctxt; -import trans::block_ctxt; import trans::new_sub_block_ctxt; import trans::new_scope_block_ctxt; import trans::load_if_immediate; -import trans::val_ty; import ty::pat_ty; import syntax::ast; import syntax::ast::def_id; diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs index 65c1bfb956e..9f2014b2a2d 100644 --- a/src/comp/middle/trans_common.rs +++ b/src/comp/middle/trans_common.rs @@ -57,9 +57,358 @@ 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; +import trans::drop_slot; +import trans::drop_ty; + +obj namegen(mutable int i) { + fn next(str prefix) -> str { i += 1; ret prefix + int::str(i); } +} + +type derived_tydesc_info = rec(ValueRef lltydesc, bool escapes); + +type glue_fns = rec(ValueRef no_op_type_glue); + +type tydesc_info = + rec(ty::t ty, + ValueRef tydesc, + ValueRef size, + ValueRef align, + mutable option::t[ValueRef] copy_glue, + mutable option::t[ValueRef] drop_glue, + mutable option::t[ValueRef] free_glue, + mutable option::t[ValueRef] cmp_glue, + uint[] ty_params); + +/* + * 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 an extern that references C code. Called with cdecl. + * + * 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. + * + */ +type stats = + rec(mutable uint n_static_tydescs, + mutable uint n_derived_tydescs, + mutable uint n_glues_created, + mutable uint n_null_glues, + mutable uint n_real_glues, + @mutable (tup(str,int)[]) fn_times); + +// Crate context. Every crate we compile has one of these. +type crate_ctxt = + rec(session::session sess, + ModuleRef llmod, + target_data td, + type_names tn, + hashmap[str, ValueRef] externs, + hashmap[str, ValueRef] intrinsics, + + // A mapping from the def_id of each item in this crate to the address + // of the first instruction of the item's definition in the executable + // we're generating. + hashmap[ast::node_id, ValueRef] item_ids, + ast_map::map ast_map, + hashmap[ast::node_id, str] item_symbols, + mutable option::t[ValueRef] main_fn, + link::link_meta link_meta, + + // TODO: hashmap[tup(tag_id,subtys), @tag_info] + hashmap[ty::t, uint] tag_sizes, + hashmap[ast::node_id, ValueRef] discrims, + hashmap[ast::node_id, str] discrim_symbols, + hashmap[ast::node_id, ValueRef] fn_pairs, + hashmap[ast::node_id, ValueRef] consts, + hashmap[ast::node_id, ()] obj_methods, + hashmap[ty::t, @tydesc_info] tydescs, + hashmap[str, ValueRef] module_data, + hashmap[ty::t, TypeRef] lltypes, + @glue_fns glues, + namegen names, + std::sha1::sha1 sha, + hashmap[ty::t, str] type_sha1s, + hashmap[ty::t, str] type_short_names, + ty::ctxt tcx, + stats stats, + @upcall::upcalls upcalls, + TypeRef rust_object_type, + TypeRef tydesc_type, + TypeRef task_type); + +type local_ctxt = + rec(str[] path, + str[] module_path, + ast::ty_param[] obj_typarams, + ast::obj_field[] obj_fields, + @crate_ctxt ccx); + +// Types used for llself. +type val_self_pair = rec(ValueRef v, ty::t t); + +// Function context. Every LLVM function we create will have one of these. +type fn_ctxt = + rec( + // The ValueRef returned from a call to llvm::LLVMAddFunction; the + // address of the first instruction in the sequence of instructions + // for this function that will go in the .text section of the + // executable we're generating. + ValueRef llfn, + + // The three implicit arguments that arrive in the function we're + // creating. For instance, foo(int, int) is really foo(ret*, task*, + // env*, int, int). These are also available via + // llvm::LLVMGetParam(llfn, uint) where uint = 1, 2, 0 respectively, + // but we unpack them into these fields for convenience. + + // Points to the current task. + ValueRef lltaskptr, + + // Points to the current environment (bindings of variables to + // values), if this is a regular function; points to the current + // object, if this is a method. + ValueRef llenv, + + // Points to where the return value of this function should end up. + ValueRef llretptr, + + // The next three elements: "hoisted basic blocks" containing + // administrative activities that have to happen in only one place in + // the function, due to LLVM's quirks. + + // A block for all the function's static allocas, so that LLVM will + // coalesce them into a single alloca call. + mutable BasicBlockRef llstaticallocas, + + // A block containing code that copies incoming arguments to space + // already allocated by code in one of the llallocas blocks. (LLVM + // requires that arguments be copied to local allocas before allowing + // most any operation to be performed on them.) + mutable BasicBlockRef llcopyargs, + + // The first block containing derived tydescs received from the + // runtime. See description of derived_tydescs, below. + mutable BasicBlockRef llderivedtydescs_first, + + // The last block of the llderivedtydescs group. + mutable BasicBlockRef llderivedtydescs, + + // A block for all of the dynamically sized allocas. This must be + // after llderivedtydescs, because these sometimes depend on + // information computed from derived tydescs. + mutable BasicBlockRef lldynamicallocas, + + // FIXME: Is llcopyargs actually the block containing the allocas for + // incoming function arguments? Or is it merely the block containing + // code that copies incoming args to space already alloca'd by code in + // llallocas? + + // The 'self' object currently in use in this function, if there is + // one. + mutable option::t[val_self_pair] llself, + + // If this function is actually a iter, a block containing the code + // called whenever the iter calls 'put'. + mutable option::t[ValueRef] lliterbody, + + // The next four items: hash tables mapping from AST def_ids to + // LLVM-stuff-in-the-frame. + + // Maps arguments to allocas created for them in llallocas. + hashmap[ast::node_id, ValueRef] llargs, + + // Maps fields in objects to pointers into the interior of llself's + // body. + hashmap[ast::node_id, ValueRef] llobjfields, + + // Maps the def_ids for local variables to the allocas created for + // them in llallocas. + hashmap[ast::node_id, ValueRef] lllocals, + + // The same as above, but for variables accessed via the frame pointer + // we pass into an iter, for access to the static environment of the + // iter-calling frame. + hashmap[ast::node_id, ValueRef] llupvars, + + // For convenience, a vector of the incoming tydescs for each of this + // functions type parameters, fetched via llvm::LLVMGetParam. For + // example, for a function foo[A, B, C](), lltydescs contains the + // ValueRefs for the tydescs for A, B, and C. + mutable ValueRef[] lltydescs, + + // Derived tydescs are tydescs created at runtime, for types that + // involve type parameters inside type constructors. For example, + // suppose a function parameterized by T creates a vector of type + // [T]. The function doesn't know what T is until runtime, and the + // function's caller knows T but doesn't know that a vector is + // involved. So a tydesc for [T] can't be created until runtime, + // when information about both "[T]" and "T" are available. When such + // a tydesc is created, we cache it in the derived_tydescs table for + // the next time that such a tydesc is needed. + hashmap[ty::t, derived_tydesc_info] derived_tydescs, + + // The source span where this function comes from, for error + // reporting. + span sp, + + // This function's enclosing local context. + @local_ctxt lcx); + +tag cleanup { + clean(fn(&@block_ctxt) -> result); + clean_temp(ValueRef, fn(&@block_ctxt) -> result); +} + +fn add_clean(&@block_ctxt cx, ValueRef val, ty::t ty) { + find_scope_cx(cx).cleanups += ~[clean(bind drop_slot(_, val, ty))]; +} +fn add_clean_temp(&@block_ctxt cx, ValueRef val, ty::t ty) { + find_scope_cx(cx).cleanups += ~[clean_temp(val, + bind drop_ty(_, val, ty))]; +} + +// Note that this only works for temporaries. We should, at some point, move +// to a system where we can also cancel the cleanup on local variables, but +// this will be more involved. For now, we simply zero out the local, and the +// drop glue checks whether it is zero. +fn revoke_clean(&@block_ctxt cx, ValueRef val) { + auto sc_cx = find_scope_cx(cx); + auto found = -1; + auto i = 0; + for (cleanup c in sc_cx.cleanups) { + alt (c) { + case (clean_temp(?v, _)) { + if (v as uint == val as uint) { found = i; break; } + } + case (_) {} + } + i += 1; + } + // The value does not have a cleanup associated with it. Might be a + // constant or some immediate value. + if (found == -1) { ret; } + // We found the cleanup and remove it + sc_cx.cleanups = std::ivec::slice(sc_cx.cleanups, 0u, found as uint) + + std::ivec::slice(sc_cx.cleanups, found as uint + 1u, + std::ivec::len(sc_cx.cleanups)); +} + +tag block_kind { + + // A scope block is a basic block created by translating a block { ... } + // the the source language. Since these blocks create variable scope, any + // variables created in them that are still live at the end of the block + // must be dropped and cleaned up when the block ends. + SCOPE_BLOCK; + + // A basic block created from the body of a loop. Contains pointers to + // which block to jump to in the case of "continue" or "break", with the + // "continue" block optional, because "while" and "do while" don't support + // "continue" (TODO: is this intentional?) + LOOP_SCOPE_BLOCK(option::t[@block_ctxt], @block_ctxt); + + // A non-scope block is a basic block created as a translation artifact + // from translating code that expresses conditional logic rather than by + // explicit { ... } block structure in the source language. It's called a + // non-scope block because it doesn't introduce a new variable scope. + NON_SCOPE_BLOCK; +} + + +// Basic block context. We create a block context for each basic block +// (single-entry, single-exit sequence of instructions) we generate from Rust +// code. Each basic block we generate is attached to a function, typically +// with many basic blocks per function. All the basic blocks attached to a +// function are organized as a directed graph. +type block_ctxt = + rec( + // The BasicBlockRef returned from a call to + // llvm::LLVMAppendBasicBlock(llfn, name), which adds a basic block to + // the function pointed to by llfn. We insert instructions into that + // block by way of this block context. + BasicBlockRef llbb, + + // The llvm::builder object serving as an interface to LLVM's + // LLVMBuild* functions. + builder build, + + // The block pointing to this one in the function's digraph. + block_parent parent, + + // The 'kind' of basic block this is. + block_kind kind, + + // A list of functions that run at the end of translating this block, + // cleaning up any variables that were introduced in the block and + // need to go out of scope at the end of it. + mutable cleanup[] cleanups, + + // The source span where this block comes from, for error reporting. + span sp, + + // The function context for the function to which this block is + // attached. + @fn_ctxt fcx); + +// 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); } + +type result = rec(@block_ctxt bcx, ValueRef val); +type result_t = rec(@block_ctxt bcx, ValueRef val, ty::t ty); + +fn extend_path(@local_ctxt cx, &str name) -> @local_ctxt { + ret @rec(path=cx.path + ~[name] with *cx); +} + +fn rslt(@block_ctxt bcx, ValueRef val) -> result { + ret rec(bcx=bcx, val=val); +} + +fn ty_str(type_names tn, TypeRef t) -> str { + ret lib::llvm::type_to_str(tn, t); +} + +fn val_ty(ValueRef v) -> TypeRef { ret llvm::LLVMTypeOf(v); } + +fn val_str(type_names tn, ValueRef v) -> str { ret ty_str(tn, val_ty(v)); } + +// Returns the nth element of the given LLVM structure type. +fn struct_elt(TypeRef llstructty, uint n) -> TypeRef { + auto elt_count = llvm::LLVMCountStructElementTypes(llstructty); + assert (n < elt_count); + auto elt_tys = std::ivec::init_elt(T_nil(), elt_count); + llvm::LLVMGetStructElementTypes(llstructty, std::ivec::to_ptr(elt_tys)); + ret llvm::LLVMGetElementType(elt_tys.(n)); +} + +fn find_scope_cx(&@block_ctxt cx) -> @block_ctxt { + if (cx.kind != NON_SCOPE_BLOCK) { ret cx; } + alt (cx.parent) { + case (parent_some(?b)) { ret find_scope_cx(b); } + case (parent_none) { + cx.fcx.lcx.ccx.sess.bug("trans::find_scope_cx() " + + "called on parentless block_ctxt"); + } + } +} + +// Accessors +// TODO: When we have overloading, simplify these names! + +fn bcx_tcx(&@block_ctxt bcx) -> ty::ctxt { ret bcx.fcx.lcx.ccx.tcx; } +fn bcx_ccx(&@block_ctxt bcx) -> @crate_ctxt { ret bcx.fcx.lcx.ccx; } +fn bcx_lcx(&@block_ctxt bcx) -> @local_ctxt { ret bcx.fcx.lcx; } +fn bcx_fcx(&@block_ctxt bcx) -> @fn_ctxt { ret bcx.fcx; } +fn lcx_ccx(&@local_ctxt lcx) -> @crate_ctxt { ret lcx.ccx; } +fn ccx_tcx(&@crate_ctxt ccx) -> ty::ctxt { ret ccx.tcx; } // LLVM type constructors. fn T_void() -> TypeRef { @@ -484,4 +833,3 @@ 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/middle/trans_dps.rs b/src/comp/middle/trans_dps.rs index 25d349fdba9..f3d74ec4d3a 100644 --- a/src/comp/middle/trans_dps.rs +++ b/src/comp/middle/trans_dps.rs @@ -6,16 +6,12 @@ import lib::llvm::llvm; import llvm::TypeRef; import llvm::ValueRef; -import middle::trans; +import middle::trans_common; import middle::ty; import syntax::ast; import syntax::codemap::span; -import trans::block_ctxt; -import trans::crate_ctxt; -import trans::fn_ctxt; -import trans::local_ctxt; import util::ppaux; - +import trans_common::*; import std::ivec; import std::option::none; import std::option::some; @@ -25,7 +21,7 @@ import LLFalse = lib::llvm::False; import LLTrue = lib::llvm::True; import ll = lib::llvm; -import lltype_of = trans::val_ty; +import lltype_of = trans_common::val_ty; import option = std::option::t; import tc = trans_common; import type_of_node = trans::node_id_type; @@ -47,7 +43,7 @@ fn llsize_of(&@crate_ctxt ccx, TypeRef llty) -> uint { fn mk_const(&@crate_ctxt ccx, &str name, bool exported, ValueRef llval) -> ValueRef { - auto llglobal = llvm::LLVMAddGlobal(ccx.llmod, trans::val_ty(llval), + auto llglobal = llvm::LLVMAddGlobal(ccx.llmod, tc::val_ty(llval), str::buf(name)); llvm::LLVMSetInitializer(llglobal, llval); @@ -140,23 +136,12 @@ fn dest_is_alias(&dest dest) -> bool { } -// Accessors -// TODO: When we have overloading, simplify these names! - -fn bcx_tcx(&@block_ctxt bcx) -> ty::ctxt { ret bcx.fcx.lcx.ccx.tcx; } -fn bcx_ccx(&@block_ctxt bcx) -> @crate_ctxt { ret bcx.fcx.lcx.ccx; } -fn bcx_lcx(&@block_ctxt bcx) -> @local_ctxt { ret bcx.fcx.lcx; } -fn bcx_fcx(&@block_ctxt bcx) -> @fn_ctxt { ret bcx.fcx; } -fn lcx_ccx(&@local_ctxt lcx) -> @crate_ctxt { ret lcx.ccx; } -fn ccx_tcx(&@crate_ctxt ccx) -> ty::ctxt { ret ccx.tcx; } - - // Common operations fn memmove(&@block_ctxt bcx, ValueRef lldestptr, ValueRef llsrcptr, ValueRef llsz) { - auto lldestty = llelement_type(trans::val_ty(lldestptr)); - auto llsrcty = llelement_type(trans::val_ty(llsrcptr)); + auto lldestty = llelement_type(tc::val_ty(lldestptr)); + auto llsrcty = llelement_type(tc::val_ty(llsrcptr)); auto dest_align = llalign_of(bcx_ccx(bcx), lldestty); auto src_align = llalign_of(bcx_ccx(bcx), llsrcty); auto align = uint::min(dest_align, src_align); @@ -205,7 +190,7 @@ fn store_ptr(&@block_ctxt bcx, &dest dest, ValueRef llsrcptr) -> @block_ctxt { *box = some(llsrcptr); } dst_copy(?lldestptr) | dst_move(?lldestptr) { - auto llsrcty = llelement_type(trans::val_ty(llsrcptr)); + auto llsrcty = llelement_type(tc::val_ty(llsrcptr)); auto llsz = tc::C_uint(llsize_of(bcx_ccx(bcx), llsrcty)); memmove(bcx, lldestptr, llsrcptr, llsz); ret bcx; @@ -421,7 +406,7 @@ fn get_upcall(&@crate_ctxt ccx, &span sp, ty::t t) ~[bcx_fcx(bcx).lltaskptr, tc::C_int(level), llarg]); log_bcx = trans::trans_block_cleanups(log_bcx, - trans::find_scope_cx(log_bcx)); + tc::find_scope_cx(log_bcx)); log_bcx.build.Br(next_bcx.llbb); ret next_bcx; } @@ -481,7 +466,7 @@ fn trans_block(&@block_ctxt cx, &dest dest, &ast::block block) none { /* no-op */ } } - bcx = trans::trans_block_cleanups(bcx, trans::find_scope_cx(bcx)); + bcx = trans::trans_block_cleanups(bcx, tc::find_scope_cx(bcx)); ret bcx; } @@ -583,7 +568,7 @@ fn trans_init_local(&@block_ctxt bcx, &@ast::local local) -> @block_ctxt { auto llptr = bcx_fcx(bcx).lllocals.get(local.node.id); auto t = type_of_node(bcx_ccx(bcx), local.node.id); - trans::add_clean(bcx, llptr, t); + tc::add_clean(bcx, llptr, t); alt (local.node.init) { some(?init) { diff --git a/src/comp/middle/trans_vec.rs b/src/comp/middle/trans_vec.rs index 6d93b4cc392..1707c085869 100644 --- a/src/comp/middle/trans_vec.rs +++ b/src/comp/middle/trans_vec.rs @@ -10,11 +10,11 @@ import syntax::ast; import syntax::codemap::span; import trans::alloca; -import trans::block_ctxt; import trans::load_inbounds; import trans::new_sub_block_ctxt; -import trans::struct_elt; import trans::type_of_or_i8; +import trans_common::block_ctxt; +import trans_common::struct_elt; import trans_common::C_int; import trans_common::C_null; import trans_common::C_uint; @@ -23,8 +23,8 @@ import trans_common::T_ivec_heap_part; import trans_common::T_opaque_ivec; import trans_common::T_ptr; -import trans_dps::bcx_ccx; -import trans_dps::bcx_tcx; +import trans_common::bcx_ccx; +import trans_common::bcx_tcx; import trans_dps::dest; import trans_dps::llsize_of; import trans_dps::mk_temp; -- GitLab