aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGraydon Hoare <[email protected]>2010-12-29 16:27:13 -0800
committerGraydon Hoare <[email protected]>2010-12-29 16:27:19 -0800
commit454bf428efa6f581f94f817d9f044d6934af1a0f (patch)
treee8726997e920a608d80526ea06fa7db9bd599594 /src
parentrustc: Make parametric return types go through an out pointer (diff)
downloadrust-454bf428efa6f581f94f817d9f044d6934af1a0f.tar.xz
rust-454bf428efa6f581f94f817d9f044d6934af1a0f.zip
Remove LLVM rustboot backend.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile162
-rw-r--r--src/boot/driver/llvm/glue.ml39
-rw-r--r--src/boot/llvm/llabi.ml94
-rw-r--r--src/boot/llvm/llasm.ml208
-rw-r--r--src/boot/llvm/llemit.ml36
-rw-r--r--src/boot/llvm/llfinal.ml105
-rw-r--r--src/boot/llvm/lltrans.ml1148
7 files changed, 3 insertions, 1789 deletions
diff --git a/src/Makefile b/src/Makefile
index 040fcdea..a16277f8 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -23,10 +23,6 @@ CFG_GCC_CFLAGS :=
CFG_GCC_LINK_FLAGS :=
CFG_VALGRIND :=
-# Disable the ocaml backend on rustboot. It's too frustrating at this
-# point.
-NO_OCAML_LLVM := 1
-
CFG_LLVM_CONFIG ?= llvm-config
CFG_BOOT_FLAGS := $(FLAGS)
CFG_RUSTC_FLAGS := -nowarn
@@ -145,7 +141,6 @@ ifdef PROFILE
$(info cfg: building with profiling info (forcing native output))
CFG_NATIVE := 1
CFG_OCAMLOPT_PROFILE_FLAGS := -p
- NO_LLVM := 1
endif
ifdef DEBUG
@@ -182,52 +177,13 @@ ifneq ($(CFG_LLVM_CONFIG),)
expected one of $(CFG_LLVM_ALLOWED_VERSIONS))
endif
endif
-ifneq ($(CFG_LLVM_CONFIG),)
- CFG_OCAML_LIBPATH := $(lastword \
- $(shell ocamlc$(OPT) -config | grep standard_library:))
- CFG_OCAML_LLVM := $(shell \
- for path in $(shell $(CFG_LLVM_CONFIG) --libdir)/ocaml \
- $(CFG_OCAML_LIBPATH) \
- $(CFG_OCAML_LIBPATH)/llvm \
- $(CFG_OCAML_LIBPATH)/llvm-$(CFG_LLVM_VERSION) ; do \
- if test -e $${path}/llvm.cma; then echo $${path}; break; fi \
- done)
- ifneq ($(CFG_OCAML_LLVM),)
- $(info cfg: found LLVM ocaml bindings in $(CFG_OCAML_LLVM))
- endif
-endif
-ifdef NO_OCAML_LLVM
- $(info cfg: disabling LLVM ocaml bindings)
- CFG_OCAML_LLVM :=
-endif
+VARIANT=x86
ifdef CFG_LLVM_CONFIG
LLC := "$(shell $(CFG_LLVM_CONFIG) --bindir)/llc"
CFG_LLC_CFLAGS := -march=x86
LLVM-DIS := "$(shell $(CFG_LLVM_CONFIG) --bindir)/llvm-dis"
- ifneq ($(CFG_OCAML_LLVM),)
- VARIANT=llvm
- LLVM_LIBS := llvm.cma llvm_bitwriter.cma
- LLVM_NATIVE_LIBS := llvm.cmxa llvm_bitwriter.cmxa
- LLVM_CLIBS := $(shell for c in `$(CFG_LLVM_CONFIG) --ldflags --libs` \
- -lllvm -lllvm_bitwriter; do echo -cclib && echo $$c; done | xargs echo)
- LLVM_INCS := -I boot/llvm -I $(CFG_OCAML_LLVM)
- LLVM_MLS := $(addprefix boot/llvm/, llabi.ml llasm.ml llfinal.ml \
- lltrans.ml llemit.ml)
- else
- VARIANT=x86
- LLVM_CLIBS :=
- LLVM_INCS :=
- LLVM_MLS :=
- $(info cfg: disabling LLVM ocaml backend)
- endif
-else
- VARIANT=x86
- LLVM_CLIBS :=
- LLVM_INCS :=
- LLVM_MLS :=
- $(info cfg: disabling LLVM backend)
endif
MKFILES := Makefile
@@ -241,7 +197,7 @@ CFG_BOOT_FLAGS += -L .
######################################################################
ML_DEP_INCS := -I boot/fe -I boot/me -I boot/be -I boot/driver/$(VARIANT) \
- -I boot/driver -I boot/util -I boot/llvm
+ -I boot/driver -I boot/util
ML_INCS := $(ML_DEP_INCS) $(LLVM_INCS)
ML_LIBS := unix.cma nums.cma bigarray.cma
ML_NATIVE_LIBS := unix.cmxa nums.cmxa bigarray.cmxa
@@ -249,11 +205,6 @@ OCAMLC_FLAGS := -g $(ML_INCS) -w Ael -warn-error Ael
OCAMLOPT_FLAGS := $(ML_INCS) -w Ael -warn-error Ael \
$(CFG_OCAMLOPT_PROFILE_FLAGS)
-ifdef CFG_LLVM_CONFIG
- ML_LIBS += $(LLVM_LIBS) -custom -cclib -lstdc++ $(LLVM_CLIBS)
- ML_NATIVE_LIBS += $(LLVM_NATIVE_LIBS) -cclib -lstdc++ $(LLVM_CLIBS)
-endif
-
# List them in link order.
# Nobody calculates the link-order DAG automatically, sadly.
@@ -270,7 +221,7 @@ FE_MLS := $(addprefix boot/fe/, ast.ml token.ml lexer.ml parser.ml \
DRIVER_TOP_MLS := $(addprefix boot/driver/, lib.ml $(VARIANT)/glue.ml main.ml)
BOOT_MLS := $(UTIL_BOT_MLS) $(DRIVER_BOT_MLS) $(FE_MLS) $(IL_MLS) $(ME_MLS) \
- $(BE_MLS) $(LLVM_MLS) $(DRIVER_TOP_MLS)
+ $(BE_MLS) $(DRIVER_TOP_MLS)
BOOT_CMOS := $(BOOT_MLS:.ml=.cmo)
BOOT_CMXS := $(BOOT_MLS:.ml=.cmx)
BOOT_OBJS := $(BOOT_MLS:.ml=.o)
@@ -458,59 +409,6 @@ TEST_XFAILS_X86 := $(TASK_XFAILS) \
test/compile-fail/infinite-vec-type-recursion.rs \
test/compile-fail/writing-through-read-alias.rs
-# Most tests fail on the boot-llvm backend, so we list the run-pass
-# xfails inside-out, by listing those that *don't* fail. A bit
-# double-negative-y but it's a bit unwieldy the other way just now.
-
-TEST_XFAILS_LLVM := $(TASK_XFAILS) \
- $(NOMINAL_TAG_XFAILS) \
- $(CONST_TAG_XFAILS) \
- $(filter-out \
- $(addprefix test/run-pass/, \
- arith-0.rs \
- arith-2.rs \
- box.rs \
- char.rs \
- dead-code-one-arm-if.rs \
- div-mod.rs \
- drop-on-ret.rs \
- else-if.rs \
- fact.rs \
- generic-fn-twice.rs \
- generic-type.rs \
- generic-type-synonym.rs \
- hello.rs \
- inner-module.rs \
- int.rs \
- item-name-overload.rs \
- multiline-comment.rs \
- native.rs \
- native-mod.rs \
- native-opaque-type.rs \
- opeq.rs \
- return-nil.rs \
- syntax-extension-shell.rs \
- tup.rs), \
- $(wildcard test/run-pass/*.rs) ) \
- $(addprefix test/run-fail/, \
- explicit-fail.rs \
- fail.rs \
- linked-failure.rs \
- non-exhaustive-match.rs \
- pred.rs \
- str-overrun.rs \
- vec-overrun.rs \
- vec-underrun.rs \
- task-comm-14.rs \
- ) \
- $(addprefix test/compile-fail/, \
- bad-recv.rs \
- bad-send.rs \
- infinite-vec-type-recursion.rs \
- rec-missing-fields.rs \
- writing-through-read-alias.rs \
- )
-
# Same strategy here for the time being: just list the ones that
# work and assume the others don't. Invert this when we're closer
# to actually bootstrapping.
@@ -578,12 +476,10 @@ TEST_XFAILS_SELF := $(filter-out \
ifdef MINGW_CROSS
TEST_XFAILS_X86 += test/run-pass/native-mod.rc
-TEST_XFAILS_LLVM += test/run-pass/native-mod.rc
TEST_XFAILS_SELF += test/run-pass/native-mod.rc
endif
ifdef CFG_WINDOWSY
TEST_XFAILS_X86 += test/run-pass/native-mod.rc
-TEST_XFAILS_LLVM += test/run-pass/native-mod.rc
TEST_XFAILS_SELF += test/run-pass/native-mod.rc
endif
@@ -596,105 +492,76 @@ CFAIL_RS := $(wildcard test/compile-fail/*.rs)
ifdef CHECK_XFAILS
TEST_RPASS_CRATES_X86 := $(filter $(TEST_XFAILS_X86), $(RPASS_RC))
-TEST_RPASS_CRATES_LLVM := $(filter $(TEST_XFAILS_LLVM), $(RPASS_RC))
TEST_RPASS_CRATES_SELF := $(filter $(TEST_XFAILS_SELF), $(RPASS_RC))
TEST_RPASS_SOURCES_X86 := $(filter $(TEST_XFAILS_X86), $(RPASS_RS))
-TEST_RPASS_SOURCES_LLVM := $(filter $(TEST_XFAILS_LLVM), $(RPASS_RS))
TEST_RPASS_SOURCES_SELF := $(filter $(TEST_XFAILS_SELF), $(RPASS_RS))
else
TEST_RPASS_CRATES_X86 := $(filter-out $(TEST_XFAILS_X86), $(RPASS_RC))
-TEST_RPASS_CRATES_LLVM := $(filter-out $(TEST_XFAILS_LLVM), $(RPASS_RC))
TEST_RPASS_CRATES_SELF := $(filter-out $(TEST_XFAILS_SELF), $(RPASS_RC))
TEST_RPASS_SOURCES_X86 := $(filter-out $(TEST_XFAILS_X86), $(RPASS_RS))
-TEST_RPASS_SOURCES_LLVM := $(filter-out $(TEST_XFAILS_LLVM), $(RPASS_RS))
TEST_RPASS_SOURCES_SELF := $(filter-out $(TEST_XFAILS_SELF), $(RPASS_RS))
endif
TEST_RPASS_EXES_X86 := \
$(TEST_RPASS_CRATES_X86:.rc=-boot.x86$(CFG_EXE_SUFFIX)) \
$(TEST_RPASS_SOURCES_X86:.rs=-boot.x86$(CFG_EXE_SUFFIX))
-TEST_RPASS_EXES_LLVM := \
- $(TEST_RPASS_CRATES_LLVM:.rc=-boot.llvm$(CFG_EXE_SUFFIX)) \
- $(TEST_RPASS_SOURCES_LLVM:.rs=-boot.llvm$(CFG_EXE_SUFFIX))
TEST_RPASS_EXES_SELF := \
$(TEST_RPASS_CRATES_SELF:.rc=.llvm$(CFG_EXE_SUFFIX)) \
$(TEST_RPASS_SOURCES_SELF:.rs=.llvm$(CFG_EXE_SUFFIX))
TEST_RPASS_OUTS_X86 := \
$(TEST_RPASS_EXES_X86:.x86$(CFG_EXE_SUFFIX)=.x86.out)
-TEST_RPASS_OUTS_LLVM := \
- $(TEST_RPASS_EXES_LLVM:.llvm$(CFG_EXE_SUFFIX)=.llvm.out)
TEST_RPASS_OUTS_SELF := \
$(TEST_RPASS_EXES_SELF:.llvm$(CFG_EXE_SUFFIX)=.llvm.out)
TEST_RPASS_TMPS_X86 := \
$(TEST_RPASS_EXES_X86:.x86$(CFG_EXE_SUFFIX)=.x86$(CFG_EXE_SUFFIX).tmp)
-TEST_RPASS_TMPS_LLVM := \
- $(TEST_RPASS_EXES_LLVM:.llvm$(CFG_EXE_SUFFIX)=.llvm$(CFG_EXE_SUFFIX).tmp)
TEST_RPASS_TMPS_SELF := \
$(TEST_RPASS_EXES_SELF:.llvm$(CFG_EXE_SUFFIX)=.llvm$(CFG_EXE_SUFFIX).tmp)
TEST_RFAIL_CRATES_X86 := $(filter-out $(TEST_XFAILS_X86), $(RFAIL_RC))
-TEST_RFAIL_CRATES_LLVM := $(filter-out $(TEST_XFAILS_LLVM), $(RFAIL_RC))
TEST_RFAIL_CRATES_SELF := $(filter-out $(TEST_XFAILS_SELF), $(RFAIL_RC))
TEST_RFAIL_SOURCES_X86 := $(filter-out $(TEST_XFAILS_X86), $(RFAIL_RS))
-TEST_RFAIL_SOURCES_LLVM := $(filter-out $(TEST_XFAILS_LLVM), $(RFAIL_RS))
TEST_RFAIL_SOURCES_SELF := $(filter-out $(TEST_XFAILS_SELF), $(RFAIL_RS))
TEST_RFAIL_EXES_X86 := \
$(TEST_RFAIL_CRATES_X86:.rc=-boot.x86$(CFG_EXE_SUFFIX)) \
$(TEST_RFAIL_SOURCES_X86:.rs=-boot.x86$(CFG_EXE_SUFFIX))
-TEST_RFAIL_EXES_LLVM := \
- $(TEST_RFAIL_CRATES_LLVM:.rc=-boot.llvm$(CFG_EXE_SUFFIX)) \
- $(TEST_RFAIL_SOURCES_LLVM:.rs=-boot.llvm$(CFG_EXE_SUFFIX))
TEST_RFAIL_EXES_SELF := \
$(TEST_RFAIL_CRATES_SELF:.rc=-boot.llvm$(CFG_EXE_SUFFIX)) \
$(TEST_RFAIL_SOURCES_SELF:.rs=-boot.llvm$(CFG_EXE_SUFFIX))
TEST_RFAIL_OUTS_X86 := \
$(TEST_RFAIL_EXES_X86:.x86$(CFG_EXE_SUFFIX)=.x86.out)
-TEST_RFAIL_OUTS_LLVM := \
- $(TEST_RFAIL_EXES_LLVM:.llvm$(CFG_EXE_SUFFIX)=.llvm.out)
TEST_RFAIL_OUTS_SELF := \
$(TEST_RFAIL_EXES_SELF:.llvm$(CFG_EXE_SUFFIX)=.llvm.out)
TEST_RFAIL_TMPS_X86 := \
$(TEST_RFAIL_EXES_X86:.x86$(CFG_EXE_SUFFIX)=.x86$(CFG_EXE_SUFFIX).tmp)
-TEST_RFAIL_TMPS_LLVM := \
- $(TEST_RFAIL_EXES_LLVM:.llvm$(CFG_EXE_SUFFIX)=.llvm$(CFG_EXE_SUFFIX).tmp)
TEST_RFAIL_TMPS_SELF := \
$(TEST_RFAIL_EXES_SELF:.llvm$(CFG_EXE_SUFFIX)=.llvm$(CFG_EXE_SUFFIX).tmp)
TEST_CFAIL_CRATES_X86 := $(filter-out $(TEST_XFAILS_X86), $(CFAIL_RC))
-TEST_CFAIL_CRATES_LLVM := $(filter-out $(TEST_XFAILS_LLVM), $(CFAIL_RC))
TEST_CFAIL_CRATES_SELF := $(filter-out $(TEST_XFAILS_SELF), $(CFAIL_RC))
TEST_CFAIL_SOURCES_X86 := $(filter-out $(TEST_XFAILS_X86), $(CFAIL_RS))
-TEST_CFAIL_SOURCES_LLVM := $(filter-out $(TEST_XFAILS_LLVM), $(CFAIL_RS))
TEST_CFAIL_SOURCES_SELF := $(filter-out $(TEST_XFAILS_SELF), $(CFAIL_RS))
TEST_CFAIL_EXES_X86 := \
$(TEST_CFAIL_CRATES_X86:.rc=-boot.x86$(CFG_EXE_SUFFIX)) \
$(TEST_CFAIL_SOURCES_X86:.rs=-boot.x86$(CFG_EXE_SUFFIX))
-TEST_CFAIL_EXES_LLVM := \
- $(TEST_CFAIL_CRATES_LLVM:.rc=-boot.llvm$(CFG_EXE_SUFFIX)) \
- $(TEST_CFAIL_SOURCES_LLVM:.rs=-boot.llvm$(CFG_EXE_SUFFIX))
TEST_CFAIL_EXES_SELF := \
$(TEST_CFAIL_CRATES_SELF:.rc=.llvm$(CFG_EXE_SUFFIX)) \
$(TEST_CFAIL_SOURCES_SELF:.rs=.llvm$(CFG_EXE_SUFFIX))
TEST_CFAIL_OUTS_X86 := \
$(TEST_CFAIL_EXES_X86:.x86$(CFG_EXE_SUFFIX)=.x86.out)
-TEST_CFAIL_OUTS_LLVM := \
- $(TEST_CFAIL_EXES_LLVM:.llvm$(CFG_EXE_SUFFIX)=.llvm.out)
TEST_CFAIL_OUTS_SELF := \
$(TEST_CFAIL_EXES_SELF:.llvm$(CFG_EXE_SUFFIX)=.llvm.out)
TEST_CFAIL_TMPS_X86 := \
$(TEST_CFAIL_EXES_X86:.x86$(CFG_EXE_SUFFIX)=.x86$(CFG_EXE_SUFFIX).tmp)
-TEST_CFAIL_TMPS_LLVM := \
- $(TEST_CFAIL_EXES_LLVM:.llvm$(CFG_EXE_SUFFIX)=.llvm$(CFG_EXE_SUFFIX).tmp)
TEST_CFAIL_TMPS_SELF := \
$(TEST_CFAIL_EXES_SELF:.llvm$(CFG_EXE_SUFFIX)=.llvm$(CFG_EXE_SUFFIX).tmp)
@@ -723,28 +590,6 @@ compile-check: tidy \
ifdef CFG_LLVM_CONFIG
-ifneq ($(CFG_OCAML_LLVM),)
-
-ALL_TEST_CRATES += $(TEST_CFAIL_CRATES_LLVM) \
- $(TEST_RFAIL_CRATES_LLVM) \
- $(TEST_RPASS_CRATES_LLVM)
-
-ALL_TEST_SOURCES += $(TEST_CFAIL_SOURCES_LLVM) \
- $(TEST_RFAIL_SOURCES_LLVM) \
- $(TEST_RPASS_SOURCES_LLVM)
-
-check_nocompile: $(TEST_CFAIL_OUTS_LLVM)
-
-check: tidy \
- $(TEST_RPASS_EXES_LLVM) $(TEST_RFAIL_EXES_LLVM) \
- $(TEST_RPASS_OUTS_LLVM) $(TEST_RFAIL_OUTS_LLVM) \
- $(TEST_CFAIL_OUTS_LLVM)
-
-compile-check: tidy \
- $(TEST_RPASS_EXES_LLVM) $(TEST_RFAIL_EXES_LLVM)
-
-endif
-
ALL_TEST_CRATES += $(TEST_CFAIL_CRATES_SELF) \
$(TEST_RFAIL_CRATES_SELF) \
$(TEST_RPASS_CRATES_SELF)
@@ -761,7 +606,6 @@ check: tidy \
$(TEST_CFAIL_OUTS_SELF)
compile-check: tidy \
- $(TEST_RPASS_EXES_LLVM) $(TEST_RFAIL_EXES_LLVM) \
$(TEST_RPASS_EXES_SELF) $(TEST_RFAIL_EXES_SELF)
endif
diff --git a/src/boot/driver/llvm/glue.ml b/src/boot/driver/llvm/glue.ml
deleted file mode 100644
index c1dc2894..00000000
--- a/src/boot/driver/llvm/glue.ml
+++ /dev/null
@@ -1,39 +0,0 @@
-(*
- * Glue for the LLVM backend.
- *)
-
-let alt_argspecs sess = [
- ("-llvm", Arg.Unit (fun _ -> sess.Session.sess_alt_backend <- true),
- "emit LLVM bitcode")
-];;
-
-let alt_pipeline sess sem_cx crate =
- let process processor =
- processor sem_cx crate;
- if sess.Session.sess_failed then exit 1 else ()
- in
- Array.iter process
- [|
- Resolve.process_crate;
- Simplify.process_crate;
- Type.process_crate;
- Typestate.process_crate;
- Layer.process_crate;
- Effect.process_crate;
- Loop.process_crate;
- Alias.process_crate;
- Dead.process_crate;
- Layout.process_crate
- |];
- Llemit.trans_and_process_crate sess sem_cx crate
-;;
-
-(*
- * Local Variables:
- * fill-column: 78;
- * indent-tabs-mode: nil
- * buffer-file-coding-system: utf-8-unix
- * compile-command: "make -k -C ../../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
- * End:
- *)
-
diff --git a/src/boot/llvm/llabi.ml b/src/boot/llvm/llabi.ml
deleted file mode 100644
index 5ff63ba5..00000000
--- a/src/boot/llvm/llabi.ml
+++ /dev/null
@@ -1,94 +0,0 @@
-(*
- * LLVM integration with the Rust runtime.
- *)
-
-type abi = {
- crate_ty: Llvm.lltype;
- task_ty: Llvm.lltype;
- word_ty: Llvm.lltype;
- tydesc_ty: Llvm.lltype;
- rust_start: Llvm.llvalue;
-};;
-
-let declare_abi (llctx:Llvm.llcontext) (llmod:Llvm.llmodule) : abi =
- let i32 = Llvm.i32_type llctx in
- (* FIXME: Use Llvm_target.intptr_type for more platform support. *)
- let word_ty = i32 in
- let p ty = Llvm.pointer_type ty in
-
- let crate_ty =
- (* TODO: other architectures besides x86 *)
- let crate_opaque_ty = Llvm.opaque_type llctx in
- let crate_tyhandle = Llvm.handle_to_type (Llvm.struct_type llctx [|
- i32; (* ptrdiff_t image_base_off *)
- Llvm.pointer_type crate_opaque_ty;(* uintptr_t self_addr *)
- i32; (* ptrdiff_t debug_abbrev_off *)
- i32; (* size_t debug_abbrev_sz *)
- i32; (* ptrdiff_t debug_info_off *)
- i32; (* size_t debug_info_sz *)
- i32; (* size_t activate_glue_off *)
- i32; (* size_t yield_glue_off *)
- i32; (* size_t unwind_glue_off *)
- i32; (* size_t gc_glue_off *)
- i32; (* size_t main_exit_task_glue_off *)
- i32; (* int n_rust_syms *)
- i32; (* int n_c_syms *)
- i32 (* int n_libs *)
- |])
- in
- Llvm.refine_type crate_opaque_ty (Llvm.type_of_handle crate_tyhandle);
- Llvm.type_of_handle crate_tyhandle
- in
- ignore (Llvm.define_type_name "rust_crate" crate_ty llmod);
-
- let task_ty =
- (* TODO: other architectures besides x86 *)
- Llvm.struct_type llctx [|
- i32; (* size_t refcnt *)
- Llvm.pointer_type i32; (* rust_task *_delegate *)
- Llvm.pointer_type i32; (* stk_seg *stk *)
- Llvm.pointer_type i32; (* uintptr_t runtime_sp *)
- Llvm.pointer_type i32; (* uintptr_t rust_sp *)
- Llvm.pointer_type i32; (* rust_rt *rt *)
- Llvm.pointer_type i32 (* rust_crate_cache *cache *)
- |]
- in
- ignore (Llvm.define_type_name "rust_task" task_ty llmod);
-
- (* This is the type_desc struct in rust_internal.h *)
- let tydesc_ty =
- (* TODO: other architectures besides x86 *)
- let tydesc_opaque_ty = Llvm.opaque_type llctx in
- let tydesc_tyhandle = Llvm.handle_to_type (Llvm.struct_type llctx [|
- p (p tydesc_opaque_ty); (* const type_desc **first_param *)
- word_ty; (* size_t size *)
- word_ty; (* size_t align *)
- word_ty; (* uintptr_t copy_glue_off *)
- word_ty; (* uintptr_t drop_glue_off *)
- word_ty; (* uintptr_t free_glue_off *)
- word_ty; (* uintptr_t sever_glue_off *)
- word_ty; (* uintptr_t mark_glue_off *)
- word_ty; (* uintptr_t obj_drop_glue_off *)
- |])
- in
- Llvm.refine_type tydesc_opaque_ty (Llvm.type_of_handle tydesc_tyhandle);
- Llvm.type_of_handle tydesc_tyhandle
- in
- ignore (Llvm.define_type_name "type_desc" tydesc_ty llmod);
-
- let rust_start_ty =
- (* Rust's main function can have several types, so we cast them
- all to uintptr_t. *)
- let main_ty = word_ty in
- let args_ty = [| main_ty; Llvm.pointer_type crate_ty; i32; i32 |] in
- Llvm.function_type i32 args_ty
- in
- {
- crate_ty = crate_ty;
- task_ty = task_ty;
- word_ty = word_ty;
- tydesc_ty = tydesc_ty;
- rust_start = Llvm.declare_function "rust_start" rust_start_ty llmod
- }
-;;
-
diff --git a/src/boot/llvm/llasm.ml b/src/boot/llvm/llasm.ml
deleted file mode 100644
index 70cf2470..00000000
--- a/src/boot/llvm/llasm.ml
+++ /dev/null
@@ -1,208 +0,0 @@
-(*
- * machine-specific assembler routines.
- *)
-
-open Common;;
-
-type asm_glue =
- {
- asm_activate_glue : Llvm.llvalue;
- asm_yield_glue : Llvm.llvalue;
- asm_upcall_glues : Llvm.llvalue array;
- }
-;;
-
-let n_upcall_glues = 7
-;;
-
-(* x86-specific asm. *)
-
-let x86_glue
- (llctx:Llvm.llcontext)
- (llmod:Llvm.llmodule)
- (abi:Llabi.abi)
- (sess:Session.sess)
- : asm_glue =
- let (prefix,align) =
- match sess.Session.sess_targ with
- Linux_x86_elf -> ("", 4)
- | Win32_x86_pe -> ("_",4)
- | MacOS_x86_macho -> ("_", 16)
- in
- let save_callee_saves =
- ["pushl %ebp";
- "pushl %edi";
- "pushl %esi";
- "pushl %ebx";]
- in
- let restore_callee_saves =
- ["popl %ebx";
- "popl %esi";
- "popl %edi";
- "popl %ebp";]
- in
- let load_esp_from_rust_sp =
- [ Printf.sprintf "movl %d(%%edx), %%esp"
- (Abi.task_field_rust_sp * 4)]
- in
- let load_esp_from_runtime_sp =
- [ Printf.sprintf "movl %d(%%edx), %%esp"
- (Abi.task_field_runtime_sp * 4) ]
- in
- let store_esp_to_rust_sp =
- [ Printf.sprintf "movl %%esp, %d(%%edx)"
- (Abi.task_field_rust_sp * 4) ]
- in
- let store_esp_to_runtime_sp =
- [ Printf.sprintf "movl %%esp, %d(%%edx)"
- (Abi.task_field_runtime_sp * 4) ]
- in
-
- let list_init i f = (Array.to_list (Array.init i f)) in
- let list_init_concat i f = List.concat (list_init i f) in
-
- let glue =
- [
- ("rust_activate_glue",
- String.concat "\n\t"
- (["movl 4(%esp), %edx # edx = rust_task"]
- @ save_callee_saves
- @ store_esp_to_runtime_sp
- @ load_esp_from_rust_sp
- (*
- * This 'add' instruction is a bit surprising.
- * See lengthy comment in boot/be/x86.ml activate_glue.
- *)
- @ [ Printf.sprintf
- "addl $20, %d(%%edx)"
- (Abi.task_field_rust_sp * 4) ]
-
- @ restore_callee_saves
- @ ["ret"]));
-
- ("rust_yield_glue",
- String.concat "\n\t"
-
- (["movl 0(%esp), %edx # edx = rust_task"]
- @ load_esp_from_rust_sp
- @ save_callee_saves
- @ store_esp_to_rust_sp
- @ load_esp_from_runtime_sp
- @ restore_callee_saves
- @ ["ret"]))
- ]
- @ list_init n_upcall_glues
- begin
- fun i ->
- (*
- * 0, 4, 8, 12 are callee-saves
- * 16 is retpc
- * 20 is taskptr
- * 24 is callee
- * 28 .. (7+i) * 4 are args
- *)
-
- ((Printf.sprintf "rust_upcall_%d" i),
- String.concat "\n\t"
- (save_callee_saves
- @ ["movl %esp, %ebp # ebp = rust_sp";
- "movl 20(%esp), %edx # edx = rust_task"]
- @ store_esp_to_rust_sp
- @ load_esp_from_runtime_sp
- @ [Printf.sprintf
- "subl $%d, %%esp # esp -= args" ((i+1)*4);
- "andl $~0xf, %esp # align esp down";
- "movl %edx, (%esp) # arg[0] = rust_task "]
-
- @ (list_init_concat i
- begin
- fun j ->
- [ Printf.sprintf "movl %d(%%ebp),%%edx" ((j+7)*4);
- Printf.sprintf "movl %%edx,%d(%%esp)" ((j+1)*4) ]
- end)
-
- @ ["movl 24(%ebp), %edx # edx = callee";
- "call *%edx # call *%edx";
- "movl 20(%ebp), %edx # edx = rust_task"]
- @ load_esp_from_rust_sp
- @ restore_callee_saves
- @ ["ret"]))
- end
- in
-
- let _ =
- Llvm.set_module_inline_asm llmod
- begin
- String.concat "\n"
- begin
- List.map
- begin
- fun (sym,asm) ->
- Printf.sprintf
- "\t.globl %s%s\n\t.balign %d\n%s%s:\n\t%s"
- prefix sym align prefix sym asm
- end
- glue
- end
- end
- in
-
- let decl_cdecl_fn name out_ty arg_tys =
- let ty = Llvm.function_type out_ty arg_tys in
- let fn = Llvm.declare_function name ty llmod in
- Llvm.set_function_call_conv Llvm.CallConv.c fn;
- fn
- in
-
- let decl_glue s =
- let task_ptr_ty = Llvm.pointer_type abi.Llabi.task_ty in
- let void_ty = Llvm.void_type llctx in
- decl_cdecl_fn s void_ty [| task_ptr_ty |]
- in
-
- let decl_upcall n =
- let task_ptr_ty = Llvm.pointer_type abi.Llabi.task_ty in
- let word_ty = abi.Llabi.word_ty in
- let callee_ty = word_ty in
- let args_ty =
- Array.append
- [| task_ptr_ty; callee_ty |]
- (Array.init n (fun _ -> word_ty))
- in
- let name = Printf.sprintf "rust_upcall_%d" n in
- decl_cdecl_fn name word_ty args_ty
- in
- {
- asm_activate_glue = decl_glue "rust_activate_glue";
- asm_yield_glue = decl_glue "rust_yield_glue";
- asm_upcall_glues = Array.init n_upcall_glues decl_upcall;
- }
-;;
-
-(* x64-specific asm. *)
-(* arm-specific asm. *)
-(* ... *)
-
-
-let get_glue
- (llctx:Llvm.llcontext)
- (llmod:Llvm.llmodule)
- (abi:Llabi.abi)
- (sess:Session.sess)
- : asm_glue =
- match sess.Session.sess_targ with
- Linux_x86_elf
- | Win32_x86_pe
- | MacOS_x86_macho ->
- x86_glue llctx llmod abi sess
-;;
-
-
-(*
- * Local Variables:
- * fill-column: 78;
- * indent-tabs-mode: nil
- * buffer-file-coding-system: utf-8-unix
- * compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
- * End:
- *)
diff --git a/src/boot/llvm/llemit.ml b/src/boot/llvm/llemit.ml
deleted file mode 100644
index 2b229fde..00000000
--- a/src/boot/llvm/llemit.ml
+++ /dev/null
@@ -1,36 +0,0 @@
-(*
- * LLVM emitter.
- *)
-
-(* The top-level interface to the LLVM translation subsystem. *)
-let trans_and_process_crate
- (sess:Session.sess)
- (sem_cx:Semant.ctxt)
- (crate:Ast.crate)
- : unit =
- let llcontext = Llvm.create_context () in
- let emit_file (llmod:Llvm.llmodule) : unit =
- let filename = Session.filename_of sess.Session.sess_out in
- if not (Llvm_bitwriter.write_bitcode_file llmod filename)
- then raise (Failure ("failed to write the LLVM bitcode '" ^ filename
- ^ "'"))
- in
- let llmod = Lltrans.trans_crate sem_cx llcontext sess crate in
- begin
- try
- emit_file llmod
- with e -> Llvm.dispose_module llmod; raise e
- end;
- Llvm.dispose_module llmod;
- Llvm.dispose_context llcontext
-;;
-
-(*
- * Local Variables:
- * fill-column: 78;
- * indent-tabs-mode: nil
- * buffer-file-coding-system: utf-8-unix
- * compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
- * End:
- *)
-
diff --git a/src/boot/llvm/llfinal.ml b/src/boot/llvm/llfinal.ml
deleted file mode 100644
index a7e190cd..00000000
--- a/src/boot/llvm/llfinal.ml
+++ /dev/null
@@ -1,105 +0,0 @@
-(*
- * LLVM ABI-level stuff that needs to happen after modules have been
- * translated.
- *)
-
-let finalize_module
- (sess:Session.sess)
- (llctx:Llvm.llcontext)
- (llmod:Llvm.llmodule)
- (abi:Llabi.abi)
- (asm_glue:Llasm.asm_glue)
- (exit_task_glue:Llvm.llvalue)
- (crate_ptr:Llvm.llvalue)
- : unit =
- let i32 = Llvm.i32_type llctx in
-
- (*
- * Count the number of Rust functions and the number of C functions by
- * simply (and crudely) testing whether each function in the module begins
- * with "_rust_".
- *)
-
- let (rust_fn_count, c_fn_count) =
- let count (rust_fn_count, c_fn_count) fn =
- let begins_with prefix str =
- let (str_len, prefix_len) =
- (String.length str, String.length prefix)
- in
- prefix_len <= str_len && (String.sub str 0 prefix_len) = prefix
- in
- if begins_with "_rust_" (Llvm.value_name fn) then
- (rust_fn_count + 1, c_fn_count)
- else
- (rust_fn_count, c_fn_count + 1)
- in
- Llvm.fold_left_functions count (0, 0) llmod
- in
-
- let crate_val =
- let crate_addr = Llvm.const_ptrtoint crate_ptr i32 in
- let glue_off glue =
- let addr = Llvm.const_ptrtoint glue i32 in
- Llvm.const_sub addr crate_addr
- in
- let activate_glue_off = glue_off asm_glue.Llasm.asm_activate_glue in
- let yield_glue_off = glue_off asm_glue.Llasm.asm_yield_glue in
- let exit_task_glue_off = glue_off exit_task_glue in
-
- Llvm.const_struct llctx [|
- Llvm.const_int i32 0; (* ptrdiff_t image_base_off *)
- crate_ptr; (* uintptr_t self_addr *)
- Llvm.const_int i32 0; (* ptrdiff_t debug_abbrev_off *)
- Llvm.const_int i32 0; (* size_t debug_abbrev_sz *)
- Llvm.const_int i32 0; (* ptrdiff_t debug_info_off *)
- Llvm.const_int i32 0; (* size_t debug_info_sz *)
- activate_glue_off; (* size_t activate_glue_off *)
- yield_glue_off; (* size_t yield_glue_off *)
- Llvm.const_int i32 0; (* size_t unwind_glue_off *)
- Llvm.const_int i32 0; (* size_t gc_glue_off *)
- exit_task_glue_off; (* size_t main_exit_task_glue_off *)
- Llvm.const_int i32 rust_fn_count; (* int n_rust_syms *)
- Llvm.const_int i32 c_fn_count; (* int n_c_syms *)
- Llvm.const_int i32 0 (* int n_libs *)
- |]
- in
-
- Llvm.set_initializer crate_val crate_ptr;
-
- (* Define the main function for crt0 to call. *)
- let main_fn =
- let main_ty = Llvm.function_type i32 [| i32; i32 |] in
- let main_name =
- match sess.Session.sess_targ with
- Common.Win32_x86_pe -> "WinMain@16"
- | Common.Linux_x86_elf
- | Common.MacOS_x86_macho -> "main"
- in
- Llvm.define_function main_name main_ty llmod
- in
- let argc = Llvm.param main_fn 0 in
- let argv = Llvm.param main_fn 1 in
- let main_builder = Llvm.builder_at_end llctx (Llvm.entry_block main_fn) in
- let rust_main_fn =
- match Llvm.lookup_function "_rust_main" llmod with
- None -> raise (Failure "no main function found")
- | Some fn -> fn
- in
- let rust_start = abi.Llabi.rust_start in
- let rust_start_args = [| Llvm.const_ptrtoint rust_main_fn abi.Llabi.word_ty;
- crate_ptr; argc; argv |] in
- ignore (Llvm.build_call
- rust_start rust_start_args "start_rust" main_builder);
- ignore (Llvm.build_ret (Llvm.const_int i32 0) main_builder)
-;;
-
-
-(*
- * Local Variables:
- * fill-column: 78;
- * indent-tabs-mode: nil
- * buffer-file-coding-system: utf-8-unix
- * compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
- * End:
- *)
-
diff --git a/src/boot/llvm/lltrans.ml b/src/boot/llvm/lltrans.ml
deleted file mode 100644
index 22c1557e..00000000
--- a/src/boot/llvm/lltrans.ml
+++ /dev/null
@@ -1,1148 +0,0 @@
-(*
- * LLVM translator.
- *)
-
-open Common;;
-open Semant;;
-open Transutil;;
-
-let log cx = Session.log "trans"
- cx.Semant.ctxt_sess.Session.sess_log_trans
- cx.Semant.ctxt_sess.Session.sess_log_out
-;;
-
-(* Returns a new LLVM IRBuilder positioned at the end of llblock. If
- debug_loc isn't None, the IRBuilder's debug location is set to its
- contents, which should be a DILocation mdnode. (See
- http://llvm.org/docs/SourceLevelDebugging.html, or get it from an existing
- llbuilder with Llvm.current_debug_location.) *)
-let llbuilder_at_end_with_debug_loc
- (llctx:Llvm.llcontext) (llblock:Llvm.llbasicblock)
- (debug_loc:Llvm.llvalue option) =
- let llbuilder = Llvm.builder_at_end llctx llblock in
- may (Llvm.set_current_debug_location llbuilder) debug_loc;
- llbuilder
-
-let trans_crate
- (sem_cx:Semant.ctxt)
- (llctx:Llvm.llcontext)
- (sess:Session.sess)
- (crate:Ast.crate)
- : Llvm.llmodule =
-
- let iflog thunk =
- if sess.Session.sess_log_trans
- then thunk ()
- else ()
- in
-
- (* Helpers for adding metadata. *)
- let md_str (s:string) : Llvm.llvalue = Llvm.mdstring llctx s in
- let md_node (vals:Llvm.llvalue array) : Llvm.llvalue =
- Llvm.mdnode llctx vals
- in
- let const_i32 (i:int) : Llvm.llvalue =
- Llvm.const_int (Llvm.i32_type llctx) i
- in
- let const_i1 (i:int) : Llvm.llvalue =
- Llvm.const_int (Llvm.i1_type llctx) i
- in
- let llvm_debug_version : int = 0x8 lsl 16 in
- let const_dw_tag (tag:Dwarf.dw_tag) : Llvm.llvalue =
- const_i32 (llvm_debug_version lor (Dwarf.dw_tag_to_int tag))
- in
-
- (* See http://llvm.org/docs/SourceLevelDebugging.html. *)
- let crate_compile_unit : Llvm.llvalue =
- let name = Hashtbl.find sem_cx.Semant.ctxt_item_files crate.id in
- md_node [| const_dw_tag Dwarf.DW_TAG_compile_unit;
- const_i32 0; (* Unused. *)
- const_i32 2; (* DW_LANG_C. FIXME: Pick a Rust DW_LANG code. *)
- md_str (Filename.basename name);
- md_str (Filename.concat
- (Sys.getcwd()) (Filename.dirname name));
- md_str ("Rustboot " ^ Version.version);
- (* This is the main compile unit. There must be exactly one of
- these in an LLVM module for it to emit debug info. *)
- const_i1 1;
- (* There are a couple more supported fields, which we ignore
- here. *)
- |]
- in
- let di_file (filepath:string) =
- md_node [| const_dw_tag Dwarf.DW_TAG_file_type;
- md_str (Filename.basename filepath);
- md_str (Filename.concat
- (Sys.getcwd()) (Filename.dirname filepath));
- crate_compile_unit
- |]
- in
- let di_subprogram (scope:Llvm.llvalue) (name:string) (fullname:string)
- (di_file:Llvm.llvalue) (line:int) (llfunction:Llvm.llvalue)
- : Llvm.llvalue =
- (* 'scope' is generally a compile unit or other subprogram. *)
- md_node [| const_dw_tag Dwarf.DW_TAG_subprogram;
- const_i32 0; (* Unused. *)
- scope;
- md_str name;
- md_str fullname; (* Display name *)
- md_str fullname; (* Linkage name *)
- di_file;
- const_i32 line;
- (* FIXME: Fill in the following fields. *)
- md_node [||];
- const_i1 1;
- const_i1 1;
- const_i32 0;
- const_i32 0;
- md_node [||];
- const_i1 0;
- const_i1 0;
- llfunction (* The llvm::Function this reflects. *)
- |]
- in
- let di_location (line:int) (col:int) (scope:Llvm.llvalue) : Llvm.llvalue =
- (* 'scope' is generally a subprogram or block. *)
- md_node [| const_i32 line; const_i32 col; scope; const_i32 0 |]
- in
-
- let di_location_from_id (scope:Llvm.llvalue) (id:node_id)
- : Llvm.llvalue option =
- match Session.get_span sess id with
- None -> None
- | Some span ->
- let (_, line, col) = span.lo in
- Some (di_location line col scope)
- in
-
- (* Sets the 'llbuilder's current location (which it attaches to all
- instructions) to the location of the start of the 'id' node within
- 'scope', usually a subprogram or lexical block. *)
- let set_debug_location
- (llbuilder:Llvm.llbuilder) (scope:Llvm.llvalue) (id:node_id)
- : unit =
- may (Llvm.set_current_debug_location llbuilder)
- (di_location_from_id scope id)
- in
-
- (* Translation of our node_ids into LLVM identifiers, which are strings. *)
- let next_anon_llid = ref 0 in
- let num_llid num klass = Printf.sprintf "%s%d" klass num in
- let anon_llid klass =
- let llid = num_llid !next_anon_llid klass in
- next_anon_llid := !next_anon_llid + 1;
- llid
- in
- let node_llid (node_id_opt:node_id option) : (string -> string) =
- match node_id_opt with
- None -> anon_llid
- | Some (Node num) -> num_llid num
- in
-
- let llnilty = Llvm.array_type (Llvm.i1_type llctx) 0 in
- let llnil = Llvm.const_array (Llvm.i1_type llctx) [| |] in
-
- let ty_of_item = Hashtbl.find sem_cx.Semant.ctxt_all_item_types in
- let ty_of_slot n = Semant.slot_ty (Semant.get_slot sem_cx n) in
-
- let filename = Session.filename_of sess.Session.sess_in in
- let llmod = Llvm.create_module llctx filename in
-
- let (abi:Llabi.abi) = Llabi.declare_abi llctx llmod in
- let (crate_ptr:Llvm.llvalue) =
- Llvm.declare_global abi.Llabi.crate_ty "rust_crate" llmod
- in
-
- let (void_ty:Llvm.lltype) = Llvm.void_type llctx in
- let (word_ty:Llvm.lltype) = abi.Llabi.word_ty in
- let (wordptr_ty:Llvm.lltype) = Llvm.pointer_type word_ty in
- let (task_ty:Llvm.lltype) = abi.Llabi.task_ty in
- let (task_ptr_ty:Llvm.lltype) = Llvm.pointer_type task_ty in
- let fn_ty (out:Llvm.lltype) (args:Llvm.lltype array) : Llvm.lltype =
- Llvm.function_type out args
- in
-
- let imm (i:int64) : Llvm.llvalue =
- Llvm.const_int word_ty (Int64.to_int i)
- in
-
- let asm_glue = Llasm.get_glue llctx llmod abi sess in
-
- let llty_str llty =
- Llvm.string_of_lltype llty
- in
-
- let llval_str llv =
- let ts = llty_str (Llvm.type_of llv) in
- match Llvm.value_name llv with
- "" ->
- Printf.sprintf "<anon=%s>" ts
- | s -> Printf.sprintf "<%s=%s>" s ts
- in
-
- let llvals_str llvals =
- (String.concat ", "
- (Array.to_list
- (Array.map llval_str llvals)))
- in
-
- let build_call callee args rvid builder =
- iflog
- begin
- fun _ ->
- let name = Llvm.value_name callee in
- log sem_cx "build_call: %s(%s)" name (llvals_str args);
- log sem_cx "build_call: typeof(%s) = %s"
- name (llty_str (Llvm.type_of callee))
- end;
- Llvm.build_call callee args rvid builder
- in
-
- (* Upcall translation *)
-
- let extern_upcalls = Hashtbl.create 0 in
- let trans_upcall
- (llbuilder:Llvm.llbuilder)
- (lltask:Llvm.llvalue)
- (name:string)
- (lldest:Llvm.llvalue option)
- (llargs:Llvm.llvalue array) =
- let n = Array.length llargs in
- let llglue = asm_glue.Llasm.asm_upcall_glues.(n) in
- let llupcall = htab_search_or_add extern_upcalls name
- begin
- fun _ ->
- let args_ty =
- Array.append
- [| task_ptr_ty |]
- (Array.init n (fun i -> Llvm.type_of llargs.(i)))
- in
- let out_ty = match lldest with
- None -> void_ty
- | Some v -> Llvm.type_of v
- in
- let fty = fn_ty out_ty args_ty in
- (*
- * NB: At this point it actually doesn't matter what type
- * we gave the upcall function, as we're just going to
- * pointercast it to a word and pass it to the upcall-glue
- * for now. But possibly in the future it might matter if
- * we develop a proper upcall calling convention.
- *)
- Llvm.declare_function name fty llmod
- end
- in
- (* Cast everything to plain words so we can hand off to the glue. *)
- let llupcall = Llvm.const_pointercast llupcall word_ty in
- let llargs =
- Array.map
- (fun arg ->
- Llvm.build_pointercast arg word_ty
- (anon_llid "arg") llbuilder)
- llargs
- in
- let llallargs = Array.append [| lltask; llupcall |] llargs in
- let llid = anon_llid "rv" in
- let llrv = build_call llglue llallargs llid llbuilder in
- Llvm.set_instruction_call_conv Llvm.CallConv.c llrv;
- match lldest with
- None -> ()
- | Some lldest ->
- let lldest =
- Llvm.build_pointercast lldest wordptr_ty "" llbuilder
- in
- ignore (Llvm.build_store llrv lldest llbuilder);
- in
-
- let upcall
- (llbuilder:Llvm.llbuilder)
- (lltask:Llvm.llvalue)
- (name:string)
- (lldest:Llvm.llvalue option)
- (llargs:Llvm.llvalue array)
- : unit =
- trans_upcall llbuilder lltask name lldest llargs
- in
-
- let trans_free
- (llbuilder:Llvm.llbuilder)
- (lltask:Llvm.llvalue)
- (src:Llvm.llvalue)
- : unit =
- upcall llbuilder lltask "upcall_free" None [| src; const_i32 0 |]
- in
-
- (*
- * let trans_malloc (llbuilder:Llvm.llbuilder)
- * (dst:Llvm.llvalue) (nbytes:int64) : unit =
- * upcall llbuilder "upcall_malloc" (Some dst) [| imm nbytes |]
- * in
- *)
-
- (* Type translation *)
-
- let lltys = Hashtbl.create 0 in
-
- let trans_mach_ty (mty:ty_mach) : Llvm.lltype =
- let tycon =
- match mty with
- TY_u8 | TY_i8 -> Llvm.i8_type
- | TY_u16 | TY_i16 -> Llvm.i16_type
- | TY_u32 | TY_i32 -> Llvm.i32_type
- | TY_u64 | TY_i64 -> Llvm.i64_type
- | TY_f32 -> Llvm.float_type
- | TY_f64 -> Llvm.double_type
- in
- tycon llctx
- in
-
-
- let rec trans_ty_full (ty:Ast.ty) : Llvm.lltype =
- let p t = Llvm.pointer_type t in
- let s ts = Llvm.struct_type llctx ts in
- let opaque _ = Llvm.opaque_type llctx in
- let vec_body_ty _ =
- s [| word_ty; word_ty; word_ty; (opaque()) |]
- in
- let rc_opaque_ty =
- s [| word_ty; (opaque()) |]
- in
- match ty with
- Ast.TY_any -> opaque ()
- | Ast.TY_nil -> llnilty
- | Ast.TY_bool -> Llvm.i1_type llctx
- | Ast.TY_mach mty -> trans_mach_ty mty
- | Ast.TY_int -> word_ty
- | Ast.TY_uint -> word_ty
- | Ast.TY_char -> Llvm.i32_type llctx
- | Ast.TY_vec _
- | Ast.TY_str -> p (vec_body_ty())
-
- | Ast.TY_fn tfn ->
- let (tsig, _) = tfn in
- let lloutptr = p (trans_slot None tsig.Ast.sig_output_slot) in
- let lltaskty = p abi.Llabi.task_ty in
- let llins = Array.map (trans_slot None) tsig.Ast.sig_input_slots in
- fn_ty void_ty (Array.append [| lloutptr; lltaskty |] llins)
-
- | Ast.TY_tup slots ->
- s (Array.map trans_ty slots)
-
- | Ast.TY_rec entries ->
- s (Array.map (fun (_, e) -> trans_ty e) entries)
-
- | Ast.TY_constrained (ty', _) -> trans_ty ty'
-
- | Ast.TY_chan _ | Ast.TY_port _ | Ast.TY_task ->
- p rc_opaque_ty
-
- | Ast.TY_box t ->
- (* FIXME: wrong, this needs to point to a refcounted cell. *)
- p (trans_ty t)
-
- | Ast.TY_mutable t ->
- (* FIXME: No idea if 'mutable' translates to LLVM-type. *)
- (trans_ty t)
-
- | Ast.TY_native _ ->
- word_ty
-
- | Ast.TY_param _ ->
- abi.Llabi.tydesc_ty
-
- | Ast.TY_tag _
- | Ast.TY_obj _ | Ast.TY_type | Ast.TY_named _ ->
- Common.unimpl None "LLVM type translation for: %a" Ast.sprintf_ty ty
-
-
- and trans_ty t =
- htab_search_or_add lltys t (fun _ -> trans_ty_full t)
-
- (* Translates the type of a slot into the corresponding LLVM type. If the
- * id_opt parameter is specified, then the type will be fetched from the
- * context. *)
- and trans_slot (id_opt:node_id option) (slot:Ast.slot) : Llvm.lltype =
- let ty =
- match id_opt with
- Some id -> ty_of_slot id
- | None -> Semant.slot_ty slot
- in
- let base_llty = trans_ty ty in
- match slot.Ast.slot_mode with
- | Ast.MODE_alias ->
- Llvm.pointer_type base_llty
- | Ast.MODE_local -> base_llty
- in
-
- let get_element_ptr
- (llbuilder:Llvm.llbuilder)
- (ptr:Llvm.llvalue)
- (i:int)
- : Llvm.llvalue =
- (*
- * GEP takes a first-index of zero. Because it must! And this is
- * sufficiently surprising that the GEP FAQ exists. And you must
- * read it.
- *)
- let deref_ptr = Llvm.const_int (Llvm.i32_type llctx) 0 in
- let idx = Llvm.const_int (Llvm.i32_type llctx) i in
- Llvm.build_gep ptr [| deref_ptr; idx |] (anon_llid "gep") llbuilder
- in
-
- let free_ty
- (llbuilder:Llvm.llbuilder)
- (lltask:Llvm.llvalue)
- (ty:Ast.ty)
- (ptr:Llvm.llvalue)
- : unit =
- match ty with
- Ast.TY_port _
- | Ast.TY_chan _
- | Ast.TY_task ->
- Common.unimpl None "ty %a in Lltrans.free_ty" Ast.sprintf_ty ty
- | _ -> trans_free llbuilder lltask ptr
- in
-
- let rec iter_ty_parts_full
- (llbuilder:Llvm.llbuilder ref)
- (ty:Ast.ty)
- (dst_ptr:Llvm.llvalue)
- (src_ptr:Llvm.llvalue)
- (f:(Llvm.llvalue
- -> Llvm.llvalue
- -> Ast.ty
- -> unit))
- : unit =
-
- (* NB: must deref llbuilder at call-time; don't curry this. *)
- let gep p i = get_element_ptr (!llbuilder) p i in
-
- match ty with
- Ast.TY_rec entries ->
- iter_rec_parts gep dst_ptr src_ptr entries f
-
- | Ast.TY_tup tys ->
- iter_tup_parts gep dst_ptr src_ptr tys f
-
- | Ast.TY_tag _
- | Ast.TY_fn _
- | Ast.TY_obj _ ->
- Common.unimpl None
- "ty %a in Lltrans.iter_ty_parts_full" Ast.sprintf_ty ty
-
- | _ -> ()
-
- and iter_ty_parts
- (llbuilder:Llvm.llbuilder ref)
- (ty:Ast.ty)
- (ptr:Llvm.llvalue)
- (f:Llvm.llvalue -> Ast.ty -> unit)
- : unit =
- iter_ty_parts_full llbuilder ty ptr ptr
- (fun _ src_ptr slot -> f src_ptr slot)
-
- and drop_ty
- (llbuilder:Llvm.llbuilder ref)
- (lltask:Llvm.llvalue)
- (ptr:Llvm.llvalue)
- (ty:Ast.ty)
- : unit =
- iter_ty_parts llbuilder ty ptr (drop_ty llbuilder lltask)
-
- and drop_slot
- (llbuilder:Llvm.llbuilder ref)
- (lltask:Llvm.llvalue)
- (slot_ptr:Llvm.llvalue)
- (slot:Ast.slot)
- : unit =
-
- let llfn = Llvm.block_parent (Llvm.insertion_block (!llbuilder)) in
- let llty = trans_slot None slot in
- let ty = Semant.slot_ty slot in
-
- let new_block klass debug_loc =
- let llblock = Llvm.append_block llctx (anon_llid klass) llfn in
- let llbuilder =
- llbuilder_at_end_with_debug_loc llctx llblock debug_loc in
- (llblock, llbuilder)
- in
-
- let if_ptr_in_slot_not_null
- (inner:Llvm.llvalue -> Llvm.llbuilder -> Llvm.llbuilder)
- (llbuilder:Llvm.llbuilder)
- : Llvm.llbuilder =
- let ptr = Llvm.build_load slot_ptr (anon_llid "tmp") llbuilder in
- let null = Llvm.const_pointer_null llty in
- let test =
- Llvm.build_icmp Llvm.Icmp.Ne null ptr (anon_llid "nullp") llbuilder
- in
- let debug_loc = Llvm.current_debug_location llbuilder in
- let (llthen, llthen_builder) = new_block "then" debug_loc in
- let (llnext, llnext_builder) = new_block "next" debug_loc in
- ignore (Llvm.build_cond_br test llthen llnext llbuilder);
- let llthen_builder = inner ptr llthen_builder in
- ignore (Llvm.build_br llnext llthen_builder);
- llnext_builder
- in
-
- let decr_refcnt_and_if_zero
- (rc_elt:int)
- (inner:Llvm.llvalue -> Llvm.llbuilder -> Llvm.llbuilder)
- (ptr:Llvm.llvalue)
- (llbuilder:Llvm.llbuilder)
- : Llvm.llbuilder =
- let rc_ptr = get_element_ptr llbuilder ptr rc_elt in
- let rc = Llvm.build_load rc_ptr (anon_llid "rc") llbuilder in
- let rc = Llvm.build_sub rc (imm 1L) (anon_llid "tmp") llbuilder in
- let _ = Llvm.build_store rc rc_ptr llbuilder in
- log sem_cx "rc type: %s" (llval_str rc);
- let test =
- Llvm.build_icmp Llvm.Icmp.Eq
- rc (imm 0L) (anon_llid "zerop") llbuilder
- in
- let debug_loc = Llvm.current_debug_location llbuilder in
- let (llthen, llthen_builder) = new_block "then" debug_loc in
- let (llnext, llnext_builder) = new_block "next" debug_loc in
- ignore (Llvm.build_cond_br test llthen llnext llbuilder);
- let llthen_builder = inner ptr llthen_builder in
- ignore (Llvm.build_br llnext llthen_builder);
- llnext_builder
- in
-
- let free_and_null_out_slot
- (ptr:Llvm.llvalue)
- (llbuilder:Llvm.llbuilder)
- : Llvm.llbuilder =
- free_ty llbuilder lltask ty ptr;
- let null = Llvm.const_pointer_null llty in
- ignore (Llvm.build_store null slot_ptr llbuilder);
- llbuilder
- in
-
- begin
- match slot_mem_ctrl sem_cx slot with
- MEM_rc_struct
- | MEM_gc ->
- llbuilder :=
- if_ptr_in_slot_not_null
- (decr_refcnt_and_if_zero
- Abi.box_rc_field_refcnt
- free_and_null_out_slot)
- (!llbuilder)
-
- | MEM_rc_opaque ->
- llbuilder :=
- if_ptr_in_slot_not_null
- (decr_refcnt_and_if_zero
- Abi.box_rc_field_refcnt
- free_and_null_out_slot)
- (!llbuilder)
-
- | MEM_interior when Semant.type_is_structured sem_cx ty ->
- (* FIXME: to handle recursive types, need to call drop
- glue here, not inline. *)
- drop_ty llbuilder lltask slot_ptr ty
-
- | _ -> ()
- end
- in
-
- (* Dereferences the box referred to by ptr, whose type is ty. Looks
- straight through all mutable and constrained-type boxes, and loads
- pointers per dctrl. Returns the dereferenced value and its type. *)
- let rec deref_ty
- (llbuilder:Llvm.llbuilder) (dctrl:deref_ctrl)
- (ptr:Llvm.llvalue) (ty:Ast.ty)
- : (Llvm.llvalue * Ast.ty) =
- match (ty, dctrl) with
-
- | (Ast.TY_mutable ty, _)
- | (Ast.TY_constrained (ty, _), _) ->
- deref_ty llbuilder dctrl ptr ty
-
- | (Ast.TY_box ty', DEREF_one_box)
- | (Ast.TY_box ty', DEREF_all_boxes) ->
- let content =
- Llvm.build_load
- (get_element_ptr llbuilder ptr (Abi.box_rc_field_body))
- (anon_llid "deref") llbuilder
- in
- let inner_dctrl =
- if dctrl = DEREF_one_box
- then DEREF_none
- else DEREF_all_boxes
- in
- (* Possibly deref recursively. *)
- deref_ty llbuilder inner_dctrl content ty'
-
- | _ -> (ptr, ty)
- in
-
- let (llitems:(node_id, Llvm.llvalue) Hashtbl.t) = Hashtbl.create 0 in
- (* Maps a fn's or block's id to an LLVM metadata node (subprogram or
- lexical block) representing it. *)
- let (dbg_llscopes:(node_id, Llvm.llvalue) Hashtbl.t) = Hashtbl.create 0 in
- let rec declare_mod_item
- (name:Ast.ident)
- mod_item
- : unit =
- let { node = { Ast.decl_item = (item:Ast.mod_item');
- Ast.decl_params = _ }; id = id } =
- mod_item in
- let full_name = Semant.item_str sem_cx id in
- let (filename, line_num) =
- match Session.get_span sess id with
- None -> ("", 0)
- | Some span ->
- let (file, line, _) = span.lo in
- (file, line)
- in
- match item with
- Ast.MOD_ITEM_fn _ ->
- let llty = trans_ty (ty_of_item id) in
- let llfn = Llvm.declare_function ("_rust_" ^ name) llty llmod in
- let meta = (di_subprogram crate_compile_unit name full_name
- (di_file filename) line_num llfn)
- in
- Llvm.set_function_call_conv Llvm.CallConv.c llfn;
- Hashtbl.add llitems id llfn;
- Hashtbl.add dbg_llscopes id meta
-
- | Ast.MOD_ITEM_type _ ->
- () (* Types get translated with their terms. *)
-
- | Ast.MOD_ITEM_mod (_, items) ->
- Hashtbl.iter declare_mod_item items
-
- | _ ->
- Common.unimpl (Some id)
- "LLVM module declaration for: %a"
- Ast.sprintf_mod_item (name, mod_item)
- in
-
- let trans_fn (fn:Ast.fn)
- (fn_id:node_id)
- : unit =
- let header_slots = fn.Ast.fn_input_slots in
- let body = fn.Ast.fn_body in
- let llfn = Hashtbl.find llitems fn_id in
- let lloutptr = Llvm.param llfn 0 in
- let lltask = Llvm.param llfn 1 in
- let llsubprogram = Hashtbl.find dbg_llscopes fn_id in
-
- (* LLVM requires that functions be grouped into basic blocks terminated by
- * terminator instructions, while our AST is less strict. So we have to do
- * a little trickery here to wrangle the statement sequence into LLVM's
- * format. *)
-
- let new_block id_opt klass debug_loc =
- let llblock = Llvm.append_block llctx (node_llid id_opt klass) llfn in
- let llbuilder =
- llbuilder_at_end_with_debug_loc llctx llblock debug_loc in
- (llblock, llbuilder)
- in
-
- (* Build up the slot-to-llvalue mapping, allocating space along the
- * way. *)
- let slot_to_llvalue = Hashtbl.create 0 in
- let (_, llinitbuilder) =
- new_block None "init" (di_location_from_id llsubprogram fn_id) in
-
- (* Allocate space for arguments (needed because arguments are lvalues in
- * Rust), and store them in the slot-to-llvalue mapping. *)
- let n_implicit_args = 2 in
- let build_arg idx llargval =
- if idx >= n_implicit_args
- then
- let ({ id = id; node = _ }, ident) = header_slots.(idx - 2) in
- Llvm.set_value_name ident llargval;
- let llarg =
- let llty = Llvm.type_of llargval in
- Llvm.build_alloca llty (ident ^ "_ptr") llinitbuilder
- in
- ignore (Llvm.build_store llargval llarg llinitbuilder);
- Hashtbl.add slot_to_llvalue id llarg
- in
- Array.iteri build_arg (Llvm.params llfn);
-
- (* Allocate space for all the blocks' slots.
- * and zero the box pointers. *)
- let init_block (block_id:node_id) : unit =
- let init_slot
- (key:Ast.slot_key)
- (slot_id:node_id)
- (slot:Ast.slot)
- : unit =
- let name = Ast.sprintf_slot_key () key in
- let llty = trans_slot (Some slot_id) slot in
- let llptr = Llvm.build_alloca llty name llinitbuilder in
- begin
- match slot_mem_ctrl sem_cx slot with
- MEM_rc_struct
- | MEM_rc_opaque
- | MEM_gc ->
- ignore (Llvm.build_store
- (Llvm.const_pointer_null llty)
- llptr llinitbuilder);
- | _ -> ()
- end;
- Hashtbl.add slot_to_llvalue slot_id llptr
- in
- iter_block_slots sem_cx block_id init_slot
- in
-
- let exit_block
- (llbuilder:Llvm.llbuilder)
- (block_id:node_id)
- : Llvm.llbuilder =
- let r = ref llbuilder in
- iter_block_slots sem_cx block_id
- begin
- fun _ slot_id slot ->
- if (not (Semant.slot_is_obj_state sem_cx slot_id))
- then
- let ptr = Hashtbl.find slot_to_llvalue slot_id in
- drop_slot r lltask ptr slot
- end;
- !r
- in
-
- List.iter init_block (Hashtbl.find sem_cx.Semant.ctxt_frame_blocks fn_id);
-
- let static_str (s:string) : Llvm.llvalue =
- Llvm.define_global (anon_llid "str") (Llvm.const_stringz llctx s) llmod
- in
-
-
- (* Translates a list of AST statements to a sequence of LLVM instructions.
- * The supplied "terminate" function appends the appropriate terminator
- * instruction to the instruction stream. It may or may not be called,
- * depending on whether the AST contains a terminating instruction
- * explicitly. *)
- let rec trans_stmts
- (block_id:node_id)
- (llbuilder:Llvm.llbuilder)
- (stmts:Ast.stmt list)
- (terminate:(Llvm.llbuilder -> node_id -> unit))
- : unit =
- let set_debug_loc (id:node_id) =
- (* Sets the llbuilder's current location (which it attaches to all
- instructions) to the location of the start of the 'id' node. *)
- set_debug_location llbuilder llsubprogram id
- in
-
- let trans_literal
- (lit:Ast.lit)
- : Llvm.llvalue =
- match lit with
- Ast.LIT_nil -> llnil
- | Ast.LIT_bool value ->
- Llvm.const_int (Llvm.i1_type llctx) (if value then 1 else 0)
- | Ast.LIT_mach_int (mty, value) ->
- let llty = trans_mach_ty mty in
- Llvm.const_of_int64 llty value (mach_is_signed mty)
- | Ast.LIT_int value ->
- Llvm.const_of_int64 (Llvm.i32_type llctx) value true
- | Ast.LIT_uint value ->
- Llvm.const_of_int64 (Llvm.i32_type llctx) value false
- | Ast.LIT_char ch ->
- Llvm.const_int (Llvm.i32_type llctx) ch
- in
-
- (* Translates an lval by reference into the appropriate pointer
- * value. *)
- let rec trans_lval (lval:Ast.lval) : (Llvm.llvalue * Ast.ty) =
- iflog (fun _ -> log sem_cx "trans_lval: %a" Ast.sprintf_lval lval);
- match lval with
- Ast.LVAL_base { id = base_id; node = _ } ->
- set_debug_loc base_id;
- let defn_id = lval_base_defn_id sem_cx lval in
- begin
- match get_defn sem_cx defn_id with
- Semant.DEFN_slot slot ->
- (Hashtbl.find slot_to_llvalue defn_id, slot_ty slot)
- | Semant.DEFN_item _ ->
- (Hashtbl.find llitems defn_id, lval_ty sem_cx lval)
- | _ ->
- Common.unimpl (Some defn_id)
- "LLVM base-defn translation of: %a"
- Ast.sprintf_lval lval
- end
- | Ast.LVAL_ext (base, component) ->
- let (llbase, base_ty) = trans_lval base in
- let base_ty = strip_mutable_or_constrained_ty base_ty in
- (*
- * All lval components aside from explicit-deref just
- * auto-deref through all boxes to find their indexable
- * referent.
- *)
- let (llbase, base_ty) =
- if component = Ast.COMP_deref
- then (llbase, base_ty)
- else deref_ty llbuilder DEREF_all_boxes llbase base_ty
- in
- match (base_ty, component) with
- (Ast.TY_rec entries,
- Ast.COMP_named (Ast.COMP_ident id)) ->
- let i = arr_idx (Array.map fst entries) id in
- (get_element_ptr llbuilder llbase i, snd entries.(i))
-
- | (Ast.TY_tup entries,
- Ast.COMP_named (Ast.COMP_idx i)) ->
- (get_element_ptr llbuilder llbase i, entries.(i))
-
- | (Ast.TY_box _, Ast.COMP_deref) ->
- deref_ty llbuilder DEREF_one_box llbase base_ty
-
- | _ -> (Common.unimpl (Some (Semant.lval_base_id lval))
- "LLVM lval translation of: %a"
- Ast.sprintf_lval lval)
- in
-
- let trans_callee (fn:Ast.lval) : (Llvm.llvalue * Ast.ty) =
- let fty = Hashtbl.find sem_cx.ctxt_all_lval_types (lval_base_id fn) in
- if lval_base_is_item sem_cx fn then
- let fn_item = lval_item sem_cx fn in
- let llfn = Hashtbl.find llitems (fn_item.id) in
- (llfn, fty)
- else
- (* indirect call to computed slot *)
- trans_lval fn
- in
-
- let trans_atom (atom:Ast.atom) : Llvm.llvalue =
- iflog (fun _ -> log sem_cx "trans_atom: %a" Ast.sprintf_atom atom);
- match atom with
- Ast.ATOM_literal { node = lit; id = _ } -> trans_literal lit
- | Ast.ATOM_lval lval ->
- Llvm.build_load (fst (trans_lval lval)) (anon_llid "tmp")
- llbuilder
- | Ast.ATOM_pexp _ ->
- bug () "Lltrans.trans_atom on ATOM_pexp"
- in
-
- let build_binop (op:Ast.binop) (lllhs:Llvm.llvalue) (llrhs:Llvm.llvalue)
- : Llvm.llvalue =
- let llid = anon_llid "expr" in
- match op with
- Ast.BINOP_eq ->
- (* TODO: equality works on more than just integers *)
- Llvm.build_icmp Llvm.Icmp.Eq lllhs llrhs llid llbuilder
-
- (* TODO: signed/unsigned distinction, floating point *)
- | Ast.BINOP_add -> Llvm.build_add lllhs llrhs llid llbuilder
- | Ast.BINOP_sub -> Llvm.build_sub lllhs llrhs llid llbuilder
- | Ast.BINOP_mul -> Llvm.build_mul lllhs llrhs llid llbuilder
- | Ast.BINOP_div -> Llvm.build_sdiv lllhs llrhs llid llbuilder
- | Ast.BINOP_mod -> Llvm.build_srem lllhs llrhs llid llbuilder
-
- | _ ->
- Common.unimpl None
- "LLVM binop trranslation of: %a"
- Ast.sprintf_binop op
- in
-
- let trans_binary_expr
- ((op:Ast.binop), (lhs:Ast.atom), (rhs:Ast.atom))
- : Llvm.llvalue =
- (* Evaluate the operands in the proper order. *)
- let (lllhs, llrhs) =
- match op with
- Ast.BINOP_or | Ast.BINOP_and | Ast.BINOP_eq | Ast.BINOP_ne
- | Ast.BINOP_lt | Ast.BINOP_le | Ast.BINOP_ge | Ast.BINOP_gt
- | Ast.BINOP_lsl | Ast.BINOP_lsr | Ast.BINOP_asr
- | Ast.BINOP_add | Ast.BINOP_sub | Ast.BINOP_mul
- | Ast.BINOP_div | Ast.BINOP_mod | Ast.BINOP_xor ->
- (trans_atom lhs, trans_atom rhs)
- | Ast.BINOP_send ->
- let llrhs = trans_atom rhs in
- let lllhs = trans_atom lhs in
- (lllhs, llrhs)
- in
- build_binop op lllhs llrhs
- in
-
- let trans_unary_expr e =
- Common.unimpl None
- "LLVM unary-expression translation of: %a"
- Ast.sprintf_expr (Ast.EXPR_unary e)
- in
-
- let trans_expr (expr:Ast.expr) : Llvm.llvalue =
- iflog (fun _ -> log sem_cx "trans_expr: %a" Ast.sprintf_expr expr);
- match expr with
- Ast.EXPR_binary binexp -> trans_binary_expr binexp
- | Ast.EXPR_unary unexp -> trans_unary_expr unexp
- | Ast.EXPR_atom atom -> trans_atom atom
- in
-
- let trans_log_str (atom:Ast.atom) : unit =
- upcall llbuilder lltask "upcall_log_str" None [| trans_atom atom |]
- in
-
- let trans_log_int (atom:Ast.atom) : unit =
- upcall llbuilder lltask "upcall_log_int" None [| trans_atom atom |]
- in
-
- let trans_fail
- (llbuilder:Llvm.llbuilder)
- (lltask:Llvm.llvalue)
- (reason:string)
- (stmt_id:node_id)
- : unit =
- let (file, line, _) =
- match Session.get_span sem_cx.Semant.ctxt_sess stmt_id with
- None -> ("<none>", 0, 0)
- | Some sp -> sp.lo
- in
- upcall llbuilder lltask "upcall_fail" None [|
- static_str reason;
- static_str file;
- Llvm.const_int (Llvm.i32_type llctx) line
- |];
- ignore (Llvm.build_unreachable llbuilder)
- in
-
- (* FIXME: this may be irrelevant; possibly LLVM will wind up
- * using GOT and such wherever it needs to to achieve PIC
- * data.
- *)
- (*
- let crate_rel (v:Llvm.llvalue) : Llvm.llvalue =
- let v_int = Llvm.const_pointercast v word_ty in
- let c_int = Llvm.const_pointercast crate_ptr word_ty in
- Llvm.const_sub v_int c_int
- in
- *)
-
- match stmts with
- [] -> terminate llbuilder block_id
- | head::tail ->
-
- iflog (fun _ ->
- log sem_cx "trans_stmt: %a" Ast.sprintf_stmt head);
-
- let trans_tail_with_builder llbuilder' : unit =
- trans_stmts block_id llbuilder' tail terminate
- in
- let trans_tail () = trans_tail_with_builder llbuilder in
-
- set_debug_loc head.id;
-
- match head.node with
- Ast.STMT_new_tup (dest, elems) ->
- let zero = const_i32 0 in
- let (lldest, _) = trans_lval dest in
- let trans_tup_elem idx (_, atom) =
- let indices = [| zero; const_i32 idx |] in
- let gep_id = anon_llid "init_tup_gep" in
- let ptr =
- Llvm.build_gep lldest indices gep_id llbuilder
- in
- ignore (Llvm.build_store (trans_atom atom) ptr llbuilder)
- in
- Array.iteri trans_tup_elem elems;
- trans_tail ()
-
- | Ast.STMT_copy (dest, src) ->
- let llsrc = trans_expr src in
- let (lldest, _) = trans_lval dest in
- ignore (Llvm.build_store llsrc lldest llbuilder);
- trans_tail ()
-
- | Ast.STMT_copy_binop (dest, op, src) ->
- let (lldest, _) = trans_lval dest in
- let llsrc = trans_atom src in
- (* FIXME: Handle vecs and strs. *)
- let lldest_deref =
- Llvm.build_load lldest (anon_llid "dest_init") llbuilder
- in
- let llres = build_binop op lldest_deref llsrc in
- ignore (Llvm.build_store llres lldest llbuilder);
- trans_tail ()
-
- | Ast.STMT_call (dest, fn, args) ->
- let llargs = Array.map trans_atom args in
- let (lldest, _) = trans_lval dest in
- let (llfn, _) = trans_callee fn in
- let llallargs = Array.append [| lldest; lltask |] llargs in
- let llrv = build_call llfn llallargs "" llbuilder in
- Llvm.set_instruction_call_conv Llvm.CallConv.c llrv;
- trans_tail ()
-
- | Ast.STMT_if sif ->
- let llexpr = trans_expr sif.Ast.if_test in
- let (llnext, llnextbuilder) =
- new_block None "next"
- (Llvm.current_debug_location llbuilder) in
- let branch_to_next llbuilder' _ =
- ignore (Llvm.build_br llnext llbuilder')
- in
- let llthen = trans_block sif.Ast.if_then branch_to_next in
- let llelse =
- match sif.Ast.if_else with
- None -> llnext
- | Some if_else -> trans_block if_else branch_to_next
- in
- ignore (Llvm.build_cond_br llexpr llthen llelse llbuilder);
- trans_tail_with_builder llnextbuilder
-
- | Ast.STMT_ret atom_opt ->
- begin
- match atom_opt with
- None -> ()
- | Some atom ->
- ignore (Llvm.build_store (trans_atom atom)
- lloutptr llbuilder)
- end;
- let llbuilder = exit_block llbuilder block_id in
- ignore (Llvm.build_ret_void llbuilder)
-
- | Ast.STMT_fail ->
- trans_fail llbuilder lltask "explicit failure" head.id
-
- | Ast.STMT_log a ->
- begin
- let aty = Semant.atom_type sem_cx a in
- match Semant.simplified_ty aty with
- (* NB: If you extend this, be sure to update the
- * typechecking code in type.ml as well. *)
- Ast.TY_str -> trans_log_str a
- | Ast.TY_int | Ast.TY_uint | Ast.TY_bool | Ast.TY_char
- | Ast.TY_mach (TY_u8) | Ast.TY_mach (TY_u16)
- | Ast.TY_mach (TY_u32) | Ast.TY_mach (TY_i8)
- | Ast.TY_mach (TY_i16) | Ast.TY_mach (TY_i32) ->
- trans_log_int a
- | _ -> Common.unimpl (Some head.id)
- "logging type"
- end;
- trans_tail ()
-
- | Ast.STMT_check_expr expr ->
- let llexpr = trans_expr expr in
- let debug_loc = Llvm.current_debug_location llbuilder in
- let (llfail, llfailbuilder) =
- new_block None "fail" debug_loc in
- let reason = Fmt.fmt_to_str Ast.fmt_expr expr in
- trans_fail llfailbuilder lltask reason head.id;
- let (llok, llokbuilder) =
- new_block None "ok" debug_loc in
- ignore (Llvm.build_cond_br llexpr llok llfail llbuilder);
- trans_tail_with_builder llokbuilder
-
- | Ast.STMT_new_str (dst, str) ->
- let (d, _) = trans_lval dst in
- let s = static_str str in
- let len =
- Llvm.const_int word_ty ((String.length str) + 1)
- in
- upcall llbuilder lltask "upcall_new_str"
- (Some d) [| s; len |];
- trans_tail ()
-
- | Ast.STMT_decl _ ->
- trans_tail ()
-
- | _ ->
- Common.unimpl (Some head.id)
- "LLVM statement translation of: %a"
- Ast.sprintf_stmt head
-
- (*
- * Translates an AST block to one or more LLVM basic blocks and returns
- * the first basic block. The supplied callback is expected to add a
- * terminator instruction.
- *)
-
- and trans_block
- ({ node = (stmts:Ast.stmt array); id = id }:Ast.block)
- (terminate:Llvm.llbuilder -> node_id -> unit)
- : Llvm.llbasicblock =
- let (llblock, llbuilder) =
- new_block (Some id) "bb" (di_location_from_id llsubprogram id) in
- trans_stmts id llbuilder (Array.to_list stmts) terminate;
- llblock
- in
-
- (* "Falling off the end" of a function needs to turn into an explicit
- * return instruction. *)
- let default_terminate llbuilder block_id =
- let llbuilder = exit_block llbuilder block_id in
- ignore (Llvm.build_ret_void llbuilder)
- in
-
- (* Build up the first body block, and link it to the end of the
- * initialization block. *)
- let llbodyblock = (trans_block body default_terminate) in
- ignore (Llvm.build_br llbodyblock llinitbuilder)
- in
-
- let rec trans_mod_item
- (name:Ast.ident)
- mod_item
- : unit =
- let { node = { Ast.decl_item = (item:Ast.mod_item');
- Ast.decl_params = _ }; id = id } =
- mod_item in
- match item with
- Ast.MOD_ITEM_type _ ->
- () (* Types get translated with their terms. *)
- | Ast.MOD_ITEM_mod (_, items) ->
- Hashtbl.iter trans_mod_item items
- | Ast.MOD_ITEM_fn fn -> trans_fn fn id
- | _ -> Common.unimpl (Some id)
- "LLVM module declaration for: %a"
- Ast.sprintf_mod_item (name, mod_item)
-
- in
-
- let exit_task_glue =
- (* The exit-task glue does not get called.
- *
- * Rather, control arrives at it by *returning* to the first
- * instruction of it, when control falls off the end of the task's
- * root function.
- *
- * There is a "fake" frame set up by the runtime, underneath us,
- * that we find ourselves in. This frame has the shape of a frame
- * entered with 2 standard arguments (outptr + taskptr), then a
- * retpc and N callee-saves sitting on the stack; all this is under
- * ebp. Then there are 2 *outgoing* args at sp[0] and sp[1].
- *
- * All these are fake except the taskptr, which is the one bit we
- * want. So we construct an equally fake cdecl llvm signature here
- * to crudely *get* the taskptr that's sitting 2 words up from sp,
- * and pass it to upcall_exit.
- *
- * The latter never returns.
- *)
- let llty = fn_ty void_ty [| task_ptr_ty |] in
- let llfn = Llvm.declare_function "rust_exit_task_glue" llty llmod in
- let lltask = Llvm.param llfn 0 in
- let llblock = Llvm.append_block llctx "body" llfn in
- let llbuilder = Llvm.builder_at_end llctx llblock in
- trans_upcall llbuilder lltask "upcall_exit" None [||];
- ignore (Llvm.build_ret_void llbuilder);
- llfn
- in
-
- try
- let crate' = crate.node in
- let items = snd (crate'.Ast.crate_items) in
- Hashtbl.iter declare_mod_item items;
- Hashtbl.iter trans_mod_item items;
- Llfinal.finalize_module
- sess llctx llmod abi asm_glue exit_task_glue crate_ptr;
- llmod
- with e -> Llvm.dispose_module llmod; raise e
-;;
-
-(*
- * Local Variables:
- * fill-column: 78;
- * indent-tabs-mode: nil
- * buffer-file-coding-system: utf-8-unix
- * compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
- * End:
- *)
-