Move the glue code to a .o file. This reduces how much asm we print

in each "translation unit".

Part of it is not repetitive and should probably be moved to a .ll file, but
for now we autogen all of it.

(Modified somewhat by graydon while integrating).
This commit is contained in:
Graydon Hoare 2011-03-10 17:25:11 -08:00
parent 7454b53411
commit 3aac5059ee
3 changed files with 123 additions and 72 deletions

View file

@ -86,7 +86,6 @@ ifdef CFG_WINDOWSY
endif
CFG_RUNTIME := rustrt.dll
CFG_STDLIB := std.dll
CFG_OBJ_SUFFIX := .o
CFG_EXE_SUFFIX := .exe
CFG_BOOT := ./rustboot.exe
CFG_RUSTC := ./rustc.exe
@ -101,7 +100,6 @@ ifdef CFG_UNIXY
CFG_INFO := $(info cfg: unix-y environment)
CFG_BOOT := ./rustboot
CFG_RUSTC := ./rustc
CFG_OBJ_SUFFIX := .o
CFG_RUN_TARG = LD_LIBRARY_PATH=. $(CFG_VALGRIND) $(1)
CFG_GCC := 1
ifdef MINGW_CROSS
@ -114,7 +112,6 @@ ifdef CFG_UNIXY
ifdef CFG_VALGRIND
CFG_VALGRIND += wine
endif
CFG_OBJ_SUFFIX := .o
CFG_EXE_SUFFIX := .exe
CFG_GCC_CFLAGS := -march=i686
CFG_GCC_LINK_FLAGS := -shared
@ -302,15 +299,15 @@ RUNTIME_HDR := rt/globals.h \
rt/test/rust_test_util.h
RUNTIME_INCS := -Irt/isaac -Irt/uthash
RUNTIME_OBJS := $(RUNTIME_CS:.cpp=$(CFG_OBJ_SUFFIX))
RUNTIME_OBJS := $(RUNTIME_CS:.cpp=.o)
RUNTIME_LIBS := $(CFG_RUNTIME_LIBS)
STDLIB_CRATE := lib/std.rc
STDLIB_INPUTS := $(wildcard lib/*.rc lib/*.rs lib/*/*.rs)
COMPILER_CRATE := comp/rustc.rc
COMPILER_INPUTS := $(wildcard comp/*.rc comp/*.rs comp/*/*.rs)
COMPILER_INPUTS := $(wildcard comp/rustc.rc comp/*.rs comp/*/*.rs)
GENERATED := boot/fe/lexer.ml boot/util/version.ml
GENERATED := boot/fe/lexer.ml boot/util/version.ml glue.o
all: $(CFG_RUSTC) $(MKFILES) $(GENERATED)
@ -329,7 +326,7 @@ $(CFG_STDLIB): $(STDLIB_CRATE) $(CFG_BOOT) $(MKFILES)
@$(call CFG_ECHO, compile: $<)
$(BOOT) -shared -o $@ $(STDLIB_CRATE)
%$(CFG_OBJ_SUFFIX): %.cpp $(MKFILES)
%.o: %.cpp $(MKFILES)
@$(call CFG_ECHO, compile: $<)
$(CFG_QUIET)$(call CFG_COMPILE_C, $@, $(RUNTIME_INCS)) $<
@ -368,8 +365,12 @@ $(CFG_RUSTC): $(COMPILER_INPUTS) $(CFG_BOOT) $(CFG_RUNTIME) $(CFG_STDLIB)
$(BOOT) -minimal -o $@ $<
$(CFG_QUIET)chmod 0755 $@
glue.bc: $(CFG_RUSTC)
@$(call CFG_ECHO, generate: $@)
$(RUSTC) -o $@ -glue
self: $(CFG_RUSTC)
@$(call CFG_ECHO, compile: $<)
@$(call CFG_ECHO, compile: $(COMPILER_CRATE))
$(RUSTC) $(COMPILER_CRATE)
@ -758,9 +759,9 @@ test/bench/shootout/%.boot$(CFG_EXE_SUFFIX): \
@$(call CFG_ECHO, assemble [llvm]: $<)
$(CFG_QUIET)gcc $(CFG_GCC_CFLAGS) -o $@ -c $<
%.rustc$(CFG_EXE_SUFFIX): %.o $(CFG_RUNTIME)
%.rustc$(CFG_EXE_SUFFIX): %.o $(CFG_RUNTIME) glue.o
@$(call CFG_ECHO, link [llvm]: $<)
$(CFG_QUIET)gcc $(CFG_GCC_CFLAGS) -o $@ $< -L. -lrustrt
$(CFG_QUIET)gcc $(CFG_GCC_CFLAGS) glue.o -o $@ $< -L. -lrustrt
@# dsymutil sometimes fails or prints a warning, but the
@# program still runs. Since it simplifies debugging other
@# programs, I\'ll live with the noise.
@ -797,7 +798,7 @@ C_DEPFILES := $(RUNTIME_CS:%.cpp=%.d)
%.d: %.cpp $(MKFILES)
@$(call CFG_ECHO, dep: $<)
$(CFG_QUIET)$(call CFG_DEPEND_C, $@ \
$(patsubst %.cpp, %$(CFG_OBJ_SUFFIX), $<), \
$(patsubst %.cpp, %.o, $<), \
$(RUNTIME_INCS)) $< $(CFG_PATH_MUNGE) >$@.tmp \
&& mv $@.tmp $@
@ -914,12 +915,12 @@ clean:
$(CFG_QUIET)rm -f $(ML_DEPFILES:%.d=%.d.tmp)
$(CFG_QUIET)rm -f $(C_DEPFILES:%.d=%.d.tmp)
$(CFG_QUIET)rm -f $(CRATE_DEPFILES:%.d=%.d.tmp)
$(CFG_QUIET)rm -f $(GENERATED)
$(CFG_QUIET)rm -f $(GENERATED) glue.bc glue.s
$(CFG_QUIET)rm -f $(CFG_BOOT) $(CFG_RUNTIME) $(CFG_STDLIB)
$(CFG_QUIET)rm -Rf $(PKG_NAME)-*.tar.gz dist
$(CFG_QUIET)rm -f $(foreach ext,cmx cmi cmo cma o a d exe,\
$(CFG_QUIET)rm -f $(foreach ext,cmx cmi cmo cma bc o a d exe,\
$(wildcard boot/*/*.$(ext) boot/*/*/*.$(ext)))
$(CFG_QUIET)rm -Rf $(foreach ext,out llvm x86 boot rustc o s exe dSYM,\
$(CFG_QUIET)rm -Rf $(foreach ext,out llvm x86 boot rustc bc o s exe dSYM,\
$(wildcard test/*/*.$(ext)))

View file

@ -84,6 +84,7 @@ fn usage(session.session sess, str argv0) {
log "";
log " -o <filename> write output to <filename>";
log " -nowarn suppress wrong-compiler warning";
log " -glue generate glue.bc file";
log " -shared compile a shared-library crate";
log " -pp pretty-print the input instead of compiling";
log " -h display this message";
@ -113,6 +114,7 @@ impure fn main(vec[str] args) {
let bool do_warn = true;
let bool shared = false;
let bool pretty = false;
let bool glue = false;
auto i = 1u;
auto len = _vec.len[str](args);
@ -123,6 +125,8 @@ impure fn main(vec[str] args) {
if (_str.byte_len(arg) > 0u && arg.(0) == '-' as u8) {
if (_str.eq(arg, "-nowarn")) {
do_warn = false;
} else if (_str.eq(arg, "-glue")) {
glue = true;
} else if (_str.eq(arg, "-shared")) {
shared = true;
} else if (_str.eq(arg, "-pp")) {
@ -159,6 +163,18 @@ impure fn main(vec[str] args) {
warn_wrong_compiler();
}
if (glue) {
alt (output_file) {
case (none[str]) {
middle.trans.make_common_glue("glue.bc");
}
case (some[str](?s)) {
middle.trans.make_common_glue(s);
}
}
ret;
}
alt (input_file) {
case (none[str]) {
usage(sess, args.(0));

View file

@ -839,32 +839,44 @@ fn decl_upcall_glue(ModuleRef llmod, type_names tn, uint _n) -> ValueRef {
ret decl_fastcall_fn(llmod, s, T_fn(args, T_int()));
}
fn get_upcall(@crate_ctxt cx, str name, int n_args) -> ValueRef {
if (cx.upcalls.contains_key(name)) {
ret cx.upcalls.get(name);
fn get_upcall(&hashmap[str, ValueRef] upcalls,
type_names tn, ModuleRef llmod,
str name, int n_args) -> ValueRef {
if (upcalls.contains_key(name)) {
ret upcalls.get(name);
}
auto inputs = vec(T_taskptr(cx.tn));
auto inputs = vec(T_taskptr(tn));
inputs += _vec.init_elt[TypeRef](T_int(), n_args as uint);
auto output = T_int();
auto f = decl_cdecl_fn(cx.llmod, name, T_fn(inputs, output));
cx.upcalls.insert(name, f);
auto f = decl_cdecl_fn(llmod, name, T_fn(inputs, output));
upcalls.insert(name, f);
ret f;
}
fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args) -> result {
auto cxx = cx.fcx.ccx;
auto t = trans_upcall2(cx.build, cxx.glues, cx.fcx.lltaskptr,
cxx.upcalls, cxx.tn, cxx.llmod, name, args);
ret res(cx, t);
}
fn trans_upcall2(builder b, @glue_fns glues, ValueRef lltaskptr,
&hashmap[str, ValueRef] upcalls,
type_names tn, ModuleRef llmod, str name,
vec[ValueRef] args) -> ValueRef {
let int n = _vec.len[ValueRef](args) as int;
let ValueRef llupcall = get_upcall(cx.fcx.ccx, name, n);
let ValueRef llupcall = get_upcall(upcalls, tn, llmod, name, n);
llupcall = llvm.LLVMConstPointerCast(llupcall, T_int());
let ValueRef llglue = cx.fcx.ccx.glues.upcall_glues.(n);
let ValueRef llglue = glues.upcall_glues.(n);
let vec[ValueRef] call_args = vec(llupcall);
call_args += cx.build.PtrToInt(cx.fcx.lltaskptr, T_int());
call_args += b.PtrToInt(lltaskptr, T_int());
for (ValueRef a in args) {
call_args += cx.build.ZExtOrBitCast(a, T_int());
call_args += b.ZExtOrBitCast(a, T_int());
}
ret res(cx, cx.build.FastCall(llglue, call_args));
ret b.FastCall(llglue, call_args);
}
fn trans_non_gc_free(@block_ctxt cx, ValueRef v) -> result {
@ -5537,28 +5549,21 @@ fn i2p(ValueRef v, TypeRef t) -> ValueRef {
ret llvm.LLVMConstIntToPtr(v, t);
}
fn trans_exit_task_glue(@crate_ctxt cx) {
fn trans_exit_task_glue(@glue_fns glues,
&hashmap[str, ValueRef] upcalls,
type_names tn, ModuleRef llmod) {
let vec[TypeRef] T_args = vec();
let vec[ValueRef] V_args = vec();
auto llfn = cx.glues.exit_task_glue;
auto llfn = glues.exit_task_glue;
let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 3u);
auto fcx = @rec(llfn=llfn,
lltaskptr=lltaskptr,
llenv=C_null(T_opaque_closure_ptr(cx.tn)),
llretptr=C_null(T_ptr(T_nil())),
mutable llself=none[ValueRef],
mutable lliterbody=none[ValueRef],
llargs=new_def_hash[ValueRef](),
llobjfields=new_def_hash[ValueRef](),
lllocals=new_def_hash[ValueRef](),
llupvars=new_def_hash[ValueRef](),
lltydescs=new_def_hash[ValueRef](),
ccx=cx);
auto bcx = new_top_block_ctxt(fcx);
trans_upcall(bcx, "upcall_exit", V_args);
bcx.build.RetVoid();
auto entrybb = llvm.LLVMAppendBasicBlock(llfn, _str.buf("entry"));
auto build = new_builder(entrybb);
trans_upcall2(build, glues, lltaskptr,
upcalls, tn, llmod, "upcall_exit", V_args);
build.RetVoid();
}
fn create_typedefs(@crate_ctxt cx) {
@ -5567,22 +5572,22 @@ fn create_typedefs(@crate_ctxt cx) {
llvm.LLVMAddTypeName(cx.llmod, _str.buf("tydesc"), T_tydesc(cx.tn));
}
fn create_crate_constant(@crate_ctxt cx) {
fn create_crate_constant(ValueRef crate_ptr, @glue_fns glues) {
let ValueRef crate_addr = p2i(cx.crate_ptr);
let ValueRef crate_addr = p2i(crate_ptr);
let ValueRef activate_glue_off =
llvm.LLVMConstSub(p2i(cx.glues.activate_glue), crate_addr);
llvm.LLVMConstSub(p2i(glues.activate_glue), crate_addr);
let ValueRef yield_glue_off =
llvm.LLVMConstSub(p2i(cx.glues.yield_glue), crate_addr);
llvm.LLVMConstSub(p2i(glues.yield_glue), crate_addr);
let ValueRef exit_task_glue_off =
llvm.LLVMConstSub(p2i(cx.glues.exit_task_glue), crate_addr);
llvm.LLVMConstSub(p2i(glues.exit_task_glue), crate_addr);
let ValueRef crate_val =
C_struct(vec(C_null(T_int()), // ptrdiff_t image_base_off
p2i(cx.crate_ptr), // uintptr_t self_addr
p2i(crate_ptr), // uintptr_t self_addr
C_null(T_int()), // ptrdiff_t debug_abbrev_off
C_null(T_int()), // size_t debug_abbrev_sz
C_null(T_int()), // ptrdiff_t debug_info_off
@ -5598,7 +5603,7 @@ fn create_crate_constant(@crate_ctxt cx) {
C_int(abi.abi_x86_rustc_fastcall) // uintptr_t abi_tag
));
llvm.LLVMSetInitializer(cx.crate_ptr, crate_val);
llvm.LLVMSetInitializer(crate_ptr, crate_val);
}
fn find_main_fn(@crate_ctxt cx) -> ValueRef {
@ -5700,26 +5705,28 @@ fn check_module(ModuleRef llmod) {
// TODO: run the linter here also, once there are llvm-c bindings for it.
}
fn make_no_op_type_glue(ModuleRef llmod, type_names tn) -> ValueRef {
fn decl_no_op_type_glue(ModuleRef llmod, type_names tn) -> ValueRef {
auto ty = T_fn(vec(T_taskptr(tn), T_ptr(T_i8())), T_void());
auto fun = decl_fastcall_fn(llmod, abi.no_op_type_glue_name(), ty);
ret decl_fastcall_fn(llmod, abi.no_op_type_glue_name(), ty);
}
fn make_no_op_type_glue(ValueRef fun) {
auto bb_name = _str.buf("_rust_no_op_type_glue_bb");
auto llbb = llvm.LLVMAppendBasicBlock(fun, bb_name);
new_builder(llbb).RetVoid();
ret fun;
}
fn make_memcpy_glue(ModuleRef llmod) -> ValueRef {
// We're not using the LLVM memcpy intrinsic. It appears to call through
// to the platform memcpy in some cases, which is not terribly safe to run
// on a rust stack.
fn decl_memcpy_glue(ModuleRef llmod) -> ValueRef {
auto p8 = T_ptr(T_i8());
auto ty = T_fn(vec(p8, p8, T_int()), T_void());
auto fun = decl_fastcall_fn(llmod, abi.memcpy_glue_name(), ty);
ret decl_fastcall_fn(llmod, abi.memcpy_glue_name(), ty);
}
fn make_memcpy_glue(ValueRef fun) {
// We're not using the LLVM memcpy intrinsic. It appears to call through
// to the platform memcpy in some cases, which is not terribly safe to run
// on a rust stack.
auto initbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("init"));
auto hdrbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("hdr"));
auto loopbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("loop"));
@ -5751,18 +5758,18 @@ fn make_memcpy_glue(ModuleRef llmod) -> ValueRef {
// End block
auto eb = new_builder(endbb);
eb.RetVoid();
ret fun;
}
fn make_bzero_glue(ModuleRef llmod) -> ValueRef {
// We're not using the LLVM memset intrinsic. Same as with memcpy.
fn decl_bzero_glue(ModuleRef llmod) -> ValueRef {
auto p8 = T_ptr(T_i8());
auto ty = T_fn(vec(p8, T_int()), T_void());
auto fun = decl_fastcall_fn(llmod, abi.bzero_glue_name(), ty);
ret decl_fastcall_fn(llmod, abi.bzero_glue_name(), ty);
}
fn make_bzero_glue(ModuleRef llmod) -> ValueRef {
// We're not using the LLVM memset intrinsic. Same as with memcpy.
auto fun = decl_bzero_glue(llmod);
auto initbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("init"));
auto hdrbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("hdr"));
auto loopbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("loop"));
@ -6008,12 +6015,43 @@ fn make_glues(ModuleRef llmod, type_names tn) -> @glue_fns {
upcall_glues =
_vec.init_fn[ValueRef](bind decl_upcall_glue(llmod, tn, _),
abi.n_upcall_glues as uint),
no_op_type_glue = make_no_op_type_glue(llmod, tn),
memcpy_glue = make_memcpy_glue(llmod),
bzero_glue = make_bzero_glue(llmod),
no_op_type_glue = decl_no_op_type_glue(llmod, tn),
memcpy_glue = decl_memcpy_glue(llmod),
bzero_glue = decl_bzero_glue(llmod),
vec_append_glue = make_vec_append_glue(llmod, tn));
}
fn make_common_glue(str output) {
// FIXME: part of this is repetitive and is probably a good idea
// to autogen it, but things like the memcpy implementation are not
// and it might be better to just check in a .ll file.
auto llmod =
llvm.LLVMModuleCreateWithNameInContext(_str.buf("rust_out"),
llvm.LLVMGetGlobalContext());
llvm.LLVMSetDataLayout(llmod, _str.buf(x86.get_data_layout()));
llvm.LLVMSetTarget(llmod, _str.buf(x86.get_target_triple()));
auto td = mk_target_data(x86.get_data_layout());
auto tn = mk_type_names();
let ValueRef crate_ptr =
llvm.LLVMAddGlobal(llmod, T_crate(tn), _str.buf("rust_crate"));
auto intrinsics = declare_intrinsics(llmod);
llvm.LLVMSetModuleInlineAsm(llmod, _str.buf(x86.get_module_asm()));
auto glues = make_glues(llmod, tn);
create_crate_constant(crate_ptr, glues);
make_memcpy_glue(glues.memcpy_glue);
trans_exit_task_glue(glues, new_str_hash[ValueRef](), tn, llmod);
check_module(llmod);
llvm.LLVMWriteBitcodeToFile(llmod, _str.buf(output));
llvm.LLVMDisposeModule(llmod);
}
fn trans_crate(session.session sess, @ast.crate crate, str output,
bool shared) {
auto llmod =
@ -6027,8 +6065,6 @@ fn trans_crate(session.session sess, @ast.crate crate, str output,
let ValueRef crate_ptr =
llvm.LLVMAddGlobal(llmod, T_crate(tn), _str.buf("rust_crate"));
llvm.LLVMSetModuleInlineAsm(llmod, _str.buf(x86.get_module_asm()));
auto intrinsics = declare_intrinsics(llmod);
auto glues = make_glues(llmod, tn);
@ -6069,9 +6105,7 @@ fn trans_crate(session.session sess, @ast.crate crate, str output,
trans_constants(cx, crate);
trans_mod(cx, crate.node.module);
trans_exit_task_glue(cx);
trans_vec_append_glue(cx);
create_crate_constant(cx);
if (!shared) {
trans_main_fn(cx, cx.crate_ptr);
}