├── rust-toolchain ├── clean_all.sh ├── .gitignore ├── cargo.sh ├── .travis.yml ├── flamegraph.sh ├── abc.cpp ├── config.sh ├── prepare.sh ├── example ├── mod_bench.rs ├── alloc_example.rs ├── dst-field-align.rs ├── arbitrary_self_types_pointers_and_wrappers.rs ├── example.rs ├── std_example.rs ├── mini_core_hello_world.rs └── mini_core.rs ├── patches ├── 0003-Disable-inline-assembly-in-libcore.patch ├── 0016-Disable-cpuid-intrinsic.patch ├── 0017-Fix-libtest-compilation.patch └── 0015-Remove-usage-of-unsized-locals.patch ├── LICENSE-MIT ├── crate_patches └── regex.patch ├── src ├── linkage.rs ├── unimpl.rs ├── analyze.rs ├── abi │ ├── comments.rs │ ├── returning.rs │ └── pass_mode.rs ├── trap.rs ├── allocator.rs ├── main_shim.rs ├── metadata.rs ├── llvm_intrinsics.rs ├── vtable.rs ├── target_features_whitelist.rs ├── cast.rs ├── discriminant.rs ├── codegen_i128.rs ├── pretty_clif.rs ├── unsize.rs ├── lib.rs ├── archive.rs ├── common.rs └── driver.rs ├── Readme.md ├── copy.clif ├── Cargo.toml ├── test.sh └── LICENSE-APACHE /rust-toolchain: -------------------------------------------------------------------------------- 1 | nightly 2 | -------------------------------------------------------------------------------- /clean_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash --verbose 2 | set -e 3 | 4 | rm -rf target/ build_sysroot/{sysroot/,sysroot_src/,target/,Cargo.lock} perf.data{,.old} 5 | rm -rf regex/ simple-raytracer/ 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | **/*.rs.bk 3 | *.rlib 4 | *.o 5 | perf.data 6 | perf.data.old 7 | /build_sysroot/sysroot 8 | /build_sysroot/sysroot_src 9 | /build_sysroot/Cargo.lock 10 | /build_sysroot/test_target/Cargo.lock 11 | /rust 12 | /regex 13 | -------------------------------------------------------------------------------- /cargo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z $CHANNEL ]; then 4 | export CHANNEL='debug' 5 | fi 6 | 7 | pushd $(dirname "$0") >/dev/null 8 | source config.sh 9 | popd >/dev/null 10 | 11 | cmd=$1 12 | shift 13 | 14 | cargo $cmd --target $TARGET_TRIPLE $@ 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: rust 3 | cache: 4 | directories: 5 | - $HOME/.cargo 6 | 7 | os: 8 | - linux 9 | - osx 10 | 11 | rust: 12 | - nightly 13 | 14 | script: 15 | - ./prepare.sh 16 | - ./test.sh --release 17 | 18 | env: 19 | global: 20 | # Enable backtraces for easier debugging. 21 | - RUST_BACKTRACE=1 22 | # Reduce amount of benchmark runs as they are slow. 23 | - COMPILE_RUNS=2 RUN_RUNS=2 24 | -------------------------------------------------------------------------------- /flamegraph.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source config.sh 3 | 4 | # These files grow really big (~1.4G) because of the sample frequency 5 | rm perf.data* || true 6 | 7 | # Profile compiling libcore 8 | perf record -F 9000 --call-graph dwarf \ 9 | -- $RUSTC --crate-type lib build_sysroot/sysroot_src/src/libcore/lib.rs --crate-name core 10 | 11 | # Generate the flamegraph 12 | perf script | ../FlameGraph/stackcollapse-perf.pl | grep cranelift | ../FlameGraph/flamegraph.pl > abc.svg 13 | -------------------------------------------------------------------------------- /abc.cpp: -------------------------------------------------------------------------------- 1 | // compile using g++ -std=c++11 -g -c abc.cpp -o abc.o 2 | 3 | struct Opaque; 4 | 5 | struct MyType { 6 | unsigned int field_a; 7 | int field_b; 8 | void* field_c; 9 | float field_d; 10 | //double field_e; 11 | //long long field_f; 12 | bool field_g; 13 | char field_h; 14 | Opaque* field_i; 15 | }; 16 | 17 | MyType bcd(int x, MyType a) { 18 | MyType b = a; 19 | MyType c = b; 20 | MyType d = c; 21 | MyType e = d; 22 | MyType f = e; 23 | MyType g = f; 24 | MyType h = g; 25 | MyType i = h; 26 | MyType j = i; 27 | MyType k = j; 28 | MyType l = k; 29 | MyType m = l; 30 | return b; 31 | } 32 | int main() { 33 | bcd(42, {}); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /config.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | unamestr=`uname` 4 | if [[ "$unamestr" == 'Linux' ]]; then 5 | dylib_ext='so' 6 | elif [[ "$unamestr" == 'Darwin' ]]; then 7 | dylib_ext='dylib' 8 | else 9 | echo "Unsupported os" 10 | exit 1 11 | fi 12 | 13 | TARGET_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ") 14 | 15 | export RUSTFLAGS='-Cpanic=abort -Cdebuginfo=2 -Zpanic-abort-tests -Zcodegen-backend='$(pwd)'/target/'$CHANNEL'/librustc_codegen_cranelift.'$dylib_ext' --sysroot '$(pwd)'/build_sysroot/sysroot' 16 | RUSTC="rustc $RUSTFLAGS -L crate=target/out --out-dir target/out" 17 | export RUSTC_LOG=warn # display metadata load errors 18 | 19 | export LD_LIBRARY_PATH="$(pwd)/target/out:$(pwd)/build_sysroot/sysroot/lib/rustlib/$TARGET_TRIPLE/lib" 20 | export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH 21 | -------------------------------------------------------------------------------- /prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash --verbose 2 | set -e 3 | 4 | rustup component add rust-src 5 | ./build_sysroot/prepare_sysroot_src.sh 6 | cargo install hyperfine || echo "Skipping hyperfine install" 7 | 8 | git clone https://github.com/rust-lang/regex.git || echo "rust-lang/regex has already been cloned" 9 | pushd regex 10 | git checkout -- . 11 | git checkout 341f207c1071f7290e3f228c710817c280c8dca1 12 | git apply ../crate_patches/regex.patch 13 | popd 14 | 15 | git clone https://github.com/ebobby/simple-raytracer || echo "ebobby/simple-raytracer has already been cloned" 16 | pushd simple-raytracer 17 | git checkout -- . 18 | git checkout 804a7a21b9e673a482797aa289a18ed480e4d813 19 | 20 | # build with cg_llvm for perf comparison 21 | cargo build 22 | mv target/debug/main raytracer_cg_llvm 23 | popd 24 | -------------------------------------------------------------------------------- /example/mod_bench.rs: -------------------------------------------------------------------------------- 1 | #![feature(start, box_syntax, core_intrinsics, lang_items)] 2 | #![no_std] 3 | 4 | #[link(name = "c")] 5 | extern {} 6 | 7 | #[panic_handler] 8 | fn panic_handler(_: &core::panic::PanicInfo) -> ! { 9 | unsafe { 10 | core::intrinsics::abort(); 11 | } 12 | } 13 | 14 | #[lang="eh_personality"] 15 | fn eh_personality(){} 16 | 17 | // Required for rustc_codegen_llvm 18 | #[no_mangle] 19 | unsafe extern "C" fn _Unwind_Resume() { 20 | core::intrinsics::unreachable(); 21 | } 22 | 23 | #[start] 24 | fn main(_argc: isize, _argv: *const *const u8) -> isize { 25 | for i in 2..100_000_000 { 26 | black_box((i + 1) % i); 27 | } 28 | 29 | 0 30 | } 31 | 32 | #[inline(never)] 33 | fn black_box(i: u32) { 34 | if i != 1 { 35 | unsafe { core::intrinsics::abort(); } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /example/alloc_example.rs: -------------------------------------------------------------------------------- 1 | #![feature(start, box_syntax, alloc_system, core_intrinsics, alloc_prelude, alloc_error_handler)] 2 | #![no_std] 3 | 4 | extern crate alloc; 5 | extern crate alloc_system; 6 | 7 | use alloc::prelude::v1::*; 8 | 9 | use alloc_system::System; 10 | 11 | #[global_allocator] 12 | static ALLOC: System = System; 13 | 14 | #[link(name = "c")] 15 | extern "C" { 16 | fn puts(s: *const u8); 17 | } 18 | 19 | #[panic_handler] 20 | fn panic_handler(_: &core::panic::PanicInfo) -> ! { 21 | unsafe { 22 | core::intrinsics::abort(); 23 | } 24 | } 25 | 26 | #[alloc_error_handler] 27 | fn alloc_error_handler(_: alloc::alloc::Layout) -> ! { 28 | unsafe { 29 | core::intrinsics::abort(); 30 | } 31 | } 32 | 33 | #[start] 34 | fn main(_argc: isize, _argv: *const *const u8) -> isize { 35 | let world: Box<&str> = box "Hello World!\0"; 36 | unsafe { 37 | puts(*world as *const str as *const u8); 38 | } 39 | 40 | 0 41 | } 42 | -------------------------------------------------------------------------------- /patches/0003-Disable-inline-assembly-in-libcore.patch: -------------------------------------------------------------------------------- 1 | From 50ce3e454d5721cb534a9e9bb73c82246b930bab Mon Sep 17 00:00:00 2001 2 | From: bjorn3 3 | Date: Sat, 19 Jan 2019 11:46:43 +0100 4 | Subject: [PATCH] Disable inline assembly in libcore 5 | 6 | --- 7 | src/libcore/hint.rs | 2 ++ 8 | 1 file changed, 2 insertions(+) 9 | 10 | diff --git a/src/libcore/hint.rs b/src/libcore/hint.rs 11 | index ad5a207..04712b8 100644 12 | --- a/src/libcore/hint.rs 13 | +++ b/src/libcore/hint.rs 14 | @@ -62,6 +62,7 @@ pub unsafe fn unreachable_unchecked() -> ! { 15 | #[inline] 16 | #[unstable(feature = "renamed_spin_loop", issue = "55002")] 17 | pub fn spin_loop() { 18 | + /* 19 | #[cfg( 20 | all( 21 | any(target_arch = "x86", target_arch = "x86_64"), 22 | @@ -71,4 +72,5 @@ pub fn spin_loop() { 23 | unsafe { crate::arch::arm::__yield() }; 24 | } 25 | } 26 | + */ 27 | } 28 | -- 29 | 2.17.2 (Apple Git-113) 30 | -------------------------------------------------------------------------------- /patches/0016-Disable-cpuid-intrinsic.patch: -------------------------------------------------------------------------------- 1 | From 7403e2998345ef0650fd50628d7098d4d1e88e5c Mon Sep 17 00:00:00 2001 2 | From: bjorn3 3 | Date: Sat, 6 Apr 2019 12:16:21 +0200 4 | Subject: [PATCH] Remove usage of unsized locals 5 | 6 | --- 7 | src/stdarch/crates/core_arch/src/x86/cpuid.rs | 2 ++ 8 | 1 files changed, 2 insertions(+), 0 deletions(-) 9 | 10 | diff --git a/src/stdarch/crates/core_arch/src/x86/cpuid.rs b/src/stdarch/crates/core_arch/src/x86/cpuid.rs 11 | index f313c42..ff952bc 100644 12 | --- a/src/stdarch/crates/core_arch/src/x86/cpuid.rs 13 | +++ b/src/stdarch/crates/core_arch/src/x86/cpuid.rs 14 | @@ -84,6 +84,9 @@ pub unsafe fn __cpuid(leaf: u32) -> CpuidResult { 15 | /// Does the host support the `cpuid` instruction? 16 | #[inline] 17 | pub fn has_cpuid() -> bool { 18 | + // __cpuid intrinsic is not yet implemented 19 | + return false; 20 | + 21 | #[cfg(target_env = "sgx")] 22 | { 23 | false 24 | -- 25 | 2.20.1 (Apple Git-117) 26 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /crate_patches/regex.patch: -------------------------------------------------------------------------------- 1 | From febff2a8c639efb5de1e1b4758cdb473847d80ce Mon Sep 17 00:00:00 2001 2 | From: bjorn3 3 | Date: Tue, 30 Jul 2019 12:12:37 +0200 4 | Subject: [PATCH] Disable threads in shootout-regex-dna example 5 | 6 | --- 7 | examples/shootout-regex-dna.rs | 4 ++-- 8 | 1 file changed, 2 insertions(+), 2 deletions(-) 9 | 10 | diff --git a/examples/shootout-regex-dna.rs b/examples/shootout-regex-dna.rs 11 | index 2171bb3..37382f8 100644 12 | --- a/examples/shootout-regex-dna.rs 13 | +++ b/examples/shootout-regex-dna.rs 14 | @@ -37,7 +37,7 @@ fn main() { 15 | for variant in variants { 16 | let seq = seq_arc.clone(); 17 | let restr = variant.to_string(); 18 | - let future = thread::spawn(move || variant.find_iter(&seq).count()); 19 | + let future = variant.find_iter(&seq).count(); 20 | counts.push((restr, future)); 21 | } 22 | 23 | @@ -60,7 +60,7 @@ fn main() { 24 | } 25 | 26 | for (variant, count) in counts { 27 | - println!("{} {}", variant, count.join().unwrap()); 28 | + println!("{} {}", variant, count); 29 | } 30 | println!("\n{}\n{}\n{}", ilen, clen, seq.len()); 31 | } 32 | -- 33 | 2.11.0 34 | 35 | -------------------------------------------------------------------------------- /src/linkage.rs: -------------------------------------------------------------------------------- 1 | use rustc::mir::mono::{Linkage as RLinkage, MonoItem, Visibility}; 2 | 3 | use crate::prelude::*; 4 | 5 | pub fn get_clif_linkage(mono_item: MonoItem, linkage: RLinkage, visibility: Visibility) -> Linkage { 6 | match (linkage, visibility) { 7 | (RLinkage::External, Visibility::Default) => Linkage::Export, 8 | (RLinkage::Internal, Visibility::Default) => Linkage::Local, 9 | // FIXME this should get external linkage, but hidden visibility, 10 | // not internal linkage and default visibility 11 | (RLinkage::External, Visibility::Hidden) => Linkage::Export, 12 | _ => panic!("{:?} = {:?} {:?}", mono_item, linkage, visibility), 13 | } 14 | } 15 | 16 | pub fn get_static_ref_linkage(tcx: TyCtxt, def_id: DefId) -> Linkage { 17 | let fn_attrs = tcx.codegen_fn_attrs(def_id); 18 | 19 | if let Some(linkage) = fn_attrs.linkage { 20 | match linkage { 21 | RLinkage::External => Linkage::Export, 22 | RLinkage::Internal => Linkage::Local, 23 | RLinkage::ExternalWeak | RLinkage::WeakAny => Linkage::Preemptible, 24 | _ => panic!("{:?}", linkage), 25 | } 26 | } else { 27 | Linkage::Import 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/unimpl.rs: -------------------------------------------------------------------------------- 1 | //! The unimpl! macro is defined here. It is used to generate 2 | //! a non-fatal error on not yet implemented things. 3 | 4 | use std::cell::RefCell; 5 | 6 | use rustc::ty::TyCtxt; 7 | 8 | thread_local! { 9 | static CURRENT_MSG: RefCell = RefCell::new(String::new()); 10 | } 11 | 12 | // Just public, because of the unimpl macro 13 | #[doc(hidden)] 14 | pub struct NonFatal(pub String); 15 | 16 | /// Use when something in the current function is unimplemented. 17 | /// 18 | /// This will emit an error and continue codegen at a different function. 19 | pub macro unimpl($($tt:tt)*) { 20 | panic!(NonFatal(format!($($tt)*))); 21 | } 22 | 23 | pub fn try_unimpl(tcx: TyCtxt, msg: String, f: impl FnOnce()) { 24 | CURRENT_MSG.with(|current_msg| { 25 | let old = std::mem::replace(&mut *current_msg.borrow_mut(), msg); 26 | 27 | let res = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| f())); 28 | 29 | if let Err(err) = res { 30 | match err.downcast::() { 31 | Ok(non_fatal) => { 32 | tcx.sess.err(&format!("at {}: {}", current_msg.borrow(), non_fatal.0)); 33 | } 34 | Err(err) => ::std::panic::resume_unwind(err), 35 | } 36 | } 37 | 38 | *current_msg.borrow_mut() = old; 39 | }); 40 | } 41 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # WIP Cranelift codegen backend for rust 2 | 3 | > ⚠⚠⚠ Threads and certain kinds of FFI don't work yet. ⚠⚠⚠ 4 | 5 | ## Building 6 | 7 | ```bash 8 | $ git clone https://github.com/bjorn3/rustc_codegen_cranelift.git 9 | $ cd rustc_codegen_cranelift 10 | $ ./prepare.sh # download and patch sysroot src and install hyperfine for benchmarking 11 | $ ./test.sh 12 | ``` 13 | 14 | ## Usage 15 | 16 | `$cg_clif_dir` is the directory you cloned this repo into in the following instruction. 17 | 18 | ### Cargo 19 | 20 | ```bash 21 | $ $cg_clif_dir/cargo.sh run 22 | ``` 23 | 24 | ### Rustc 25 | 26 | ```bash 27 | $ rustc -Cpanic=abort -Zcodegen-backend=$cg_clif_dir/target/debug/librustc_codegen_cranelift.so --sysroot $cg_clif_dir/build_sysroot/sysroot my_crate.rs 28 | ``` 29 | 30 | 31 | ## Not yet supported 32 | 33 | * Good non-rust abi support ([several problems](https://github.com/bjorn3/rustc_codegen_cranelift/issues/10)) 34 | * Checked binops ([some missing instructions in cranelift](https://github.com/CraneStation/cranelift/issues/460)) 35 | * Inline assembly ([no cranelift support](https://github.com/CraneStation/cranelift/issues/444), not coming soon) 36 | * SIMD ([tracked here](https://github.com/bjorn3/rustc_codegen_cranelift/issues/171), some basic things work) 37 | 38 | ## Troubleshooting 39 | 40 | ### Can't compile 41 | 42 | Try updating your nightly compiler. You can try to use an nightly a day or two older if updating rustc doesn't fix it. If you still can't compile it, please fill an issue. 43 | -------------------------------------------------------------------------------- /src/analyze.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | use rustc::mir::StatementKind::*; 4 | 5 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 6 | pub enum SsaKind { 7 | NotSsa, 8 | Ssa, 9 | } 10 | 11 | pub fn analyze(fx: &FunctionCx<'_, '_, impl Backend>) -> HashMap { 12 | let mut flag_map = HashMap::new(); 13 | 14 | for (local, local_decl) in fx.mir.local_decls.iter_enumerated() { 15 | if fx.clif_type(local_decl.ty).is_some() { 16 | flag_map.insert(local, SsaKind::Ssa); 17 | } else { 18 | flag_map.insert(local, SsaKind::NotSsa); 19 | } 20 | } 21 | 22 | for bb in fx.mir.basic_blocks().iter() { 23 | for stmt in bb.statements.iter() { 24 | match &stmt.kind { 25 | Assign(place_and_rval) => match &place_and_rval.1 { 26 | Rvalue::Ref(_, _, place) => { 27 | analyze_non_ssa_place(&mut flag_map, place); 28 | } 29 | _ => {} 30 | }, 31 | _ => {} 32 | } 33 | } 34 | 35 | match &bb.terminator().kind { 36 | TerminatorKind::Call { 37 | destination: Some((place, _)), 38 | .. 39 | } => analyze_non_ssa_place(&mut flag_map, place), 40 | _ => {} 41 | } 42 | } 43 | 44 | flag_map 45 | } 46 | 47 | fn analyze_non_ssa_place(flag_map: &mut HashMap, place: &Place) { 48 | match place.base { 49 | PlaceBase::Local(local) => not_ssa(flag_map, local), 50 | _ => {} 51 | } 52 | } 53 | 54 | fn not_ssa>(flag_map: &mut HashMap, local: L) { 55 | *flag_map.get_mut(local.borrow()).unwrap() = SsaKind::NotSsa; 56 | } 57 | -------------------------------------------------------------------------------- /example/dst-field-align.rs: -------------------------------------------------------------------------------- 1 | // run-pass 2 | #![allow(dead_code)] 3 | struct Foo { 4 | a: u16, 5 | b: T 6 | } 7 | 8 | trait Bar { 9 | fn get(&self) -> usize; 10 | } 11 | 12 | impl Bar for usize { 13 | fn get(&self) -> usize { *self } 14 | } 15 | 16 | struct Baz { 17 | a: T 18 | } 19 | 20 | struct HasDrop { 21 | ptr: Box, 22 | data: T 23 | } 24 | 25 | fn main() { 26 | // Test that zero-offset works properly 27 | let b : Baz = Baz { a: 7 }; 28 | assert_eq!(b.a.get(), 7); 29 | let b : &Baz = &b; 30 | assert_eq!(b.a.get(), 7); 31 | 32 | // Test that the field is aligned properly 33 | let f : Foo = Foo { a: 0, b: 11 }; 34 | assert_eq!(f.b.get(), 11); 35 | let ptr1 : *const u8 = &f.b as *const _ as *const u8; 36 | 37 | let f : &Foo = &f; 38 | let ptr2 : *const u8 = &f.b as *const _ as *const u8; 39 | assert_eq!(f.b.get(), 11); 40 | 41 | // The pointers should be the same 42 | assert_eq!(ptr1, ptr2); 43 | 44 | // Test that nested DSTs work properly 45 | let f : Foo> = Foo { a: 0, b: Foo { a: 1, b: 17 }}; 46 | assert_eq!(f.b.b.get(), 17); 47 | let f : &Foo> = &f; 48 | assert_eq!(f.b.b.get(), 17); 49 | 50 | // Test that get the pointer via destructuring works 51 | 52 | let f : Foo = Foo { a: 0, b: 11 }; 53 | let f : &Foo = &f; 54 | let &Foo { a: _, b: ref bar } = f; 55 | assert_eq!(bar.get(), 11); 56 | 57 | // Make sure that drop flags don't screw things up 58 | 59 | let d : HasDrop> = HasDrop { 60 | ptr: Box::new(0), 61 | data: Baz { a: [1,2,3,4] } 62 | }; 63 | assert_eq!([1,2,3,4], d.data.a); 64 | 65 | let d : &HasDrop> = &d; 66 | assert_eq!(&[1,2,3,4], &d.data.a); 67 | } 68 | -------------------------------------------------------------------------------- /copy.clif: -------------------------------------------------------------------------------- 1 | target x86_64 2 | 3 | ; copy_nonoverlapping 4 | function u0:0(i64, i64, i64) fast { 5 | ss0 = explicit_slot 8 6 | ss1 = explicit_slot 8 7 | ss2 = explicit_slot 8 8 | ebb0(v0: i64, v1: i64, v2: i64): ; fn(src, dst, count) 9 | v99 = iconst.i64 1 10 | jump ebb1(v0, v1, v2) 11 | 12 | ebb1(v10: i64, v11: i64, v12: i64): 13 | ; if no more bytes to copy, return 14 | brz v12, ebb2 15 | 16 | ; copy one byte 17 | v20 = uload8.i32 v10 18 | istore8.i32 v20, v11 19 | 20 | ; increment src and dst and decrement remaining count 21 | v30 = iadd_imm v10, 1 22 | v31 = iadd_imm v11, 1 23 | v32 = isub v12, v99 24 | 25 | ; loop 26 | jump ebb1(v30, v31, v32) 27 | 28 | ebb2: 29 | return 30 | } 31 | 32 | ; copy 33 | function u0:0(i64, i64, i64) fast { 34 | ss0 = explicit_slot 8 35 | ss1 = explicit_slot 8 36 | ss2 = explicit_slot 8 37 | ebb0(v0: i64, v1: i64, v2: i64): ; fn(src, dst, count): 38 | v98 = iconst.i64 8 39 | v99 = iconst.i64 1 40 | jump ebb1(v0, v1, v2) 41 | 42 | ; copy eight bytes 43 | ebb1(v10: i64, v11: i64, v12: i64): 44 | ; if less than eight bytes to copy, goto ebb2 45 | v90 = icmp ult v12, v98 46 | brz v90, ebb2(v10, v11, v12) 47 | 48 | ; copy one byte 49 | v80 = load.i64 v10 50 | store.i64 v80, v11 51 | 52 | ; increment src and dst and decrement remaining count 53 | v20 = iadd_imm v0, 1 54 | v21 = iadd_imm v1, 1 55 | v22 = isub v2, v98 56 | 57 | ; loop 58 | jump ebb1(v20, v21, v22) 59 | 60 | ; copy one byte 61 | ebb2(v30: i64, v31: i64, v32: i64): 62 | ; if no more bytes to copy, return 63 | brz v32, ebb3 64 | 65 | ; copy one byte 66 | v81 = uload8.i32 v30 67 | istore8.i32 v81, v31 68 | 69 | ; increment src and dst and decrement remaining count 70 | v40 = iadd_imm v30, 1 71 | v41 = iadd_imm v31, 1 72 | v42 = isub v32, v99 73 | 74 | ; loop 75 | jump ebb2(v40, v41, v42) 76 | 77 | ; done 78 | ebb3: 79 | return 80 | } -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | cargo-features = ["profile-overrides"] 2 | 3 | [package] 4 | name = "rustc_codegen_cranelift" 5 | version = "0.1.0" 6 | authors = ["bjorn3 "] 7 | edition = "2018" 8 | 9 | [lib] 10 | crate-type = ["dylib"] 11 | 12 | [dependencies] 13 | # These have to be in sync with each other 14 | cranelift = { git = "https://github.com/CraneStation/cranelift.git" } 15 | cranelift-module = { git = "https://github.com/CraneStation/cranelift.git" } 16 | cranelift-faerie = { git = "https://github.com/CraneStation/cranelift.git" } 17 | target-lexicon = "0.8.1" 18 | faerie = "0.11.0" 19 | 20 | #goblin = "0.0.17" 21 | ar = "0.8.0" 22 | byteorder = "1.2.7" 23 | libc = "0.2.53" 24 | gimli = "0.19.0" 25 | indexmap = "1.0.2" 26 | libloading = "0.5.1" 27 | 28 | [dependencies.object] 29 | version = "0.14.0" 30 | default-features = false 31 | features = ["compression", "read", "std"] # We don't need WASM support 32 | 33 | # Uncomment to use local checkout of cranelift 34 | #[patch."https://github.com/CraneStation/cranelift.git"] 35 | #cranelift = { path = "../cranelift/cranelift-umbrella" } 36 | #cranelift-module = { path = "../cranelift/cranelift-module" } 37 | #cranelift-simplejit = { path = "../cranelift/cranelift-simplejit" } 38 | #cranelift-faerie = { path = "../cranelift/cranelift-faerie" } 39 | 40 | #[patch.crates-io] 41 | #gimli = { path = "../" } 42 | 43 | [target.'cfg(not(target_arch = "wasm32"))'.dependencies] 44 | cranelift-simplejit = { git = "https://github.com/CraneStation/cranelift.git" } 45 | 46 | [profile.dev] 47 | # By compiling dependencies with optimizations, performing tests gets much faster. 48 | opt-level = 3 49 | 50 | [profile.dev.overrides."rustc_codegen_cranelift"] 51 | # Disabling optimizations for cg_clif itself makes compilation after a change faster. 52 | opt-level = 0 53 | 54 | # Disable optimizations and debuginfo of build scripts and some of the heavy build deps, as the 55 | # execution time of build scripts is so fast that optimizing them slows down the total build time. 56 | [profile.dev.build-override] 57 | opt-level = 0 58 | debug = false 59 | 60 | [profile.dev.overrides.cranelift-codegen-meta] 61 | opt-level = 0 62 | debug = false 63 | 64 | [profile.dev.overrides.syn] 65 | opt-level = 0 66 | debug = false 67 | 68 | [profile.dev.overrides.synstructure] 69 | opt-level = 0 70 | debug = false 71 | -------------------------------------------------------------------------------- /example/arbitrary_self_types_pointers_and_wrappers.rs: -------------------------------------------------------------------------------- 1 | // Adapted from rustc run-pass test suite 2 | 3 | #![feature(no_core, arbitrary_self_types, box_syntax)] 4 | #![feature(rustc_attrs)] 5 | 6 | #![feature(start, lang_items)] 7 | #![no_core] 8 | 9 | extern crate mini_core; 10 | 11 | use mini_core::*; 12 | 13 | macro_rules! assert_eq { 14 | ($l:expr, $r: expr) => { 15 | if $l != $r { 16 | panic(&(stringify!($l != $r), file!(), line!(), 0)); 17 | } 18 | } 19 | } 20 | 21 | struct Ptr(Box); 22 | 23 | impl Deref for Ptr { 24 | type Target = T; 25 | 26 | fn deref(&self) -> &T { 27 | &*self.0 28 | } 29 | } 30 | 31 | impl + ?Sized, U: ?Sized> CoerceUnsized> for Ptr {} 32 | impl + ?Sized, U: ?Sized> DispatchFromDyn> for Ptr {} 33 | 34 | struct Wrapper(T); 35 | 36 | impl Deref for Wrapper { 37 | type Target = T; 38 | 39 | fn deref(&self) -> &T { 40 | &self.0 41 | } 42 | } 43 | 44 | impl, U> CoerceUnsized> for Wrapper {} 45 | impl, U> DispatchFromDyn> for Wrapper {} 46 | 47 | 48 | trait Trait { 49 | // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable 50 | // without unsized_locals), but wrappers arond `Self` currently are not. 51 | // FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented 52 | // fn wrapper(self: Wrapper) -> i32; 53 | fn ptr_wrapper(self: Ptr>) -> i32; 54 | fn wrapper_ptr(self: Wrapper>) -> i32; 55 | fn wrapper_ptr_wrapper(self: Wrapper>>) -> i32; 56 | } 57 | 58 | impl Trait for i32 { 59 | fn ptr_wrapper(self: Ptr>) -> i32 { 60 | **self 61 | } 62 | fn wrapper_ptr(self: Wrapper>) -> i32 { 63 | **self 64 | } 65 | fn wrapper_ptr_wrapper(self: Wrapper>>) -> i32 { 66 | ***self 67 | } 68 | } 69 | 70 | #[start] 71 | fn main(_: isize, _: *const *const u8) -> isize { 72 | let pw = Ptr(box Wrapper(5)) as Ptr>; 73 | assert_eq!(pw.ptr_wrapper(), 5); 74 | 75 | let wp = Wrapper(Ptr(box 6)) as Wrapper>; 76 | assert_eq!(wp.wrapper_ptr(), 6); 77 | 78 | let wpw = Wrapper(Ptr(box Wrapper(7))) as Wrapper>>; 79 | assert_eq!(wpw.wrapper_ptr_wrapper(), 7); 80 | 81 | 0 82 | } 83 | -------------------------------------------------------------------------------- /src/abi/comments.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | 3 | use rustc::mir; 4 | 5 | use crate::abi::pass_mode::*; 6 | use crate::prelude::*; 7 | 8 | pub fn add_args_header_comment(fx: &mut FunctionCx) { 9 | fx.add_global_comment(format!( 10 | "kind loc.idx param pass mode ty" 11 | )); 12 | } 13 | 14 | pub fn add_arg_comment<'tcx>( 15 | fx: &mut FunctionCx<'_, 'tcx, impl Backend>, 16 | kind: &str, 17 | local: mir::Local, 18 | local_field: Option, 19 | params: EmptySinglePair, 20 | pass_mode: PassMode, 21 | ty: Ty<'tcx>, 22 | ) { 23 | let local_field = if let Some(local_field) = local_field { 24 | Cow::Owned(format!(".{}", local_field)) 25 | } else { 26 | Cow::Borrowed("") 27 | }; 28 | let params = match params { 29 | Empty => Cow::Borrowed("-"), 30 | Single(param) => Cow::Owned(format!("= {:?}", param)), 31 | Pair(param_a, param_b) => Cow::Owned(format!("= {:?}, {:?}", param_a, param_b)), 32 | }; 33 | let pass_mode = format!("{:?}", pass_mode); 34 | fx.add_global_comment(format!( 35 | "{kind:5}{local:>3}{local_field:<5} {params:10} {pass_mode:36} {ty:?}", 36 | kind = kind, 37 | local = format!("{:?}", local), 38 | local_field = local_field, 39 | params = params, 40 | pass_mode = pass_mode, 41 | ty = ty, 42 | )); 43 | } 44 | 45 | pub fn add_locals_header_comment(fx: &mut FunctionCx) { 46 | fx.add_global_comment(String::new()); 47 | fx.add_global_comment(format!( 48 | "kind local ty size align (abi,pref)" 49 | )); 50 | } 51 | 52 | pub fn add_local_place_comments<'tcx>( 53 | fx: &mut FunctionCx<'_, 'tcx, impl Backend>, 54 | place: CPlace<'tcx>, 55 | local: Local, 56 | ) { 57 | let TyLayout { ty, details } = place.layout(); 58 | let ty::layout::LayoutDetails { 59 | size, 60 | align, 61 | abi: _, 62 | variants: _, 63 | fields: _, 64 | largest_niche: _, 65 | } = details; 66 | match *place.inner() { 67 | CPlaceInner::Var(var) => { 68 | assert_eq!(local, var); 69 | fx.add_global_comment(format!( 70 | "ssa {:5} {:20} {:4}b {}, {}", 71 | format!("{:?}", local), 72 | format!("{:?}", ty), 73 | size.bytes(), 74 | align.abi.bytes(), 75 | align.pref.bytes(), 76 | )); 77 | } 78 | CPlaceInner::Stack(stack_slot) => fx.add_entity_comment( 79 | stack_slot, 80 | format!( 81 | "{:?}: {:?} size={} align={},{}", 82 | local, 83 | ty, 84 | size.bytes(), 85 | align.abi.bytes(), 86 | align.pref.bytes(), 87 | ), 88 | ), 89 | CPlaceInner::NoPlace => fx.add_global_comment(format!( 90 | "zst {:5} {:20} {:4}b {}, {}", 91 | format!("{:?}", local), 92 | format!("{:?}", ty), 93 | size.bytes(), 94 | align.abi.bytes(), 95 | align.pref.bytes(), 96 | )), 97 | CPlaceInner::Addr(addr, None) => fx.add_global_comment(format!( 98 | "reuse {:5} {:20} {:4}b {}, {} storage={}", 99 | format!("{:?}", local), 100 | format!("{:?}", ty), 101 | size.bytes(), 102 | align.abi.bytes(), 103 | align.pref.bytes(), 104 | addr, 105 | )), 106 | CPlaceInner::Addr(_, Some(_)) => unreachable!(), 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/abi/returning.rs: -------------------------------------------------------------------------------- 1 | use crate::abi::pass_mode::*; 2 | use crate::prelude::*; 3 | 4 | pub fn codegen_return_param( 5 | fx: &mut FunctionCx, 6 | ssa_analyzed: &HashMap, 7 | start_ebb: Ebb, 8 | ) { 9 | let ret_layout = fx.return_layout(); 10 | let output_pass_mode = get_pass_mode(fx.tcx, fx.return_layout()); 11 | 12 | let ret_param = match output_pass_mode { 13 | PassMode::NoPass => { 14 | fx.local_map 15 | .insert(RETURN_PLACE, CPlace::no_place(ret_layout)); 16 | Empty 17 | } 18 | PassMode::ByVal(_) | PassMode::ByValPair(_, _) => { 19 | let is_ssa = 20 | *ssa_analyzed.get(&RETURN_PLACE).unwrap() == crate::analyze::SsaKind::Ssa; 21 | 22 | super::local_place(fx, RETURN_PLACE, ret_layout, is_ssa); 23 | 24 | Empty 25 | } 26 | PassMode::ByRef => { 27 | let ret_param = fx.bcx.append_ebb_param(start_ebb, fx.pointer_type); 28 | fx.local_map 29 | .insert(RETURN_PLACE, CPlace::for_addr(ret_param, ret_layout)); 30 | 31 | Single(ret_param) 32 | } 33 | }; 34 | 35 | #[cfg(debug_assertions)] 36 | crate::abi::comments::add_arg_comment( 37 | fx, 38 | "ret", 39 | RETURN_PLACE, 40 | None, 41 | ret_param, 42 | output_pass_mode, 43 | ret_layout.ty, 44 | ); 45 | } 46 | 47 | pub fn codegen_with_call_return_arg<'tcx, B: Backend, T>( 48 | fx: &mut FunctionCx<'_, 'tcx, B>, 49 | fn_sig: FnSig<'tcx>, 50 | ret_place: Option>, 51 | f: impl FnOnce(&mut FunctionCx<'_, 'tcx, B>, Option) -> (Inst, T), 52 | ) -> (Inst, T) { 53 | let ret_layout = fx.layout_of(fn_sig.output()); 54 | 55 | let output_pass_mode = get_pass_mode(fx.tcx, ret_layout); 56 | let return_ptr = match output_pass_mode { 57 | PassMode::NoPass => None, 58 | PassMode::ByRef => match ret_place { 59 | Some(ret_place) => Some(ret_place.to_addr(fx)), 60 | None => Some(fx.bcx.ins().iconst(fx.pointer_type, 43)), 61 | }, 62 | PassMode::ByVal(_) | PassMode::ByValPair(_, _) => None, 63 | }; 64 | 65 | let (call_inst, meta) = f(fx, return_ptr); 66 | 67 | match output_pass_mode { 68 | PassMode::NoPass => {} 69 | PassMode::ByVal(_) => { 70 | if let Some(ret_place) = ret_place { 71 | let ret_val = fx.bcx.inst_results(call_inst)[0]; 72 | ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_layout)); 73 | } 74 | } 75 | PassMode::ByValPair(_, _) => { 76 | if let Some(ret_place) = ret_place { 77 | let ret_val_a = fx.bcx.inst_results(call_inst)[0]; 78 | let ret_val_b = fx.bcx.inst_results(call_inst)[1]; 79 | ret_place.write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_layout)); 80 | } 81 | } 82 | PassMode::ByRef => {} 83 | } 84 | 85 | (call_inst, meta) 86 | } 87 | 88 | pub fn codegen_return(fx: &mut FunctionCx) { 89 | match get_pass_mode(fx.tcx, fx.return_layout()) { 90 | PassMode::NoPass | PassMode::ByRef => { 91 | fx.bcx.ins().return_(&[]); 92 | } 93 | PassMode::ByVal(_) => { 94 | let place = fx.get_local_place(RETURN_PLACE); 95 | let ret_val = place.to_cvalue(fx).load_scalar(fx); 96 | fx.bcx.ins().return_(&[ret_val]); 97 | } 98 | PassMode::ByValPair(_, _) => { 99 | let place = fx.get_local_place(RETURN_PLACE); 100 | let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx); 101 | fx.bcx.ins().return_(&[ret_val_a, ret_val_b]); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /patches/0017-Fix-libtest-compilation.patch: -------------------------------------------------------------------------------- 1 | From e06143d3373293d0490df482261cd4a842f1a5c5 Mon Sep 17 00:00:00 2001 2 | From: bjorn3 3 | Date: Thu, 3 Oct 2019 16:51:34 +0200 4 | Subject: [PATCH] Fix libtest compilation 5 | 6 | --- 7 | src/libtest/lib.rs | 28 ++++++++-------------------- 8 | 1 file changed, 8 insertions(+), 20 deletions(-) 9 | 10 | diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs 11 | index 8b76080..9e65de2 100644 12 | --- a/src/libtest/lib.rs 13 | +++ b/src/libtest/lib.rs 14 | @@ -52,7 +52,7 @@ use std::fmt; 15 | use std::fs::File; 16 | use std::io; 17 | use std::io::prelude::*; 18 | -use std::panic::{self, catch_unwind, AssertUnwindSafe, PanicInfo}; 19 | +use std::panic::{self, PanicInfo}; 20 | use std::path::PathBuf; 21 | use std::process; 22 | use std::process::{ExitStatus, Command, Termination}; 23 | @@ -1493,7 +1493,7 @@ pub fn run_test( 24 | report_time: bool, 25 | strategy: RunStrategy, 26 | monitor_ch: Sender, 27 | - testfn: Box, 28 | + testfn: Box, 29 | concurrency: Concurrent, 30 | ) { 31 | let name = desc.name.clone(); 32 | @@ -1509,7 +1509,7 @@ pub fn run_test( 33 | // If the platform is single-threaded we're just going to run 34 | // the test synchronously, regardless of the concurrency 35 | // level. 36 | - let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_arch = "wasm32"); 37 | + let supports_threads = false; 38 | if concurrency == Concurrent::Yes && supports_threads { 39 | let cfg = thread::Builder::new().name(name.as_slice().to_owned()); 40 | cfg.spawn(runtest).unwrap(); 41 | @@ -1531,20 +1531,8 @@ pub fn run_test( 42 | (benchfn.clone())(harness) 43 | }); 44 | } 45 | - DynTestFn(f) => { 46 | - match strategy { 47 | - RunStrategy::InProcess => (), 48 | - _ => panic!("Cannot run dynamic test fn out-of-process"), 49 | - }; 50 | - run_test_inner( 51 | - desc, 52 | - opts.nocapture, 53 | - opts.report_time, 54 | - strategy, 55 | - monitor_ch, 56 | - Box::new(move || __rust_begin_short_backtrace(f)), 57 | - concurrency 58 | - ); 59 | + DynTestFn(_f) => { 60 | + unimplemented!(); 61 | } 62 | StaticTestFn(f) => run_test_inner( 63 | desc, 64 | @@ -1604,7 +1592,7 @@ fn get_result_from_exit_code(desc: &TestDesc, code: i32) -> TestResult { 65 | fn run_test_in_process(desc: TestDesc, 66 | nocapture: bool, 67 | report_time: bool, 68 | - testfn: Box, 69 | + testfn: Box, 70 | monitor_ch: Sender) { 71 | // Buffer for capturing standard I/O 72 | let data = Arc::new(Mutex::new(Vec::new())); 73 | @@ -1623,7 +1611,7 @@ fn run_test_in_process(desc: TestDesc, 74 | } else { 75 | None 76 | }; 77 | - let result = catch_unwind(AssertUnwindSafe(testfn)); 78 | + let result = Ok::<(), Box>(testfn()); 79 | let exec_time = start.map(|start| { 80 | let duration = start.elapsed(); 81 | TestExecTime(duration) 82 | @@ -1688,7 +1676,7 @@ fn spawn_test_subprocess(desc: TestDesc, report_time: bool, monitor_ch: Sender) -> ! { 87 | +fn run_test_in_spawned_subprocess(desc: TestDesc, testfn: Box) -> ! { 88 | let builtin_panic_hook = panic::take_hook(); 89 | let record_result = Arc::new(move |panic_info: Option<&'_ PanicInfo<'_>>| { 90 | let test_result = match panic_info { 91 | -- 92 | 2.20.1 93 | 94 | -------------------------------------------------------------------------------- /src/trap.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | fn codegen_print(fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>, msg: &str) { 4 | let puts = fx 5 | .module 6 | .declare_function( 7 | "puts", 8 | Linkage::Import, 9 | &Signature { 10 | call_conv: crate::default_call_conv(fx.tcx.sess), 11 | params: vec![AbiParam::new(pointer_ty(fx.tcx))], 12 | returns: vec![], 13 | }, 14 | ) 15 | .unwrap(); 16 | let puts = fx.module.declare_func_in_func(puts, &mut fx.bcx.func); 17 | #[cfg(debug_assertions)] 18 | { 19 | fx.add_entity_comment(puts, "puts"); 20 | } 21 | 22 | let symbol_name = fx.tcx.symbol_name(fx.instance); 23 | let real_msg = format!("trap at {:?} ({}): {}\0", fx.instance, symbol_name, msg); 24 | let mut data_ctx = DataContext::new(); 25 | data_ctx.define(real_msg.as_bytes().to_vec().into_boxed_slice()); 26 | let msg_id = fx 27 | .module 28 | .declare_data( 29 | &(symbol_name.name.as_str().to_string() + msg), 30 | Linkage::Local, 31 | false, 32 | None, 33 | ) 34 | .unwrap(); 35 | 36 | // Ignore DuplicateDefinition error, as the data will be the same 37 | let _ = fx.module.define_data(msg_id, &data_ctx); 38 | 39 | let local_msg_id = fx.module.declare_data_in_func(msg_id, fx.bcx.func); 40 | #[cfg(debug_assertions)] 41 | { 42 | fx.add_entity_comment(local_msg_id, msg); 43 | } 44 | let msg_ptr = fx.bcx.ins().global_value(pointer_ty(fx.tcx), local_msg_id); 45 | fx.bcx.ins().call(puts, &[msg_ptr]); 46 | } 47 | 48 | /// Use this when `rustc_codegen_llvm` would insert a call to the panic handler. 49 | /// 50 | /// Trap code: user0 51 | pub fn trap_panic( 52 | fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>, 53 | msg: impl AsRef, 54 | ) { 55 | codegen_print(fx, msg.as_ref()); 56 | fx.bcx.ins().trap(TrapCode::User(0)); 57 | } 58 | 59 | /// Use this for example when a function call should never return. This will fill the current block, 60 | /// so you can **not** add instructions to it afterwards. 61 | /// 62 | /// Trap code: user65535 63 | pub fn trap_unreachable( 64 | fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>, 65 | msg: impl AsRef, 66 | ) { 67 | codegen_print(fx, msg.as_ref()); 68 | fx.bcx.ins().trap(TrapCode::User(!0)); 69 | } 70 | 71 | /// Use this when something is unimplemented, but `libcore` or `libstd` requires it to codegen. 72 | /// Unlike `trap_unreachable` this will not fill the current block, so you **must** add instructions 73 | /// to it afterwards. 74 | /// 75 | /// Trap code: user65535 76 | pub fn trap_unimplemented( 77 | fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>, 78 | msg: impl AsRef, 79 | ) { 80 | codegen_print(fx, msg.as_ref()); 81 | let true_ = fx.bcx.ins().iconst(types::I32, 1); 82 | fx.bcx.ins().trapnz(true_, TrapCode::User(!0)); 83 | } 84 | 85 | /// Like `trap_unreachable` but returns a fake value of the specified type. 86 | /// 87 | /// Trap code: user65535 88 | pub fn trap_unreachable_ret_value<'tcx>( 89 | fx: &mut FunctionCx<'_, 'tcx, impl cranelift_module::Backend>, 90 | dest_layout: TyLayout<'tcx>, 91 | msg: impl AsRef, 92 | ) -> CValue<'tcx> { 93 | trap_unimplemented(fx, msg); 94 | let zero = fx.bcx.ins().iconst(fx.pointer_type, 0); 95 | CValue::by_ref(zero, dest_layout) 96 | } 97 | 98 | /// Like `trap_unreachable` but returns a fake place for the specified type. 99 | /// 100 | /// Trap code: user65535 101 | pub fn trap_unreachable_ret_place<'tcx>( 102 | fx: &mut FunctionCx<'_, 'tcx, impl cranelift_module::Backend>, 103 | dest_layout: TyLayout<'tcx>, 104 | msg: impl AsRef, 105 | ) -> CPlace<'tcx> { 106 | trap_unimplemented(fx, msg); 107 | let zero = fx.bcx.ins().iconst(fx.pointer_type, 0); 108 | CPlace::for_addr(zero, dest_layout) 109 | } 110 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [[ "$1" == "--release" ]]; then 6 | export CHANNEL='release' 7 | cargo build --release 8 | else 9 | export CHANNEL='debug' 10 | cargo build 11 | fi 12 | 13 | source config.sh 14 | 15 | jit() { 16 | if [[ `uname` == 'Darwin' ]]; then 17 | # FIXME(#671) `dlsym` returns "symbol not found" for existing symbols on macOS. 18 | echo "[JIT] $1 (Ignored on macOS)" 19 | else 20 | echo "[JIT] $1" 21 | SHOULD_RUN=1 $RUSTC --crate-type bin -Cprefer-dynamic $2 22 | fi 23 | } 24 | 25 | rm -r target/out || true 26 | mkdir -p target/out/clif 27 | 28 | echo "[BUILD] mini_core" 29 | $RUSTC example/mini_core.rs --crate-name mini_core --crate-type lib,dylib 30 | 31 | echo "[BUILD] example" 32 | $RUSTC example/example.rs --crate-type lib 33 | 34 | JIT_ARGS="abc bcd" jit mini_core_hello_world example/mini_core_hello_world.rs 35 | 36 | echo "[AOT] mini_core_hello_world" 37 | $RUSTC example/mini_core_hello_world.rs --crate-name mini_core_hello_world --crate-type bin 38 | ./target/out/mini_core_hello_world abc bcd 39 | 40 | echo "[AOT] arbitrary_self_types_pointers_and_wrappers" 41 | $RUSTC example/arbitrary_self_types_pointers_and_wrappers.rs --crate-name arbitrary_self_types_pointers_and_wrappers --crate-type bin 42 | ./target/out/arbitrary_self_types_pointers_and_wrappers 43 | 44 | echo "[BUILD] sysroot" 45 | time ./build_sysroot/build_sysroot.sh 46 | 47 | echo "[AOT] alloc_example" 48 | $RUSTC example/alloc_example.rs --crate-type bin 49 | ./target/out/alloc_example 50 | 51 | jit std_example example/std_example.rs 52 | 53 | echo "[AOT] dst_field_align" 54 | $RUSTC example/dst-field-align.rs -Zmir-opt-level=2 --crate-name dst_field_align --crate-type bin 55 | ./target/out/dst_field_align 56 | 57 | echo "[AOT] std_example" 58 | $RUSTC example/std_example.rs --crate-type bin 59 | ./target/out/std_example 60 | 61 | echo "[BUILD] mod_bench" 62 | $RUSTC example/mod_bench.rs --crate-type bin 63 | 64 | # FIXME linker gives multiple definitions error on Linux 65 | #echo "[BUILD] sysroot in release mode" 66 | #./build_sysroot/build_sysroot.sh --release 67 | 68 | pushd simple-raytracer 69 | echo "[BENCH] ebobby/simple-raytracer" 70 | cargo clean && ../cargo.sh build 71 | cp ./target/*/debug/main ./raytracer_cg_clif 72 | 73 | hyperfine --runs ${RUN_RUNS:-10} ./raytracer_cg_llvm ./raytracer_cg_clif 74 | popd 75 | 76 | pushd regex 77 | echo "[TEST] rust-lang/regex example shootout-regex-dna" 78 | ../cargo.sh clean 79 | # Make sure `[codegen mono items] start` doesn't poison the diff 80 | ../cargo.sh build --example shootout-regex-dna 81 | cat examples/regexdna-input.txt | ../cargo.sh run --example shootout-regex-dna > res.txt 82 | diff -u res.txt examples/regexdna-output.txt 83 | 84 | echo "[TEST] rust-lang/regex tests" 85 | ../cargo.sh test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options 86 | popd 87 | 88 | echo 89 | echo "[BENCH COMPILE] mod_bench" 90 | 91 | COMPILE_MOD_BENCH_INLINE="$RUSTC example/mod_bench.rs --crate-type bin -Zmir-opt-level=3 -O --crate-name mod_bench_inline" 92 | COMPILE_MOD_BENCH_LLVM_0="rustc example/mod_bench.rs --crate-type bin -Copt-level=0 -o target/out/mod_bench_llvm_0 -Cpanic=abort" 93 | COMPILE_MOD_BENCH_LLVM_1="rustc example/mod_bench.rs --crate-type bin -Copt-level=1 -o target/out/mod_bench_llvm_1 -Cpanic=abort" 94 | COMPILE_MOD_BENCH_LLVM_2="rustc example/mod_bench.rs --crate-type bin -Copt-level=2 -o target/out/mod_bench_llvm_2 -Cpanic=abort" 95 | COMPILE_MOD_BENCH_LLVM_3="rustc example/mod_bench.rs --crate-type bin -Copt-level=3 -o target/out/mod_bench_llvm_3 -Cpanic=abort" 96 | 97 | # Use 100 runs, because a single compilations doesn't take more than ~150ms, so it isn't very slow 98 | hyperfine --runs ${COMPILE_RUNS:-100} "$COMPILE_MOD_BENCH_INLINE" "$COMPILE_MOD_BENCH_LLVM_0" "$COMPILE_MOD_BENCH_LLVM_1" "$COMPILE_MOD_BENCH_LLVM_2" "$COMPILE_MOD_BENCH_LLVM_3" 99 | 100 | echo 101 | echo "[BENCH RUN] mod_bench" 102 | hyperfine --runs ${RUN_RUNS:-10} ./target/out/mod_bench{,_inline} ./target/out/mod_bench_llvm_* 103 | -------------------------------------------------------------------------------- /src/allocator.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | use crate::prelude::*; 12 | 13 | use syntax::ext::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS}; 14 | 15 | /// Returns whether an allocator shim was created 16 | pub fn codegen(tcx: TyCtxt<'_>, module: &mut Module) -> bool { 17 | let any_dynamic_crate = tcx.dependency_formats(LOCAL_CRATE).iter().any(|(_, list)| { 18 | use rustc::middle::dependency_format::Linkage; 19 | list.iter().any(|&linkage| linkage == Linkage::Dynamic) 20 | }); 21 | if any_dynamic_crate { 22 | false 23 | } else if let Some(kind) = *tcx.sess.allocator_kind.get() { 24 | codegen_inner(tcx.sess, module, kind); 25 | true 26 | } else { 27 | false 28 | } 29 | } 30 | 31 | pub fn codegen_inner(sess: &Session, module: &mut Module, kind: AllocatorKind) { 32 | let usize_ty = module.target_config().pointer_type(); 33 | 34 | for method in ALLOCATOR_METHODS { 35 | let mut arg_tys = Vec::with_capacity(method.inputs.len()); 36 | for ty in method.inputs.iter() { 37 | match *ty { 38 | AllocatorTy::Layout => { 39 | arg_tys.push(usize_ty); // size 40 | arg_tys.push(usize_ty); // align 41 | } 42 | AllocatorTy::Ptr => arg_tys.push(usize_ty), 43 | AllocatorTy::Usize => arg_tys.push(usize_ty), 44 | 45 | AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"), 46 | } 47 | } 48 | let output = match method.output { 49 | AllocatorTy::ResultPtr => Some(usize_ty), 50 | AllocatorTy::Unit => None, 51 | 52 | AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { 53 | panic!("invalid allocator output") 54 | } 55 | }; 56 | 57 | let sig = Signature { 58 | call_conv: crate::default_call_conv(sess), 59 | params: arg_tys.iter().cloned().map(AbiParam::new).collect(), 60 | returns: output.into_iter().map(AbiParam::new).collect(), 61 | }; 62 | 63 | let caller_name = format!("__rust_{}", method.name); 64 | let callee_name = kind.fn_name(method.name); 65 | //eprintln!("Codegen allocator shim {} -> {} ({:?} -> {:?})", caller_name, callee_name, sig.params, sig.returns); 66 | 67 | let func_id = module 68 | .declare_function(&caller_name, Linkage::Export, &sig) 69 | .unwrap(); 70 | 71 | let callee_func_id = module 72 | .declare_function(&callee_name, Linkage::Import, &sig) 73 | .unwrap(); 74 | 75 | let mut ctx = Context::new(); 76 | ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig.clone()); 77 | { 78 | let mut func_ctx = FunctionBuilderContext::new(); 79 | let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); 80 | 81 | let ebb = bcx.create_ebb(); 82 | bcx.switch_to_block(ebb); 83 | let args = arg_tys 84 | .into_iter() 85 | .map(|ty| bcx.append_ebb_param(ebb, ty)) 86 | .collect::>(); 87 | 88 | let callee_func_ref = module.declare_func_in_func(callee_func_id, &mut bcx.func); 89 | 90 | let call_inst = bcx.ins().call(callee_func_ref, &args); 91 | 92 | let results = bcx.inst_results(call_inst).to_vec(); // Clone to prevent borrow error 93 | bcx.ins().return_(&results); 94 | bcx.seal_all_blocks(); 95 | bcx.finalize(); 96 | } 97 | module.define_function(func_id, &mut ctx).unwrap(); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main_shim.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | /// Create the `main` function which will initialize the rust runtime and call 4 | /// users main function. 5 | pub fn maybe_create_entry_wrapper(tcx: TyCtxt<'_>, module: &mut Module) { 6 | use rustc::middle::lang_items::StartFnLangItem; 7 | use rustc::session::config::EntryFnType; 8 | 9 | let (main_def_id, use_start_lang_item) = match tcx.entry_fn(LOCAL_CRATE) { 10 | Some((def_id, entry_ty)) => ( 11 | def_id, 12 | match entry_ty { 13 | EntryFnType::Main => true, 14 | EntryFnType::Start => false, 15 | }, 16 | ), 17 | None => return, 18 | }; 19 | 20 | create_entry_fn(tcx, module, main_def_id, use_start_lang_item); 21 | 22 | fn create_entry_fn( 23 | tcx: TyCtxt<'_>, 24 | m: &mut Module, 25 | rust_main_def_id: DefId, 26 | use_start_lang_item: bool, 27 | ) { 28 | let main_ret_ty = tcx.fn_sig(rust_main_def_id).output(); 29 | // Given that `main()` has no arguments, 30 | // then its return type cannot have 31 | // late-bound regions, since late-bound 32 | // regions must appear in the argument 33 | // listing. 34 | let main_ret_ty = tcx.erase_regions(&main_ret_ty.no_bound_vars().unwrap()); 35 | 36 | let cmain_sig = Signature { 37 | params: vec![ 38 | AbiParam::new(m.target_config().pointer_type()), 39 | AbiParam::new(m.target_config().pointer_type()), 40 | ], 41 | returns: vec![AbiParam::new( 42 | m.target_config().pointer_type(), /*isize*/ 43 | )], 44 | call_conv: crate::default_call_conv(tcx.sess), 45 | }; 46 | 47 | let cmain_func_id = m 48 | .declare_function("main", Linkage::Export, &cmain_sig) 49 | .unwrap(); 50 | 51 | let instance = Instance::mono(tcx, rust_main_def_id); 52 | 53 | let (main_name, main_sig) = get_function_name_and_sig(tcx, instance, false); 54 | let main_func_id = m 55 | .declare_function(&main_name, Linkage::Import, &main_sig) 56 | .unwrap(); 57 | 58 | let mut ctx = Context::new(); 59 | ctx.func = Function::with_name_signature(ExternalName::user(0, 0), cmain_sig.clone()); 60 | { 61 | let mut func_ctx = FunctionBuilderContext::new(); 62 | let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); 63 | 64 | let ebb = bcx.create_ebb(); 65 | bcx.switch_to_block(ebb); 66 | let arg_argc = bcx.append_ebb_param(ebb, m.target_config().pointer_type()); 67 | let arg_argv = bcx.append_ebb_param(ebb, m.target_config().pointer_type()); 68 | 69 | let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func); 70 | 71 | let call_inst = if use_start_lang_item { 72 | let start_def_id = tcx.require_lang_item(StartFnLangItem, None); 73 | let start_instance = Instance::resolve( 74 | tcx, 75 | ParamEnv::reveal_all(), 76 | start_def_id, 77 | tcx.intern_substs(&[main_ret_ty.into()]), 78 | ) 79 | .unwrap(); 80 | let start_func_id = import_function(tcx, m, start_instance); 81 | 82 | let main_val = bcx 83 | .ins() 84 | .func_addr(m.target_config().pointer_type(), main_func_ref); 85 | 86 | let func_ref = m.declare_func_in_func(start_func_id, &mut bcx.func); 87 | bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv]) 88 | } else { 89 | // using user-defined start fn 90 | bcx.ins().call(main_func_ref, &[arg_argc, arg_argv]) 91 | }; 92 | 93 | let result = bcx.inst_results(call_inst)[0]; 94 | bcx.ins().return_(&[result]); 95 | bcx.seal_all_blocks(); 96 | bcx.finalize(); 97 | } 98 | m.define_function(cmain_func_id, &mut ctx).unwrap(); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /patches/0015-Remove-usage-of-unsized-locals.patch: -------------------------------------------------------------------------------- 1 | From 7403e2998345ef0650fd50628d7098d4d1e88e5c Mon Sep 17 00:00:00 2001 2 | From: bjorn3 3 | Date: Sat, 6 Apr 2019 12:16:21 +0200 4 | Subject: [PATCH] Remove usage of unsized locals 5 | 6 | --- 7 | src/liballoc/boxed.rs | 23 ----------------------- 8 | src/libstd/sys_common/at_exit_imp.rs | 2 ++ 9 | src/libstd/sys_common/mod.rs | 1 - 10 | src/libstd/sys_common/thread.rs | 7 +------ 11 | 4 files changed, 3 insertions(+), 30 deletions(-) 12 | 13 | diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs 14 | index f6dee7c..0c6a8c0 100644 15 | --- a/src/liballoc/boxed.rs 16 | +++ b/src/liballoc/boxed.rs 17 | @@ -694,29 +694,6 @@ impl ExactSizeIterator for Box { 18 | #[stable(feature = "fused", since = "1.26.0")] 19 | impl FusedIterator for Box {} 20 | 21 | -#[stable(feature = "boxed_closure_impls", since = "1.35.0")] 22 | -impl + ?Sized> FnOnce for Box { 23 | - type Output = >::Output; 24 | - 25 | - extern "rust-call" fn call_once(self, args: A) -> Self::Output { 26 | - >::call_once(*self, args) 27 | - } 28 | -} 29 | - 30 | -#[stable(feature = "boxed_closure_impls", since = "1.35.0")] 31 | -impl + ?Sized> FnMut for Box { 32 | - extern "rust-call" fn call_mut(&mut self, args: A) -> Self::Output { 33 | - >::call_mut(self, args) 34 | - } 35 | -} 36 | - 37 | -#[stable(feature = "boxed_closure_impls", since = "1.35.0")] 38 | -impl + ?Sized> Fn for Box { 39 | - extern "rust-call" fn call(&self, args: A) -> Self::Output { 40 | - >::call(self, args) 41 | - } 42 | -} 43 | - 44 | #[unstable(feature = "coerce_unsized", issue = "27732")] 45 | impl, U: ?Sized> CoerceUnsized> for Box {} 46 | 47 | diff --git a/src/libstd/sys_common/at_exit_imp.rs b/src/libstd/sys_common/at_exit_imp.rs 48 | index 1181b86..20f9251 100644 49 | --- a/src/libstd/sys_common/at_exit_imp.rs 50 | +++ b/src/libstd/sys_common/at_exit_imp.rs 51 | @@ -38,6 +38,7 @@ unsafe fn init() -> bool { 52 | true 53 | } 54 | 55 | +/* 56 | pub fn cleanup() { 57 | for i in 1..=ITERS { 58 | unsafe { 59 | @@ -60,6 +61,7 @@ pub fn cleanup() { 60 | } 61 | } 62 | } 63 | +*/ 64 | 65 | pub fn push(f: Box) -> bool { 66 | unsafe { 67 | diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs 68 | index 6260c3b..611ed7e 100644 69 | --- a/src/libstd/sys_common/mod.rs 70 | +++ b/src/libstd/sys_common/mod.rs 71 | @@ -127,7 +127,6 @@ pub fn cleanup() { 72 | CLEANUP.call_once(|| unsafe { 73 | sys::args::cleanup(); 74 | sys::stack_overflow::cleanup(); 75 | - at_exit_imp::cleanup(); 76 | }); 77 | } 78 | 79 | diff --git a/src/libstd/sys_common/thread.rs b/src/libstd/sys_common/thread.rs 80 | index b2142e7..718bb1c 100644 81 | --- a/src/libstd/sys_common/thread.rs 82 | +++ b/src/libstd/sys_common/thread.rs 83 | @@ -6,12 +6,7 @@ use crate::sys::thread as imp; 84 | 85 | #[allow(dead_code)] 86 | pub unsafe fn start_thread(main: *mut u8) { 87 | - // Next, set up our stack overflow handler which may get triggered if we run 88 | - // out of stack. 89 | - let _handler = stack_overflow::Handler::new(); 90 | - 91 | - // Finally, let's run some code. 92 | - Box::from_raw(main as *mut Box)() 93 | + panic!("Threads are not yet supported, because cranelift doesn't support atomics."); 94 | } 95 | 96 | pub fn min_stack() -> usize { 97 | diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs 98 | index f4a1783..362b537 100644 99 | --- a/src/libstd/sys/unix/thread.rs 100 | +++ b/src/libstd/sys/unix/thread.rs 101 | @@ -40,6 +40,8 @@ impl Thread { 102 | // unsafe: see thread::Builder::spawn_unchecked for safety requirements 103 | pub unsafe fn new(stack: usize, p: Box) 104 | -> io::Result { 105 | + panic!("Threads are not yet supported, because cranelift doesn't support atomics."); 106 | + 107 | let p = box p; 108 | let mut native: libc::pthread_t = mem::zeroed(); 109 | let mut attr: libc::pthread_attr_t = mem::zeroed(); 110 | -- 111 | 2.20.1 (Apple Git-117) 112 | -------------------------------------------------------------------------------- /example/example.rs: -------------------------------------------------------------------------------- 1 | #![feature(no_core, unboxed_closures)] 2 | #![no_core] 3 | #![allow(dead_code)] 4 | 5 | extern crate mini_core; 6 | 7 | use mini_core::*; 8 | 9 | fn abc(a: u8) -> u8 { 10 | a * 2 11 | } 12 | 13 | fn bcd(b: bool, a: u8) -> u8 { 14 | if b { 15 | a * 2 16 | } else { 17 | a * 3 18 | } 19 | } 20 | 21 | fn call() { 22 | abc(42); 23 | } 24 | 25 | fn indirect_call() { 26 | let f: fn() = call; 27 | f(); 28 | } 29 | 30 | enum BoolOption { 31 | Some(bool), 32 | None, 33 | } 34 | 35 | fn option_unwrap_or(o: BoolOption, d: bool) -> bool { 36 | match o { 37 | BoolOption::Some(b) => b, 38 | BoolOption::None => d, 39 | } 40 | } 41 | 42 | fn ret_42() -> u8 { 43 | 42 44 | } 45 | 46 | fn return_str() -> &'static str { 47 | "hello world" 48 | } 49 | 50 | fn promoted_val() -> &'static u8 { 51 | &(1 * 2) 52 | } 53 | 54 | fn cast_ref_to_raw_ptr(abc: &u8) -> *const u8 { 55 | abc as *const u8 56 | } 57 | 58 | fn cmp_raw_ptr(a: *const u8, b: *const u8) -> bool { 59 | a == b 60 | } 61 | 62 | fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u32) { 63 | ( 64 | a as u8, a as u16, a as u32, a as usize, a as i8, a as i16, a as i32, a as isize, b as u8, 65 | b as u32, 66 | ) 67 | } 68 | 69 | fn char_cast(c: char) -> u8 { 70 | c as u8 71 | } 72 | 73 | pub struct DebugTuple(()); 74 | 75 | fn debug_tuple() -> DebugTuple { 76 | DebugTuple(()) 77 | } 78 | 79 | fn size_of() -> usize { 80 | intrinsics::size_of::() 81 | } 82 | 83 | fn use_size_of() -> usize { 84 | size_of::() 85 | } 86 | 87 | unsafe fn use_copy_intrinsic(src: *const u8, dst: *mut u8) { 88 | intrinsics::copy::(src, dst, 1); 89 | } 90 | 91 | unsafe fn use_copy_intrinsic_ref(src: *const u8, dst: *mut u8) { 92 | let copy2 = &intrinsics::copy::; 93 | copy2(src, dst, 1); 94 | } 95 | 96 | const ABC: u8 = 6 * 7; 97 | 98 | fn use_const() -> u8 { 99 | ABC 100 | } 101 | 102 | pub fn call_closure_3arg() { 103 | (|_, _, _| {})(0u8, 42u16, 0u8) 104 | } 105 | 106 | pub fn call_closure_2arg() { 107 | (|_, _| {})(0u8, 42u16) 108 | } 109 | 110 | struct IsNotEmpty; 111 | 112 | impl<'a, 'b> FnOnce<(&'a &'b [u16],)> for IsNotEmpty { 113 | type Output = (u8, u8); 114 | 115 | #[inline] 116 | extern "rust-call" fn call_once(mut self, arg: (&'a &'b [u16],)) -> (u8, u8) { 117 | self.call_mut(arg) 118 | } 119 | } 120 | 121 | impl<'a, 'b> FnMut<(&'a &'b [u16],)> for IsNotEmpty { 122 | #[inline] 123 | extern "rust-call" fn call_mut(&mut self, _arg: (&'a &'b [u16],)) -> (u8, u8) { 124 | (0, 42) 125 | } 126 | } 127 | 128 | pub fn call_is_not_empty() { 129 | IsNotEmpty.call_once((&(&[0u16] as &[_]),)); 130 | } 131 | 132 | fn eq_char(a: char, b: char) -> bool { 133 | a == b 134 | } 135 | 136 | unsafe fn transmute(c: char) -> u32 { 137 | intrinsics::transmute(c) 138 | } 139 | 140 | unsafe fn deref_str_ptr(s: *const str) -> &'static str { 141 | &*s 142 | } 143 | 144 | fn use_array(arr: [u8; 3]) -> u8 { 145 | arr[1] 146 | } 147 | 148 | fn repeat_array() -> [u8; 3] { 149 | [0; 3] 150 | } 151 | 152 | fn array_as_slice(arr: &[u8; 3]) -> &[u8] { 153 | arr 154 | } 155 | 156 | unsafe fn use_ctlz_nonzero(a: u16) -> u16 { 157 | intrinsics::ctlz_nonzero(a) 158 | } 159 | 160 | fn ptr_as_usize(ptr: *const u8) -> usize { 161 | ptr as usize 162 | } 163 | 164 | fn float_cast(a: f32, b: f64) -> (f64, f32) { 165 | (a as f64, b as f32) 166 | } 167 | 168 | fn int_to_float(a: u8, b: i32) -> (f64, f32) { 169 | (a as f64, b as f32) 170 | } 171 | 172 | fn make_array() -> [u8; 3] { 173 | [42, 0, 5] 174 | } 175 | 176 | fn some_promoted_tuple() -> &'static (&'static str, &'static str) { 177 | &("abc", "some") 178 | } 179 | 180 | fn index_slice(s: &[u8]) -> u8 { 181 | s[2] 182 | } 183 | 184 | pub struct StrWrapper { 185 | s: str, 186 | } 187 | 188 | fn str_wrapper_get(w: &StrWrapper) -> &str { 189 | &w.s 190 | } 191 | 192 | fn i16_as_i8(a: i16) -> i8 { 193 | a as i8 194 | } 195 | 196 | struct Unsized(u8, str); 197 | 198 | fn get_sized_field_ref_from_unsized_type(u: &Unsized) -> &u8 { 199 | &u.0 200 | } 201 | 202 | fn get_unsized_field_ref_from_unsized_type(u: &Unsized) -> &str { 203 | &u.1 204 | } 205 | 206 | pub fn reuse_byref_argument_storage(a: (u8, u16, u32)) -> u8 { 207 | a.0 208 | } 209 | -------------------------------------------------------------------------------- /src/metadata.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::path::Path; 3 | 4 | use rustc::middle::cstore::{EncodedMetadata, MetadataLoader}; 5 | use rustc::session::config; 6 | use rustc::ty::TyCtxt; 7 | use rustc_codegen_ssa::METADATA_FILENAME; 8 | use rustc_data_structures::owning_ref::{self, OwningRef}; 9 | use rustc_data_structures::rustc_erase_owner; 10 | use rustc_target::spec::Target; 11 | 12 | pub struct CraneliftMetadataLoader; 13 | 14 | impl MetadataLoader for CraneliftMetadataLoader { 15 | fn get_rlib_metadata( 16 | &self, 17 | _target: &Target, 18 | path: &Path, 19 | ) -> Result, String> { 20 | let mut archive = ar::Archive::new(File::open(path).map_err(|e| format!("{:?}", e))?); 21 | // Iterate over all entries in the archive: 22 | while let Some(entry_result) = archive.next_entry() { 23 | let mut entry = entry_result.map_err(|e| format!("{:?}", e))?; 24 | if entry.header().identifier() == METADATA_FILENAME.as_bytes() { 25 | let mut buf = Vec::new(); 26 | ::std::io::copy(&mut entry, &mut buf).map_err(|e| format!("{:?}", e))?; 27 | let buf: OwningRef, [u8]> = OwningRef::new(buf).into(); 28 | return Ok(rustc_erase_owner!(buf.map_owner_box())); 29 | } 30 | } 31 | 32 | Err("couldn't find metadata entry".to_string()) 33 | //self.get_dylib_metadata(target, path) 34 | } 35 | 36 | fn get_dylib_metadata( 37 | &self, 38 | _target: &Target, 39 | path: &Path, 40 | ) -> Result, String> { 41 | use object::Object; 42 | let file = std::fs::read(path).map_err(|e| format!("read:{:?}", e))?; 43 | let file = object::File::parse(&file).map_err(|e| format!("parse: {:?}", e))?; 44 | let buf = file 45 | .section_data_by_name(".rustc") 46 | .ok_or("no .rustc section")? 47 | .into_owned(); 48 | let buf: OwningRef, [u8]> = OwningRef::new(buf).into(); 49 | Ok(rustc_erase_owner!(buf.map_owner_box())) 50 | } 51 | } 52 | 53 | // Adapted from https://github.com/rust-lang/rust/blob/da573206f87b5510de4b0ee1a9c044127e409bd3/src/librustc_codegen_llvm/base.rs#L47-L112 54 | pub fn write_metadata(tcx: TyCtxt<'_>, artifact: &mut faerie::Artifact) -> EncodedMetadata { 55 | use flate2::write::DeflateEncoder; 56 | use flate2::Compression; 57 | use std::io::Write; 58 | 59 | #[derive(PartialEq, Eq, PartialOrd, Ord)] 60 | enum MetadataKind { 61 | None, 62 | Uncompressed, 63 | Compressed, 64 | } 65 | 66 | let kind = tcx 67 | .sess 68 | .crate_types 69 | .borrow() 70 | .iter() 71 | .map(|ty| match *ty { 72 | config::CrateType::Executable 73 | | config::CrateType::Staticlib 74 | | config::CrateType::Cdylib => MetadataKind::None, 75 | 76 | config::CrateType::Rlib => MetadataKind::Uncompressed, 77 | 78 | config::CrateType::Dylib | config::CrateType::ProcMacro => MetadataKind::Compressed, 79 | }) 80 | .max() 81 | .unwrap_or(MetadataKind::None); 82 | 83 | if kind == MetadataKind::None { 84 | return EncodedMetadata::new(); 85 | } 86 | 87 | let metadata = tcx.encode_metadata(); 88 | if kind == MetadataKind::Uncompressed { 89 | return metadata; 90 | } 91 | 92 | assert!(kind == MetadataKind::Compressed); 93 | let mut compressed = tcx.metadata_encoding_version(); 94 | DeflateEncoder::new(&mut compressed, Compression::fast()) 95 | .write_all(&metadata.raw_data) 96 | .unwrap(); 97 | 98 | artifact 99 | .declare(".rustc", faerie::Decl::section(faerie::SectionKind::Data)) 100 | .unwrap(); 101 | artifact 102 | .define_with_symbols(".rustc", compressed, { 103 | let mut map = std::collections::BTreeMap::new(); 104 | // FIXME implement faerie elf backend section custom symbols 105 | // For MachO this is necessary to prevent the linker from throwing away the .rustc section, 106 | // but for ELF it isn't. 107 | if tcx.sess.target.target.options.is_like_osx { 108 | map.insert( 109 | rustc::middle::exported_symbols::metadata_symbol_name(tcx), 110 | 0, 111 | ); 112 | } 113 | map 114 | }) 115 | .unwrap(); 116 | 117 | metadata 118 | } 119 | -------------------------------------------------------------------------------- /src/llvm_intrinsics.rs: -------------------------------------------------------------------------------- 1 | use crate::intrinsics::*; 2 | use crate::prelude::*; 3 | 4 | use rustc::ty::subst::SubstsRef; 5 | 6 | pub fn codegen_llvm_intrinsic_call<'tcx>( 7 | fx: &mut FunctionCx<'_, 'tcx, impl Backend>, 8 | intrinsic: &str, 9 | substs: SubstsRef<'tcx>, 10 | args: &[mir::Operand<'tcx>], 11 | destination: Option<(CPlace<'tcx>, BasicBlock)>, 12 | ) { 13 | let ret = match destination { 14 | Some((place, _)) => place, 15 | None => { 16 | // Insert non returning intrinsics here 17 | match intrinsic { 18 | "abort" => { 19 | trap_panic(fx, "Called intrinsic::abort."); 20 | } 21 | "unreachable" => { 22 | trap_unreachable(fx, "[corruption] Called intrinsic::unreachable."); 23 | } 24 | _ => unimplemented!("unsupported instrinsic {}", intrinsic), 25 | } 26 | return; 27 | } 28 | }; 29 | 30 | intrinsic_match! { 31 | fx, intrinsic, substs, args, 32 | _ => { 33 | fx.tcx.sess.warn(&format!("unsupported llvm intrinsic {}; replacing with trap", intrinsic)); 34 | crate::trap::trap_unimplemented(fx, intrinsic); 35 | }; 36 | 37 | // Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8` 38 | llvm.x86.sse2.pmovmskb.128 | llvm.x86.avx2.pmovmskb | llvm.x86.sse2.movmsk.pd, (c a) { 39 | let (lane_layout, lane_count) = lane_type_and_count(fx, a.layout(), intrinsic); 40 | let lane_ty = fx.clif_type(lane_layout.ty).unwrap(); 41 | assert!(lane_count <= 32); 42 | 43 | let mut res = fx.bcx.ins().iconst(types::I32, 0); 44 | 45 | for lane in (0..lane_count).rev() { 46 | let a_lane = a.value_field(fx, mir::Field::new(lane.try_into().unwrap())).load_scalar(fx); 47 | 48 | // cast float to int 49 | let a_lane = match lane_ty { 50 | types::F32 => fx.bcx.ins().bitcast(types::I32, a_lane), 51 | types::F64 => fx.bcx.ins().bitcast(types::I64, a_lane), 52 | _ => a_lane, 53 | }; 54 | 55 | // extract sign bit of an int 56 | let a_lane_sign = fx.bcx.ins().ushr_imm(a_lane, i64::from(lane_ty.bits() - 1)); 57 | 58 | // shift sign bit into result 59 | let a_lane_sign = clif_intcast(fx, a_lane_sign, types::I32, false); 60 | res = fx.bcx.ins().ishl_imm(res, 1); 61 | res = fx.bcx.ins().bor(res, a_lane_sign); 62 | } 63 | 64 | let res = CValue::by_val(res, fx.layout_of(fx.tcx.types.i32)); 65 | ret.write_cvalue(fx, res); 66 | }; 67 | llvm.x86.sse2.cmp.ps | llvm.x86.sse2.cmp.pd, (c x, c y, o kind) { 68 | let kind_const = crate::constant::mir_operand_get_const_val(fx, kind).expect("llvm.x86.sse2.cmp.* kind not const"); 69 | let flt_cc = match kind_const.val.try_to_bits(Size::from_bytes(1)).expect(&format!("kind not scalar: {:?}", kind_const)) { 70 | 0 => FloatCC::Equal, 71 | 1 => FloatCC::LessThan, 72 | 2 => FloatCC::LessThanOrEqual, 73 | 7 => { 74 | unimplemented!("Compares corresponding elements in `a` and `b` to see if neither is `NaN`."); 75 | } 76 | 3 => { 77 | unimplemented!("Compares corresponding elements in `a` and `b` to see if either is `NaN`."); 78 | } 79 | 4 => FloatCC::NotEqual, 80 | 5 => { 81 | unimplemented!("not less than"); 82 | } 83 | 6 => { 84 | unimplemented!("not less than or equal"); 85 | } 86 | kind => unreachable!("kind {:?}", kind), 87 | }; 88 | 89 | simd_for_each_lane(fx, intrinsic, x, y, ret, |fx, lane_layout, res_lane_layout, x_lane, y_lane| { 90 | let res_lane = match lane_layout.ty.kind { 91 | ty::Float(_) => fx.bcx.ins().fcmp(flt_cc, x_lane, y_lane), 92 | _ => unreachable!("{:?}", lane_layout.ty), 93 | }; 94 | bool_to_zero_or_max_uint(fx, res_lane_layout, res_lane) 95 | }); 96 | }; 97 | } 98 | 99 | if let Some((_, dest)) = destination { 100 | let ret_ebb = fx.get_ebb(dest); 101 | fx.bcx.ins().jump(ret_ebb, &[]); 102 | } else { 103 | trap_unreachable(fx, "[corruption] Diverging intrinsic returned."); 104 | } 105 | } 106 | 107 | // llvm.x86.avx2.vperm2i128 108 | // llvm.x86.ssse3.pshuf.b.128 109 | // llvm.x86.avx2.pshuf.b 110 | // llvm.x86.avx2.psrli.w 111 | // llvm.x86.sse2.psrli.w 112 | -------------------------------------------------------------------------------- /src/abi/pass_mode.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | #[derive(Copy, Clone, Debug)] 4 | pub enum PassMode { 5 | NoPass, 6 | ByVal(Type), 7 | ByValPair(Type, Type), 8 | ByRef, 9 | } 10 | 11 | #[derive(Copy, Clone, Debug)] 12 | pub enum EmptySinglePair { 13 | Empty, 14 | Single(T), 15 | Pair(T, T), 16 | } 17 | 18 | impl EmptySinglePair { 19 | pub fn into_iter(self) -> EmptySinglePairIter { 20 | EmptySinglePairIter(self) 21 | } 22 | 23 | pub fn map(self, mut f: impl FnMut(T) -> U) -> EmptySinglePair { 24 | match self { 25 | Empty => Empty, 26 | Single(v) => Single(f(v)), 27 | Pair(a, b) => Pair(f(a), f(b)), 28 | } 29 | } 30 | } 31 | 32 | pub struct EmptySinglePairIter(EmptySinglePair); 33 | 34 | impl Iterator for EmptySinglePairIter { 35 | type Item = T; 36 | 37 | fn next(&mut self) -> Option { 38 | match std::mem::replace(&mut self.0, Empty) { 39 | Empty => None, 40 | Single(v) => Some(v), 41 | Pair(a, b) => { 42 | self.0 = Single(b); 43 | Some(a) 44 | } 45 | } 46 | } 47 | } 48 | 49 | impl EmptySinglePair { 50 | pub fn assert_single(self) -> T { 51 | match self { 52 | Single(v) => v, 53 | _ => panic!("Called assert_single on {:?}", self), 54 | } 55 | } 56 | 57 | pub fn assert_pair(self) -> (T, T) { 58 | match self { 59 | Pair(a, b) => (a, b), 60 | _ => panic!("Called assert_pair on {:?}", self), 61 | } 62 | } 63 | } 64 | 65 | pub use EmptySinglePair::*; 66 | 67 | impl PassMode { 68 | pub fn get_param_ty(self, tcx: TyCtxt<'_>) -> EmptySinglePair { 69 | match self { 70 | PassMode::NoPass => Empty, 71 | PassMode::ByVal(clif_type) => Single(clif_type), 72 | PassMode::ByValPair(a, b) => Pair(a, b), 73 | PassMode::ByRef => Single(pointer_ty(tcx)), 74 | } 75 | } 76 | } 77 | 78 | pub fn get_pass_mode<'tcx>(tcx: TyCtxt<'tcx>, layout: TyLayout<'tcx>) -> PassMode { 79 | assert!(!layout.is_unsized()); 80 | 81 | if layout.is_zst() { 82 | // WARNING zst arguments must never be passed, as that will break CastKind::ClosureFnPointer 83 | PassMode::NoPass 84 | } else { 85 | match &layout.abi { 86 | layout::Abi::Uninhabited => PassMode::NoPass, 87 | layout::Abi::Scalar(scalar) => { 88 | PassMode::ByVal(scalar_to_clif_type(tcx, scalar.clone())) 89 | } 90 | layout::Abi::ScalarPair(a, b) => { 91 | let a = scalar_to_clif_type(tcx, a.clone()); 92 | let b = scalar_to_clif_type(tcx, b.clone()); 93 | if a == types::I128 && b == types::I128 { 94 | // Returning (i128, i128) by-val-pair would take 4 regs, while only 3 are 95 | // available on x86_64. Cranelift gets confused when too many return params 96 | // are used. 97 | PassMode::ByRef 98 | } else { 99 | PassMode::ByValPair(a, b) 100 | } 101 | } 102 | 103 | // FIXME implement Vector Abi in a cg_llvm compatible way 104 | layout::Abi::Vector { .. } => PassMode::ByRef, 105 | 106 | layout::Abi::Aggregate { .. } => PassMode::ByRef, 107 | } 108 | } 109 | } 110 | 111 | pub fn adjust_arg_for_abi<'tcx>( 112 | fx: &mut FunctionCx<'_, 'tcx, impl Backend>, 113 | arg: CValue<'tcx>, 114 | ) -> EmptySinglePair { 115 | match get_pass_mode(fx.tcx, arg.layout()) { 116 | PassMode::NoPass => Empty, 117 | PassMode::ByVal(_) => Single(arg.load_scalar(fx)), 118 | PassMode::ByValPair(_, _) => { 119 | let (a, b) = arg.load_scalar_pair(fx); 120 | Pair(a, b) 121 | } 122 | PassMode::ByRef => Single(arg.force_stack(fx)), 123 | } 124 | } 125 | 126 | pub fn cvalue_for_param<'tcx>( 127 | fx: &mut FunctionCx<'_, 'tcx, impl Backend>, 128 | start_ebb: Ebb, 129 | local: mir::Local, 130 | local_field: Option, 131 | arg_ty: Ty<'tcx>, 132 | ) -> Option> { 133 | let layout = fx.layout_of(arg_ty); 134 | let pass_mode = get_pass_mode(fx.tcx, fx.layout_of(arg_ty)); 135 | 136 | if let PassMode::NoPass = pass_mode { 137 | return None; 138 | } 139 | 140 | let clif_types = pass_mode.get_param_ty(fx.tcx); 141 | let ebb_params = clif_types.map(|t| fx.bcx.append_ebb_param(start_ebb, t)); 142 | 143 | #[cfg(debug_assertions)] 144 | crate::abi::comments::add_arg_comment( 145 | fx, 146 | "arg", 147 | local, 148 | local_field, 149 | ebb_params, 150 | pass_mode, 151 | arg_ty, 152 | ); 153 | 154 | match pass_mode { 155 | PassMode::NoPass => unreachable!(), 156 | PassMode::ByVal(_) => Some(CValue::by_val(ebb_params.assert_single(), layout)), 157 | PassMode::ByValPair(_, _) => { 158 | let (a, b) = ebb_params.assert_pair(); 159 | Some(CValue::by_val_pair(a, b, layout)) 160 | } 161 | PassMode::ByRef => Some(CValue::by_ref(ebb_params.assert_single(), layout)), 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/vtable.rs: -------------------------------------------------------------------------------- 1 | //! See librustc_codegen_llvm/meth.rs for reference 2 | 3 | use crate::prelude::*; 4 | 5 | const DROP_FN_INDEX: usize = 0; 6 | const SIZE_INDEX: usize = 1; 7 | const ALIGN_INDEX: usize = 2; 8 | 9 | pub fn drop_fn_of_obj(fx: &mut FunctionCx<'_, '_, impl Backend>, vtable: Value) -> Value { 10 | let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize; 11 | fx.bcx.ins().load( 12 | pointer_ty(fx.tcx), 13 | MemFlags::new(), 14 | vtable, 15 | (DROP_FN_INDEX * usize_size) as i32, 16 | ) 17 | } 18 | 19 | pub fn size_of_obj(fx: &mut FunctionCx<'_, '_, impl Backend>, vtable: Value) -> Value { 20 | let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize; 21 | fx.bcx.ins().load( 22 | pointer_ty(fx.tcx), 23 | MemFlags::new(), 24 | vtable, 25 | (SIZE_INDEX * usize_size) as i32, 26 | ) 27 | } 28 | 29 | pub fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, impl Backend>, vtable: Value) -> Value { 30 | let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize; 31 | fx.bcx.ins().load( 32 | pointer_ty(fx.tcx), 33 | MemFlags::new(), 34 | vtable, 35 | (ALIGN_INDEX * usize_size) as i32, 36 | ) 37 | } 38 | 39 | pub fn get_ptr_and_method_ref<'tcx>( 40 | fx: &mut FunctionCx<'_, 'tcx, impl Backend>, 41 | arg: CValue<'tcx>, 42 | idx: usize, 43 | ) -> (Value, Value) { 44 | let (ptr, vtable) = arg.load_scalar_pair(fx); 45 | let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes(); 46 | let func_ref = fx.bcx.ins().load( 47 | pointer_ty(fx.tcx), 48 | MemFlags::new(), 49 | vtable, 50 | ((idx + 3) * usize_size as usize) as i32, 51 | ); 52 | (ptr, func_ref) 53 | } 54 | 55 | pub fn get_vtable<'tcx>( 56 | fx: &mut FunctionCx<'_, 'tcx, impl Backend>, 57 | ty: Ty<'tcx>, 58 | trait_ref: Option>, 59 | ) -> Value { 60 | let data_id = if let Some(data_id) = fx.caches.vtables.get(&(ty, trait_ref)) { 61 | *data_id 62 | } else { 63 | let data_id = build_vtable(fx, ty, trait_ref); 64 | fx.caches.vtables.insert((ty, trait_ref), data_id); 65 | data_id 66 | }; 67 | 68 | let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); 69 | fx.bcx.ins().global_value(fx.pointer_type, local_data_id) 70 | } 71 | 72 | fn build_vtable<'tcx>( 73 | fx: &mut FunctionCx<'_, 'tcx, impl Backend>, 74 | ty: Ty<'tcx>, 75 | trait_ref: Option>, 76 | ) -> DataId { 77 | let tcx = fx.tcx; 78 | let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize; 79 | 80 | let drop_in_place_fn = 81 | import_function(tcx, fx.module, Instance::resolve_drop_in_place(tcx, ty)); 82 | 83 | let mut components: Vec<_> = vec![Some(drop_in_place_fn), None, None]; 84 | 85 | let methods_root; 86 | let methods = if let Some(trait_ref) = trait_ref { 87 | methods_root = tcx.vtable_methods(trait_ref.with_self_ty(tcx, ty)); 88 | methods_root.iter() 89 | } else { 90 | (&[]).iter() 91 | }; 92 | let methods = methods.cloned().map(|opt_mth| { 93 | opt_mth.map_or(None, |(def_id, substs)| { 94 | Some(import_function( 95 | tcx, 96 | fx.module, 97 | Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), def_id, substs).unwrap(), 98 | )) 99 | }) 100 | }); 101 | components.extend(methods); 102 | 103 | let mut data_ctx = DataContext::new(); 104 | let mut data = ::std::iter::repeat(0u8) 105 | .take(components.len() * usize_size) 106 | .collect::>() 107 | .into_boxed_slice(); 108 | 109 | let layout = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap(); 110 | write_usize(fx.tcx, &mut data, SIZE_INDEX, layout.size.bytes()); 111 | write_usize(fx.tcx, &mut data, ALIGN_INDEX, layout.align.abi.bytes()); 112 | data_ctx.define(data); 113 | 114 | for (i, component) in components.into_iter().enumerate() { 115 | if let Some(func_id) = component { 116 | let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx); 117 | data_ctx.write_function_addr((i * usize_size) as u32, func_ref); 118 | } 119 | } 120 | 121 | let data_id = fx 122 | .module 123 | .declare_data( 124 | &format!("vtable.{:?}.for.{:?}", trait_ref, ty), 125 | Linkage::Local, 126 | false, 127 | Some( 128 | fx.tcx 129 | .data_layout 130 | .pointer_align 131 | .pref 132 | .bytes() 133 | .try_into() 134 | .unwrap(), 135 | ), 136 | ) 137 | .unwrap(); 138 | 139 | match fx.module.define_data(data_id, &data_ctx) { 140 | Ok(()) | Err(cranelift_module::ModuleError::DuplicateDefinition(_)) => {} 141 | err => err.unwrap(), 142 | } 143 | 144 | data_id 145 | } 146 | 147 | fn write_usize(tcx: TyCtxt, buf: &mut [u8], idx: usize, num: u64) { 148 | use byteorder::{BigEndian, LittleEndian, WriteBytesExt}; 149 | 150 | let usize_size = tcx 151 | .layout_of(ParamEnv::reveal_all().and(tcx.types.usize)) 152 | .unwrap() 153 | .size 154 | .bytes() as usize; 155 | let mut target = &mut buf[idx * usize_size..(idx + 1) * usize_size]; 156 | 157 | match tcx.data_layout.endian { 158 | layout::Endian::Little => target.write_uint::(num, usize_size), 159 | layout::Endian::Big => target.write_uint::(num, usize_size), 160 | } 161 | .unwrap() 162 | } 163 | -------------------------------------------------------------------------------- /src/target_features_whitelist.rs: -------------------------------------------------------------------------------- 1 | use syntax::symbol::{sym, Symbol}; 2 | 3 | use rustc::session::Session; 4 | 5 | // Copied from https://github.com/rust-lang/rust/blob/f69b07144a151f46aaee1b6230ba4160e9394562/src/librustc_codegen_llvm/llvm_util.rs#L93-L264 6 | 7 | // WARNING: the features after applying `to_llvm_feature` must be known 8 | // to LLVM or the feature detection code will walk past the end of the feature 9 | // array, leading to crashes. 10 | 11 | const ARM_WHITELIST: &[(&str, Option)] = &[ 12 | ("aclass", Some(sym::arm_target_feature)), 13 | ("mclass", Some(sym::arm_target_feature)), 14 | ("rclass", Some(sym::arm_target_feature)), 15 | ("dsp", Some(sym::arm_target_feature)), 16 | ("neon", Some(sym::arm_target_feature)), 17 | ("v5te", Some(sym::arm_target_feature)), 18 | ("v6", Some(sym::arm_target_feature)), 19 | ("v6k", Some(sym::arm_target_feature)), 20 | ("v6t2", Some(sym::arm_target_feature)), 21 | ("v7", Some(sym::arm_target_feature)), 22 | ("v8", Some(sym::arm_target_feature)), 23 | ("vfp2", Some(sym::arm_target_feature)), 24 | ("vfp3", Some(sym::arm_target_feature)), 25 | ("vfp4", Some(sym::arm_target_feature)), 26 | ]; 27 | 28 | const AARCH64_WHITELIST: &[(&str, Option)] = &[ 29 | ("fp", Some(sym::aarch64_target_feature)), 30 | ("neon", Some(sym::aarch64_target_feature)), 31 | ("sve", Some(sym::aarch64_target_feature)), 32 | ("crc", Some(sym::aarch64_target_feature)), 33 | ("crypto", Some(sym::aarch64_target_feature)), 34 | ("ras", Some(sym::aarch64_target_feature)), 35 | ("lse", Some(sym::aarch64_target_feature)), 36 | ("rdm", Some(sym::aarch64_target_feature)), 37 | ("fp16", Some(sym::aarch64_target_feature)), 38 | ("rcpc", Some(sym::aarch64_target_feature)), 39 | ("dotprod", Some(sym::aarch64_target_feature)), 40 | ("v8.1a", Some(sym::aarch64_target_feature)), 41 | ("v8.2a", Some(sym::aarch64_target_feature)), 42 | ("v8.3a", Some(sym::aarch64_target_feature)), 43 | ]; 44 | 45 | const X86_WHITELIST: &[(&str, Option)] = &[ 46 | ("adx", Some(sym::adx_target_feature)), 47 | ("aes", None), 48 | ("avx", None), 49 | ("avx2", None), 50 | ("avx512bw", Some(sym::avx512_target_feature)), 51 | ("avx512cd", Some(sym::avx512_target_feature)), 52 | ("avx512dq", Some(sym::avx512_target_feature)), 53 | ("avx512er", Some(sym::avx512_target_feature)), 54 | ("avx512f", Some(sym::avx512_target_feature)), 55 | ("avx512ifma", Some(sym::avx512_target_feature)), 56 | ("avx512pf", Some(sym::avx512_target_feature)), 57 | ("avx512vbmi", Some(sym::avx512_target_feature)), 58 | ("avx512vl", Some(sym::avx512_target_feature)), 59 | ("avx512vpopcntdq", Some(sym::avx512_target_feature)), 60 | ("bmi1", None), 61 | ("bmi2", None), 62 | ("cmpxchg16b", Some(sym::cmpxchg16b_target_feature)), 63 | ("f16c", Some(sym::f16c_target_feature)), 64 | ("fma", None), 65 | ("fxsr", None), 66 | ("lzcnt", None), 67 | ("mmx", Some(sym::mmx_target_feature)), 68 | ("movbe", Some(sym::movbe_target_feature)), 69 | ("pclmulqdq", None), 70 | ("popcnt", None), 71 | ("rdrand", None), 72 | ("rdseed", None), 73 | ("rtm", Some(sym::rtm_target_feature)), 74 | ("sha", None), 75 | ("sse", None), 76 | ("sse2", None), 77 | ("sse3", None), 78 | ("sse4.1", None), 79 | ("sse4.2", None), 80 | ("sse4a", Some(sym::sse4a_target_feature)), 81 | ("ssse3", None), 82 | ("tbm", Some(sym::tbm_target_feature)), 83 | ("xsave", None), 84 | ("xsavec", None), 85 | ("xsaveopt", None), 86 | ("xsaves", None), 87 | ]; 88 | 89 | const HEXAGON_WHITELIST: &[(&str, Option)] = &[ 90 | ("hvx", Some(sym::hexagon_target_feature)), 91 | ("hvx-double", Some(sym::hexagon_target_feature)), 92 | ]; 93 | 94 | const POWERPC_WHITELIST: &[(&str, Option)] = &[ 95 | ("altivec", Some(sym::powerpc_target_feature)), 96 | ("power8-altivec", Some(sym::powerpc_target_feature)), 97 | ("power9-altivec", Some(sym::powerpc_target_feature)), 98 | ("power8-vector", Some(sym::powerpc_target_feature)), 99 | ("power9-vector", Some(sym::powerpc_target_feature)), 100 | ("vsx", Some(sym::powerpc_target_feature)), 101 | ]; 102 | 103 | const MIPS_WHITELIST: &[(&str, Option)] = &[ 104 | ("fp64", Some(sym::mips_target_feature)), 105 | ("msa", Some(sym::mips_target_feature)), 106 | ]; 107 | 108 | const WASM_WHITELIST: &[(&str, Option)] = &[ 109 | ("simd128", Some(sym::wasm_target_feature)), 110 | ("atomics", Some(sym::wasm_target_feature)), 111 | ]; 112 | 113 | /// When rustdoc is running, provide a list of all known features so that all their respective 114 | /// primitives may be documented. 115 | /// 116 | /// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this 117 | /// iterator! 118 | pub fn all_known_features() -> impl Iterator)> { 119 | ARM_WHITELIST 120 | .iter() 121 | .cloned() 122 | .chain(AARCH64_WHITELIST.iter().cloned()) 123 | .chain(X86_WHITELIST.iter().cloned()) 124 | .chain(HEXAGON_WHITELIST.iter().cloned()) 125 | .chain(POWERPC_WHITELIST.iter().cloned()) 126 | .chain(MIPS_WHITELIST.iter().cloned()) 127 | .chain(WASM_WHITELIST.iter().cloned()) 128 | } 129 | 130 | pub fn target_feature_whitelist(sess: &Session) -> &'static [(&'static str, Option)] { 131 | match &*sess.target.target.arch { 132 | "arm" => ARM_WHITELIST, 133 | "aarch64" => AARCH64_WHITELIST, 134 | "x86" | "x86_64" => X86_WHITELIST, 135 | "hexagon" => HEXAGON_WHITELIST, 136 | "mips" | "mips64" => MIPS_WHITELIST, 137 | "powerpc" | "powerpc64" => POWERPC_WHITELIST, 138 | // wasm32 on emscripten does not support these target features 139 | "wasm32" if !sess.target.target.options.is_like_emscripten => WASM_WHITELIST, 140 | _ => &[], 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/cast.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | pub fn clif_intcast( 4 | fx: &mut FunctionCx<'_, '_, impl Backend>, 5 | val: Value, 6 | to: Type, 7 | signed: bool, 8 | ) -> Value { 9 | let from = fx.bcx.func.dfg.value_type(val); 10 | match (from, to) { 11 | // equal 12 | (_, _) if from == to => val, 13 | 14 | // extend 15 | (_, types::I128) => { 16 | let wider = if from == types::I64 { 17 | val 18 | } else if signed { 19 | fx.bcx.ins().sextend(types::I64, val) 20 | } else { 21 | fx.bcx.ins().uextend(types::I64, val) 22 | }; 23 | let zero = fx.bcx.ins().iconst(types::I64, 0); 24 | fx.bcx.ins().iconcat(wider, zero) 25 | } 26 | (_, _) if to.wider_or_equal(from) => { 27 | if signed { 28 | fx.bcx.ins().sextend(to, val) 29 | } else { 30 | fx.bcx.ins().uextend(to, val) 31 | } 32 | } 33 | 34 | // reduce 35 | (types::I128, _) => { 36 | let (lsb, _msb) = fx.bcx.ins().isplit(val); 37 | if to == types::I64 { 38 | lsb 39 | } else { 40 | fx.bcx.ins().ireduce(to, lsb) 41 | } 42 | } 43 | (_, _) => fx.bcx.ins().ireduce(to, val), 44 | } 45 | } 46 | 47 | pub fn clif_int_or_float_cast( 48 | fx: &mut FunctionCx<'_, '_, impl Backend>, 49 | from: Value, 50 | from_signed: bool, 51 | to_ty: Type, 52 | to_signed: bool, 53 | ) -> Value { 54 | let from_ty = fx.bcx.func.dfg.value_type(from); 55 | 56 | if from_ty.is_int() && to_ty.is_int() { 57 | // int-like -> int-like 58 | clif_intcast( 59 | fx, 60 | from, 61 | to_ty, 62 | from_signed, // FIXME is this correct? 63 | ) 64 | } else if from_ty.is_int() && to_ty.is_float() { 65 | if from_ty == types::I128 { 66 | // _______ss__f_ 67 | // __float tisf: i128 -> f32 68 | // __float tidf: i128 -> f64 69 | // __floatuntisf: u128 -> f32 70 | // __floatuntidf: u128 -> f64 71 | 72 | let name = format!( 73 | "__float{sign}ti{flt}f", 74 | sign = if from_signed { "" } else { "un" }, 75 | flt = match to_ty { 76 | types::F32 => "s", 77 | types::F64 => "d", 78 | _ => unreachable!("{:?}", to_ty), 79 | }, 80 | ); 81 | 82 | let from_rust_ty = if from_signed { 83 | fx.tcx.types.i128 84 | } else { 85 | fx.tcx.types.u128 86 | }; 87 | 88 | let to_rust_ty = match to_ty { 89 | types::F32 => fx.tcx.types.f32, 90 | types::F64 => fx.tcx.types.f64, 91 | _ => unreachable!(), 92 | }; 93 | 94 | return fx 95 | .easy_call( 96 | &name, 97 | &[CValue::by_val(from, fx.layout_of(from_rust_ty))], 98 | to_rust_ty, 99 | ) 100 | .load_scalar(fx); 101 | } 102 | 103 | // int-like -> float 104 | if from_signed { 105 | fx.bcx.ins().fcvt_from_sint(to_ty, from) 106 | } else { 107 | fx.bcx.ins().fcvt_from_uint(to_ty, from) 108 | } 109 | } else if from_ty.is_float() && to_ty.is_int() { 110 | if to_ty == types::I128 { 111 | // _____sssf___ 112 | // __fix sfti: f32 -> i128 113 | // __fix dfti: f64 -> i128 114 | // __fixunssfti: f32 -> u128 115 | // __fixunsdfti: f64 -> u128 116 | 117 | let name = format!( 118 | "__fix{sign}{flt}fti", 119 | sign = if to_signed { "" } else { "uns" }, 120 | flt = match from_ty { 121 | types::F32 => "s", 122 | types::F64 => "d", 123 | _ => unreachable!("{:?}", to_ty), 124 | }, 125 | ); 126 | 127 | let from_rust_ty = match from_ty { 128 | types::F32 => fx.tcx.types.f32, 129 | types::F64 => fx.tcx.types.f64, 130 | _ => unreachable!(), 131 | }; 132 | 133 | let to_rust_ty = if to_signed { 134 | fx.tcx.types.i128 135 | } else { 136 | fx.tcx.types.u128 137 | }; 138 | 139 | return fx 140 | .easy_call( 141 | &name, 142 | &[CValue::by_val(from, fx.layout_of(from_rust_ty))], 143 | to_rust_ty, 144 | ) 145 | .load_scalar(fx); 146 | } 147 | 148 | // float -> int-like 149 | if to_ty == types::I8 || to_ty == types::I16 { 150 | // FIXME implement fcvt_to_*int_sat.i8/i16 151 | let val = if to_signed { 152 | fx.bcx.ins().fcvt_to_sint_sat(types::I32, from) 153 | } else { 154 | fx.bcx.ins().fcvt_to_uint_sat(types::I32, from) 155 | }; 156 | let (min, max) = type_min_max_value(to_ty, to_signed); 157 | let min_val = fx.bcx.ins().iconst(types::I32, min); 158 | let max_val = fx.bcx.ins().iconst(types::I32, max); 159 | 160 | let val = if to_signed { 161 | let has_underflow = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, val, min); 162 | let has_overflow = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThan, val, max); 163 | let bottom_capped = fx.bcx.ins().select(has_underflow, min_val, val); 164 | fx.bcx.ins().select(has_overflow, max_val, bottom_capped) 165 | } else { 166 | let has_overflow = fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, val, max); 167 | fx.bcx.ins().select(has_overflow, max_val, val) 168 | }; 169 | fx.bcx.ins().ireduce(to_ty, val) 170 | } else { 171 | if to_signed { 172 | fx.bcx.ins().fcvt_to_sint_sat(to_ty, from) 173 | } else { 174 | fx.bcx.ins().fcvt_to_uint_sat(to_ty, from) 175 | } 176 | } 177 | } else if from_ty.is_float() && to_ty.is_float() { 178 | // float -> float 179 | match (from_ty, to_ty) { 180 | (types::F32, types::F64) => fx.bcx.ins().fpromote(types::F64, from), 181 | (types::F64, types::F32) => fx.bcx.ins().fdemote(types::F32, from), 182 | _ => from, 183 | } 184 | } else { 185 | unreachable!("cast value from {:?} to {:?}", from_ty, to_ty); 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/discriminant.rs: -------------------------------------------------------------------------------- 1 | //! Adapted from https://github.com/rust-lang/rust/blob/d760df5aea483aae041c9a241e7acacf48f75035/src/librustc_codegen_ssa/mir/place.rs 2 | 3 | use crate::prelude::*; 4 | 5 | pub fn codegen_set_discriminant<'tcx>( 6 | fx: &mut FunctionCx<'_, 'tcx, impl Backend>, 7 | place: CPlace<'tcx>, 8 | variant_index: VariantIdx, 9 | ) { 10 | let layout = place.layout(); 11 | if layout.for_variant(fx, variant_index).abi.is_uninhabited() { 12 | return; 13 | } 14 | match layout.variants { 15 | layout::Variants::Single { index } => { 16 | assert_eq!(index, variant_index); 17 | } 18 | layout::Variants::Multiple { 19 | discr: _, 20 | discr_index, 21 | discr_kind: layout::DiscriminantKind::Tag, 22 | variants: _, 23 | } => { 24 | let ptr = place.place_field(fx, mir::Field::new(discr_index)); 25 | let to = layout 26 | .ty 27 | .discriminant_for_variant(fx.tcx, variant_index) 28 | .unwrap() 29 | .val; 30 | let discr = CValue::const_val(fx, ptr.layout().ty, to); 31 | ptr.write_cvalue(fx, discr); 32 | } 33 | layout::Variants::Multiple { 34 | discr: _, 35 | discr_index, 36 | discr_kind: 37 | layout::DiscriminantKind::Niche { 38 | dataful_variant, 39 | ref niche_variants, 40 | niche_start, 41 | }, 42 | variants: _, 43 | } => { 44 | if variant_index != dataful_variant { 45 | let niche = place.place_field(fx, mir::Field::new(discr_index)); 46 | let niche_value = variant_index.as_u32() - niche_variants.start().as_u32(); 47 | let niche_value = u128::from(niche_value).wrapping_add(niche_start); 48 | let niche_llval = CValue::const_val(fx, niche.layout().ty, niche_value); 49 | niche.write_cvalue(fx, niche_llval); 50 | } 51 | } 52 | } 53 | } 54 | 55 | pub fn codegen_get_discriminant<'tcx>( 56 | fx: &mut FunctionCx<'_, 'tcx, impl Backend>, 57 | value: CValue<'tcx>, 58 | dest_layout: TyLayout<'tcx>, 59 | ) -> CValue<'tcx> { 60 | let layout = value.layout(); 61 | 62 | if layout.abi == layout::Abi::Uninhabited { 63 | return trap_unreachable_ret_value( 64 | fx, 65 | dest_layout, 66 | "[panic] Tried to get discriminant for uninhabited type.", 67 | ); 68 | } 69 | 70 | let (discr_scalar, discr_index, discr_kind) = match &layout.variants { 71 | layout::Variants::Single { index } => { 72 | let discr_val = layout 73 | .ty 74 | .discriminant_for_variant(fx.tcx, *index) 75 | .map_or(u128::from(index.as_u32()), |discr| discr.val); 76 | return CValue::const_val(fx, dest_layout.ty, discr_val); 77 | } 78 | layout::Variants::Multiple { 79 | discr, 80 | discr_index, 81 | discr_kind, 82 | variants: _, 83 | } => (discr, *discr_index, discr_kind), 84 | }; 85 | 86 | let cast_to = fx.clif_type(dest_layout.ty).unwrap(); 87 | 88 | // Read the tag/niche-encoded discriminant from memory. 89 | let encoded_discr = value.value_field(fx, mir::Field::new(discr_index)); 90 | let encoded_discr = encoded_discr.load_scalar(fx); 91 | 92 | // Decode the discriminant (specifically if it's niche-encoded). 93 | match *discr_kind { 94 | layout::DiscriminantKind::Tag => { 95 | let signed = match discr_scalar.value { 96 | layout::Int(_, signed) => signed, 97 | _ => false, 98 | }; 99 | let val = clif_intcast(fx, encoded_discr, cast_to, signed); 100 | return CValue::by_val(val, dest_layout); 101 | } 102 | layout::DiscriminantKind::Niche { 103 | dataful_variant, 104 | ref niche_variants, 105 | niche_start, 106 | } => { 107 | // Rebase from niche values to discriminants, and check 108 | // whether the result is in range for the niche variants. 109 | 110 | // We first compute the "relative discriminant" (wrt `niche_variants`), 111 | // that is, if `n = niche_variants.end() - niche_variants.start()`, 112 | // we remap `niche_start..=niche_start + n` (which may wrap around) 113 | // to (non-wrap-around) `0..=n`, to be able to check whether the 114 | // discriminant corresponds to a niche variant with one comparison. 115 | // We also can't go directly to the (variant index) discriminant 116 | // and check that it is in the range `niche_variants`, because 117 | // that might not fit in the same type, on top of needing an extra 118 | // comparison (see also the comment on `let niche_discr`). 119 | let relative_discr = if niche_start == 0 { 120 | encoded_discr 121 | } else { 122 | // FIXME handle niche_start > i64::max_value() 123 | fx.bcx 124 | .ins() 125 | .iadd_imm(encoded_discr, -i64::try_from(niche_start).unwrap()) 126 | }; 127 | let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32(); 128 | let is_niche = { 129 | codegen_icmp_imm( 130 | fx, 131 | IntCC::UnsignedLessThanOrEqual, 132 | relative_discr, 133 | i128::from(relative_max), 134 | ) 135 | }; 136 | 137 | // NOTE(eddyb) this addition needs to be performed on the final 138 | // type, in case the niche itself can't represent all variant 139 | // indices (e.g. `u8` niche with more than `256` variants, 140 | // but enough uninhabited variants so that the remaining variants 141 | // fit in the niche). 142 | // In other words, `niche_variants.end - niche_variants.start` 143 | // is representable in the niche, but `niche_variants.end` 144 | // might not be, in extreme cases. 145 | let niche_discr = { 146 | let relative_discr = if relative_max == 0 { 147 | // HACK(eddyb) since we have only one niche, we know which 148 | // one it is, and we can avoid having a dynamic value here. 149 | fx.bcx.ins().iconst(cast_to, 0) 150 | } else { 151 | clif_intcast(fx, relative_discr, cast_to, false) 152 | }; 153 | fx.bcx 154 | .ins() 155 | .iadd_imm(relative_discr, i64::from(niche_variants.start().as_u32())) 156 | }; 157 | 158 | let dataful_variant = fx 159 | .bcx 160 | .ins() 161 | .iconst(cast_to, i64::from(dataful_variant.as_u32())); 162 | let discr = fx.bcx.ins().select(is_niche, niche_discr, dataful_variant); 163 | CValue::by_val(discr, dest_layout) 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/codegen_i128.rs: -------------------------------------------------------------------------------- 1 | //! Replaces 128-bit operators with lang item calls 2 | 3 | use crate::prelude::*; 4 | 5 | pub fn maybe_codegen<'tcx>( 6 | fx: &mut FunctionCx<'_, 'tcx, impl Backend>, 7 | bin_op: BinOp, 8 | checked: bool, 9 | lhs: CValue<'tcx>, 10 | rhs: CValue<'tcx>, 11 | ) -> Option> { 12 | if lhs.layout().ty != fx.tcx.types.u128 && lhs.layout().ty != fx.tcx.types.i128 { 13 | return None; 14 | } 15 | 16 | let lhs_val = lhs.load_scalar(fx); 17 | let rhs_val = rhs.load_scalar(fx); 18 | 19 | let is_signed = type_sign(lhs.layout().ty); 20 | 21 | match bin_op { 22 | BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => { 23 | assert!(!checked); 24 | return None; 25 | } 26 | BinOp::Add | BinOp::Sub if !checked => return None, 27 | BinOp::Add => { 28 | let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter()); 29 | return Some(if is_signed { 30 | fx.easy_call("__rust_i128_addo", &[lhs, rhs], out_ty) 31 | } else { 32 | fx.easy_call("__rust_u128_addo", &[lhs, rhs], out_ty) 33 | }); 34 | } 35 | BinOp::Sub => { 36 | let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter()); 37 | return Some(if is_signed { 38 | fx.easy_call("__rust_i128_subo", &[lhs, rhs], out_ty) 39 | } else { 40 | fx.easy_call("__rust_u128_subo", &[lhs, rhs], out_ty) 41 | }); 42 | } 43 | BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"), 44 | BinOp::Mul => { 45 | let res = if checked { 46 | let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter()); 47 | if is_signed { 48 | fx.easy_call("__rust_i128_mulo", &[lhs, rhs], out_ty) 49 | } else { 50 | fx.easy_call("__rust_u128_mulo", &[lhs, rhs], out_ty) 51 | } 52 | } else { 53 | let val_ty = if is_signed { 54 | fx.tcx.types.i128 55 | } else { 56 | fx.tcx.types.u128 57 | }; 58 | fx.easy_call("__multi3", &[lhs, rhs], val_ty) 59 | }; 60 | return Some(res); 61 | } 62 | BinOp::Div => { 63 | assert!(!checked); 64 | if is_signed { 65 | Some(fx.easy_call("__divti3", &[lhs, rhs], fx.tcx.types.i128)) 66 | } else { 67 | Some(fx.easy_call("__udivti3", &[lhs, rhs], fx.tcx.types.u128)) 68 | } 69 | } 70 | BinOp::Rem => { 71 | assert!(!checked); 72 | if is_signed { 73 | Some(fx.easy_call("__modti3", &[lhs, rhs], fx.tcx.types.i128)) 74 | } else { 75 | Some(fx.easy_call("__umodti3", &[lhs, rhs], fx.tcx.types.u128)) 76 | } 77 | } 78 | BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => { 79 | assert!(!checked); 80 | return None; 81 | } 82 | BinOp::Shl | BinOp::Shr => { 83 | let is_overflow = if checked { 84 | // rhs >= 128 85 | 86 | // FIXME support non 128bit rhs 87 | /*let (rhs_lsb, rhs_msb) = fx.bcx.ins().isplit(rhs_val); 88 | let rhs_msb_gt_0 = fx.bcx.ins().icmp_imm(IntCC::NotEqual, rhs_msb, 0); 89 | let rhs_lsb_ge_128 = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThan, rhs_lsb, 127); 90 | let is_overflow = fx.bcx.ins().bor(rhs_msb_gt_0, rhs_lsb_ge_128);*/ 91 | let is_overflow = fx.bcx.ins().bconst(types::B1, false); 92 | 93 | Some(fx.bcx.ins().bint(types::I8, is_overflow)) 94 | } else { 95 | None 96 | }; 97 | 98 | // Optimize `val >> 64`, because compiler_builtins uses it to deconstruct an 128bit 99 | // integer into its lsb and msb. 100 | // https://github.com/rust-lang-nursery/compiler-builtins/blob/79a6a1603d5672cbb9187ff41ff4d9b5048ac1cb/src/int/mod.rs#L217 101 | if resolve_value_imm(fx.bcx.func, rhs_val) == Some(64) { 102 | let (lhs_lsb, lhs_msb) = fx.bcx.ins().isplit(lhs_val); 103 | let all_zeros = fx.bcx.ins().iconst(types::I64, 0); 104 | let val = match (bin_op, is_signed) { 105 | (BinOp::Shr, false) => { 106 | let val = fx.bcx.ins().iconcat(lhs_msb, all_zeros); 107 | Some(CValue::by_val(val, fx.layout_of(fx.tcx.types.u128))) 108 | } 109 | (BinOp::Shr, true) => { 110 | let sign = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, lhs_msb, 0); 111 | let all_ones = fx.bcx.ins().iconst(types::I64, u64::max_value() as i64); 112 | let all_sign_bits = fx.bcx.ins().select(sign, all_zeros, all_ones); 113 | 114 | let val = fx.bcx.ins().iconcat(lhs_msb, all_sign_bits); 115 | Some(CValue::by_val(val, fx.layout_of(fx.tcx.types.i128))) 116 | } 117 | (BinOp::Shl, _) => { 118 | let val_ty = if is_signed { 119 | fx.tcx.types.i128 120 | } else { 121 | fx.tcx.types.u128 122 | }; 123 | let val = fx.bcx.ins().iconcat(all_zeros, lhs_lsb); 124 | Some(CValue::by_val(val, fx.layout_of(val_ty))) 125 | } 126 | _ => None, 127 | }; 128 | if let Some(val) = val { 129 | if let Some(is_overflow) = is_overflow { 130 | let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter()); 131 | let val = val.load_scalar(fx); 132 | return Some(CValue::by_val_pair(val, is_overflow, fx.layout_of(out_ty))); 133 | } else { 134 | return Some(val); 135 | } 136 | } 137 | } 138 | 139 | let truncated_rhs = clif_intcast(fx, rhs_val, types::I32, false); 140 | let truncated_rhs = CValue::by_val(truncated_rhs, fx.layout_of(fx.tcx.types.u32)); 141 | let val = match (bin_op, is_signed) { 142 | (BinOp::Shl, false) => { 143 | fx.easy_call("__ashlti3", &[lhs, truncated_rhs], fx.tcx.types.u128) 144 | } 145 | (BinOp::Shl, true) => { 146 | fx.easy_call("__ashlti3", &[lhs, truncated_rhs], fx.tcx.types.i128) 147 | } 148 | (BinOp::Shr, false) => { 149 | fx.easy_call("__lshrti3", &[lhs, truncated_rhs], fx.tcx.types.u128) 150 | } 151 | (BinOp::Shr, true) => { 152 | fx.easy_call("__ashrti3", &[lhs, truncated_rhs], fx.tcx.types.i128) 153 | } 154 | (_, _) => unreachable!(), 155 | }; 156 | if let Some(is_overflow) = is_overflow { 157 | let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter()); 158 | let val = val.load_scalar(fx); 159 | Some(CValue::by_val_pair(val, is_overflow, fx.layout_of(out_ty))) 160 | } else { 161 | Some(val) 162 | } 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /example/std_example.rs: -------------------------------------------------------------------------------- 1 | #![feature(core_intrinsics)] 2 | 3 | use std::arch::x86_64::*; 4 | use std::io::Write; 5 | 6 | fn main() { 7 | let mutex = std::sync::Mutex::new(()); 8 | let _guard = mutex.lock().unwrap(); 9 | 10 | let _ = ::std::iter::repeat('a' as u8).take(10).collect::>(); 11 | let stderr = ::std::io::stderr(); 12 | let mut stderr = stderr.lock(); 13 | 14 | writeln!(stderr, "some {} text", "").unwrap(); 15 | 16 | let _ = std::process::Command::new("true").env("c", "d").spawn(); 17 | 18 | println!("cargo:rustc-link-lib=z"); 19 | 20 | static ONCE: std::sync::Once = std::sync::Once::new(); 21 | ONCE.call_once(|| {}); 22 | 23 | let _eq = LoopState::Continue(()) == LoopState::Break(()); 24 | 25 | // Make sure ByValPair values with differently sized components are correctly passed 26 | map(None::<(u8, Box)>); 27 | 28 | println!("{}", 2.3f32.exp()); 29 | println!("{}", 2.3f32.exp2()); 30 | println!("{}", 2.3f32.abs()); 31 | println!("{}", 2.3f32.sqrt()); 32 | println!("{}", 2.3f32.floor()); 33 | println!("{}", 2.3f32.ceil()); 34 | println!("{}", 2.3f32.min(1.0)); 35 | println!("{}", 2.3f32.max(1.0)); 36 | println!("{}", 2.3f32.powi(2)); 37 | println!("{}", 2.3f32.log2()); 38 | assert_eq!(2.3f32.copysign(-1.0), -2.3f32); 39 | println!("{}", 2.3f32.powf(2.0)); 40 | 41 | assert_eq!(-128i8, (-128i8).saturating_sub(1)); 42 | assert_eq!(127i8, 127i8.saturating_sub(-128)); 43 | assert_eq!(-128i8, (-128i8).saturating_add(-128)); 44 | assert_eq!(127i8, 127i8.saturating_add(1)); 45 | 46 | assert_eq!(0b0000000000000000000000000010000010000000000000000000000000000000_0000000000100000000000000000000000001000000000000100000000000000u128.leading_zeros(), 26); 47 | assert_eq!(0b0000000000000000000000000010000000000000000000000000000000000000_0000000000000000000000000000000000001000000000000000000010000000u128.trailing_zeros(), 7); 48 | 49 | let _d = 0i128.checked_div(2i128); 50 | let _d = 0u128.checked_div(2u128); 51 | assert_eq!(1u128 + 2, 3); 52 | 53 | assert_eq!(0b100010000000000000000000000000000u128 >> 10, 0b10001000000000000000000u128); 54 | assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 >> 64, 0xFEDCBA98765432u128); 55 | assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 as i128 >> 64, 0xFEDCBA98765432i128); 56 | assert_eq!(353985398u128 * 932490u128, 330087843781020u128); 57 | 58 | // Check that all u/i128 <-> float casts work correctly. 59 | let houndred_u128 = 100u128; 60 | let houndred_i128 = 100i128; 61 | let houndred_f32 = 100.0f32; 62 | let houndred_f64 = 100.0f64; 63 | assert_eq!(houndred_u128 as f32, 100.0); 64 | assert_eq!(houndred_u128 as f64, 100.0); 65 | assert_eq!(houndred_f32 as u128, 100); 66 | assert_eq!(houndred_f64 as u128, 100); 67 | assert_eq!(houndred_i128 as f32, 100.0); 68 | assert_eq!(houndred_i128 as f64, 100.0); 69 | assert_eq!(houndred_f32 as i128, 100); 70 | assert_eq!(houndred_f64 as i128, 100); 71 | 72 | let _a = 1u32 << 2u8; 73 | 74 | unsafe { 75 | test_simd(); 76 | } 77 | } 78 | 79 | #[target_feature(enable = "sse2")] 80 | unsafe fn test_simd() { 81 | let x = _mm_setzero_si128(); 82 | let y = _mm_set1_epi16(7); 83 | let or = _mm_or_si128(x, y); 84 | let cmp_eq = _mm_cmpeq_epi8(y, y); 85 | let cmp_lt = _mm_cmplt_epi8(y, y); 86 | 87 | assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]); 88 | assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_eq), [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]); 89 | assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]); 90 | 91 | test_mm_slli_si128(); 92 | test_mm_movemask_epi8(); 93 | test_mm256_movemask_epi8(); 94 | test_mm_add_epi8(); 95 | test_mm_add_pd(); 96 | test_mm_cvtepi8_epi16(); 97 | test_mm_cvtsi128_si64(); 98 | 99 | // FIXME(#666) implement `#[rustc_arg_required_const(..)]` support 100 | //test_mm_extract_epi8(); 101 | 102 | let mask1 = _mm_movemask_epi8(dbg!(_mm_setr_epi8(255u8 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))); 103 | assert_eq!(mask1, 1); 104 | } 105 | 106 | #[target_feature(enable = "sse2")] 107 | unsafe fn test_mm_slli_si128() { 108 | #[rustfmt::skip] 109 | let a = _mm_setr_epi8( 110 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 111 | ); 112 | let r = _mm_slli_si128(a, 1); 113 | let e = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); 114 | assert_eq_m128i(r, e); 115 | 116 | #[rustfmt::skip] 117 | let a = _mm_setr_epi8( 118 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 119 | ); 120 | let r = _mm_slli_si128(a, 15); 121 | let e = _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); 122 | assert_eq_m128i(r, e); 123 | 124 | #[rustfmt::skip] 125 | let a = _mm_setr_epi8( 126 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 127 | ); 128 | let r = _mm_slli_si128(a, 16); 129 | assert_eq_m128i(r, _mm_set1_epi8(0)); 130 | 131 | #[rustfmt::skip] 132 | let a = _mm_setr_epi8( 133 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 134 | ); 135 | let r = _mm_slli_si128(a, -1); 136 | assert_eq_m128i(_mm_set1_epi8(0), r); 137 | 138 | #[rustfmt::skip] 139 | let a = _mm_setr_epi8( 140 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 141 | ); 142 | let r = _mm_slli_si128(a, -0x80000000); 143 | assert_eq_m128i(r, _mm_set1_epi8(0)); 144 | } 145 | 146 | #[target_feature(enable = "sse2")] 147 | unsafe fn test_mm_movemask_epi8() { 148 | #[rustfmt::skip] 149 | let a = _mm_setr_epi8( 150 | 0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8, 0b01, 151 | 0b0101, 0b1111_0000u8 as i8, 0, 0, 152 | 0, 0, 0b1111_0000u8 as i8, 0b0101, 153 | 0b01, 0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8, 154 | ); 155 | let r = _mm_movemask_epi8(a); 156 | assert_eq!(r, 0b10100100_00100101); 157 | } 158 | 159 | #[target_feature(enable = "avx2")] 160 | unsafe fn test_mm256_movemask_epi8() { 161 | let a = _mm256_set1_epi8(-1); 162 | let r = _mm256_movemask_epi8(a); 163 | let e = -1; 164 | assert_eq!(r, e); 165 | } 166 | 167 | #[target_feature(enable = "sse2")] 168 | unsafe fn test_mm_add_epi8() { 169 | let a = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); 170 | #[rustfmt::skip] 171 | let b = _mm_setr_epi8( 172 | 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 173 | ); 174 | let r = _mm_add_epi8(a, b); 175 | #[rustfmt::skip] 176 | let e = _mm_setr_epi8( 177 | 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 178 | ); 179 | assert_eq_m128i(r, e); 180 | } 181 | 182 | #[target_feature(enable = "sse2")] 183 | unsafe fn test_mm_add_pd() { 184 | let a = _mm_setr_pd(1.0, 2.0); 185 | let b = _mm_setr_pd(5.0, 10.0); 186 | let r = _mm_add_pd(a, b); 187 | assert_eq_m128d(r, _mm_setr_pd(6.0, 12.0)); 188 | } 189 | 190 | fn assert_eq_m128i(x: std::arch::x86_64::__m128i, y: std::arch::x86_64::__m128i) { 191 | unsafe { 192 | assert_eq!(std::mem::transmute::<_, [u8; 16]>(x), std::mem::transmute::<_, [u8; 16]>(y)); 193 | } 194 | } 195 | 196 | #[target_feature(enable = "sse2")] 197 | pub unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) { 198 | if _mm_movemask_pd(_mm_cmpeq_pd(a, b)) != 0b11 { 199 | panic!("{:?} != {:?}", a, b); 200 | } 201 | } 202 | 203 | #[target_feature(enable = "sse2")] 204 | unsafe fn test_mm_cvtsi128_si64() { 205 | let r = _mm_cvtsi128_si64(std::mem::transmute::<[i64; 2], _>([5, 0])); 206 | assert_eq!(r, 5); 207 | } 208 | 209 | #[target_feature(enable = "sse4.1")] 210 | unsafe fn test_mm_cvtepi8_epi16() { 211 | let a = _mm_set1_epi8(10); 212 | let r = _mm_cvtepi8_epi16(a); 213 | let e = _mm_set1_epi16(10); 214 | assert_eq_m128i(r, e); 215 | let a = _mm_set1_epi8(-10); 216 | let r = _mm_cvtepi8_epi16(a); 217 | let e = _mm_set1_epi16(-10); 218 | assert_eq_m128i(r, e); 219 | } 220 | 221 | #[target_feature(enable = "sse4.1")] 222 | unsafe fn test_mm_extract_epi8() { 223 | #[rustfmt::skip] 224 | let a = _mm_setr_epi8( 225 | -1, 1, 2, 3, 4, 5, 6, 7, 226 | 8, 9, 10, 11, 12, 13, 14, 15 227 | ); 228 | let r1 = _mm_extract_epi8(a, 0); 229 | let r2 = _mm_extract_epi8(a, 19); 230 | assert_eq!(r1, 0xFF); 231 | assert_eq!(r2, 3); 232 | } 233 | 234 | #[derive(PartialEq)] 235 | enum LoopState { 236 | Continue(()), 237 | Break(()) 238 | } 239 | 240 | pub enum Instruction { 241 | Increment, 242 | Loop, 243 | } 244 | 245 | fn map(a: Option<(u8, Box)>) -> Option> { 246 | match a { 247 | None => None, 248 | Some((_, instr)) => Some(instr), 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /src/pretty_clif.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | use std::collections::HashMap; 3 | use std::fmt; 4 | 5 | use cranelift::codegen::{ 6 | entity::SecondaryMap, 7 | ir::{self, entities::AnyEntity, function::DisplayFunctionAnnotations}, 8 | write::{FuncWriter, PlainWriter}, 9 | ValueLabelsRanges, 10 | }; 11 | 12 | use crate::prelude::*; 13 | 14 | /// This module provides the [CommentWriter] which makes it possible 15 | /// to add comments to the written cranelift ir. 16 | /// 17 | /// # Example 18 | /// 19 | /// ```clif 20 | /// test compile 21 | /// target x86_64 22 | /// 23 | /// function u0:0(i64, i64, i64) system_v { 24 | /// ; symbol _ZN119_$LT$example..IsNotEmpty$u20$as$u20$mini_core..FnOnce$LT$$LP$$RF$$u27$a$u20$$RF$$u27$b$u20$$u5b$u16$u5d$$C$$RP$$GT$$GT$9call_once17he85059d5e6a760a0E 25 | /// ; instance Instance { def: Item(DefId(0/0:29 ~ example[8787]::{{impl}}[0]::call_once[0])), substs: [ReErased, ReErased] } 26 | /// ; sig ([IsNotEmpty, (&&[u16],)]; c_variadic: false)->(u8, u8) 27 | /// 28 | /// ; ssa {_2: NOT_SSA, _4: NOT_SSA, _0: NOT_SSA, _3: (empty), _1: NOT_SSA} 29 | /// ; msg loc.idx param pass mode ssa flags ty 30 | /// ; ret _0 = v0 ByRef NOT_SSA (u8, u8) 31 | /// ; arg _1 = v1 ByRef NOT_SSA IsNotEmpty 32 | /// ; arg _2.0 = v2 ByVal(types::I64) NOT_SSA &&[u16] 33 | /// 34 | /// ss0 = explicit_slot 0 ; _1: IsNotEmpty size=0 align=1,8 35 | /// ss1 = explicit_slot 8 ; _2: (&&[u16],) size=8 align=8,8 36 | /// ss2 = explicit_slot 8 ; _4: (&&[u16],) size=8 align=8,8 37 | /// sig0 = (i64, i64, i64) system_v 38 | /// sig1 = (i64, i64, i64) system_v 39 | /// fn0 = colocated u0:6 sig1 ; Instance { def: Item(DefId(0/0:31 ~ example[8787]::{{impl}}[1]::call_mut[0])), substs: [ReErased, ReErased] } 40 | /// 41 | /// ebb0(v0: i64, v1: i64, v2: i64): 42 | /// v3 = stack_addr.i64 ss0 43 | /// v4 = stack_addr.i64 ss1 44 | /// store v2, v4 45 | /// v5 = stack_addr.i64 ss2 46 | /// jump ebb1 47 | /// 48 | /// ebb1: 49 | /// nop 50 | /// ; _3 = &mut _1 51 | /// ; _4 = _2 52 | /// v6 = load.i64 v4 53 | /// store v6, v5 54 | /// ; 55 | /// ; _0 = const mini_core::FnMut::call_mut(move _3, move _4) 56 | /// v7 = load.i64 v5 57 | /// call fn0(v0, v3, v7) 58 | /// jump ebb2 59 | /// 60 | /// ebb2: 61 | /// nop 62 | /// ; 63 | /// ; return 64 | /// return 65 | /// } 66 | /// ``` 67 | 68 | #[derive(Debug)] 69 | pub struct CommentWriter { 70 | global_comments: Vec, 71 | entity_comments: HashMap, 72 | inst_comments: HashMap, 73 | } 74 | 75 | impl CommentWriter { 76 | pub fn new<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self { 77 | CommentWriter { 78 | global_comments: vec![ 79 | format!("symbol {}", tcx.symbol_name(instance).name.as_str()), 80 | format!("instance {:?}", instance), 81 | format!( 82 | "sig {:?}", 83 | tcx.normalize_erasing_late_bound_regions( 84 | ParamEnv::reveal_all(), 85 | &instance.fn_sig(tcx) 86 | ) 87 | ), 88 | String::new(), 89 | ], 90 | entity_comments: HashMap::new(), 91 | inst_comments: HashMap::new(), 92 | } 93 | } 94 | } 95 | 96 | impl FuncWriter for &'_ CommentWriter { 97 | fn write_preamble( 98 | &mut self, 99 | w: &mut dyn fmt::Write, 100 | func: &Function, 101 | reg_info: Option<&isa::RegInfo>, 102 | ) -> Result { 103 | for comment in &self.global_comments { 104 | if !comment.is_empty() { 105 | writeln!(w, "; {}", comment)?; 106 | } else { 107 | writeln!(w, "")?; 108 | } 109 | } 110 | if !self.global_comments.is_empty() { 111 | writeln!(w, "")?; 112 | } 113 | 114 | self.super_preamble(w, func, reg_info) 115 | } 116 | 117 | fn write_entity_definition( 118 | &mut self, 119 | w: &mut dyn fmt::Write, 120 | _func: &Function, 121 | entity: AnyEntity, 122 | value: &dyn fmt::Display, 123 | ) -> fmt::Result { 124 | write!(w, " {} = {}", entity, value)?; 125 | 126 | if let Some(comment) = self.entity_comments.get(&entity) { 127 | writeln!(w, " ; {}", comment.replace('\n', "\n; ")) 128 | } else { 129 | writeln!(w, "") 130 | } 131 | } 132 | 133 | fn write_ebb_header( 134 | &mut self, 135 | w: &mut dyn fmt::Write, 136 | func: &Function, 137 | isa: Option<&dyn isa::TargetIsa>, 138 | ebb: Ebb, 139 | indent: usize, 140 | ) -> fmt::Result { 141 | PlainWriter.write_ebb_header(w, func, isa, ebb, indent) 142 | } 143 | 144 | fn write_instruction( 145 | &mut self, 146 | w: &mut dyn fmt::Write, 147 | func: &Function, 148 | aliases: &SecondaryMap>, 149 | isa: Option<&dyn isa::TargetIsa>, 150 | inst: Inst, 151 | indent: usize, 152 | ) -> fmt::Result { 153 | PlainWriter.write_instruction(w, func, aliases, isa, inst, indent)?; 154 | if let Some(comment) = self.inst_comments.get(&inst) { 155 | writeln!(w, "; {}", comment.replace('\n', "\n; "))?; 156 | } 157 | Ok(()) 158 | } 159 | } 160 | 161 | #[cfg(debug_assertions)] 162 | impl<'a, 'tcx, B: Backend + 'static> FunctionCx<'_, 'tcx, B> { 163 | pub fn add_global_comment>(&mut self, comment: S) { 164 | self.clif_comments.global_comments.push(comment.into()); 165 | } 166 | 167 | pub fn add_entity_comment<'s, S: Into>, E: Into>( 168 | &mut self, 169 | entity: E, 170 | comment: S, 171 | ) { 172 | use std::collections::hash_map::Entry; 173 | match self.clif_comments.entity_comments.entry(entity.into()) { 174 | Entry::Occupied(mut occ) => { 175 | occ.get_mut().push('\n'); 176 | occ.get_mut().push_str(comment.into().as_ref()); 177 | } 178 | Entry::Vacant(vac) => { 179 | vac.insert(comment.into().into_owned()); 180 | } 181 | } 182 | } 183 | 184 | pub fn add_comment<'s, S: Into>>(&mut self, inst: Inst, comment: S) { 185 | use std::collections::hash_map::Entry; 186 | match self.clif_comments.inst_comments.entry(inst) { 187 | Entry::Occupied(mut occ) => { 188 | occ.get_mut().push('\n'); 189 | occ.get_mut().push_str(comment.into().as_ref()); 190 | } 191 | Entry::Vacant(vac) => { 192 | vac.insert(comment.into().into_owned()); 193 | } 194 | } 195 | } 196 | } 197 | 198 | pub fn write_clif_file<'tcx>( 199 | tcx: TyCtxt<'tcx>, 200 | postfix: &str, 201 | instance: Instance<'tcx>, 202 | func: &ir::Function, 203 | mut clif_comments: &CommentWriter, 204 | value_ranges: Option<&ValueLabelsRanges>, 205 | ) { 206 | use std::io::Write; 207 | 208 | let symbol_name = tcx.symbol_name(instance).name.as_str(); 209 | let clif_file_name = format!( 210 | "{}/{}__{}.{}.clif", 211 | concat!(env!("CARGO_MANIFEST_DIR"), "/target/out/clif"), 212 | tcx.crate_name(LOCAL_CRATE), 213 | symbol_name, 214 | postfix, 215 | ); 216 | 217 | let mut clif = String::new(); 218 | cranelift::codegen::write::decorate_function( 219 | &mut clif_comments, 220 | &mut clif, 221 | &func, 222 | &DisplayFunctionAnnotations { 223 | isa: Some(&*crate::build_isa( 224 | tcx.sess, true, /* PIC doesn't matter here */ 225 | )), 226 | value_ranges, 227 | }, 228 | ) 229 | .unwrap(); 230 | 231 | match ::std::fs::File::create(clif_file_name) { 232 | Ok(mut file) => { 233 | let target_triple = crate::target_triple(tcx.sess); 234 | writeln!(file, "test compile").unwrap(); 235 | writeln!(file, "set is_pic").unwrap(); 236 | writeln!(file, "target {}", target_triple).unwrap(); 237 | writeln!(file, "").unwrap(); 238 | file.write(clif.as_bytes()).unwrap(); 239 | } 240 | Err(e) => { 241 | tcx.sess.warn(&format!("err opening clif file: {:?}", e)); 242 | } 243 | } 244 | } 245 | 246 | impl<'a, 'tcx, B: Backend + 'static> fmt::Debug for FunctionCx<'_, 'tcx, B> { 247 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 248 | writeln!(f, "{:?}", self.instance.substs)?; 249 | writeln!(f, "{:?}", self.local_map)?; 250 | 251 | let mut clif = String::new(); 252 | ::cranelift::codegen::write::decorate_function( 253 | &mut &self.clif_comments, 254 | &mut clif, 255 | &self.bcx.func, 256 | &DisplayFunctionAnnotations::default(), 257 | ) 258 | .unwrap(); 259 | writeln!(f, "\n{}", clif) 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /src/unsize.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | 3 | // Adapted from https://github.com/rust-lang/rust/blob/2a663555ddf36f6b041445894a8c175cd1bc718c/src/librustc_codegen_ssa/base.rs#L159-L307 4 | 5 | /// Retrieve the information we are losing (making dynamic) in an unsizing 6 | /// adjustment. 7 | /// 8 | /// The `old_info` argument is a bit funny. It is intended for use 9 | /// in an upcast, where the new vtable for an object will be derived 10 | /// from the old one. 11 | pub fn unsized_info<'tcx>( 12 | fx: &mut FunctionCx<'_, 'tcx, impl Backend>, 13 | source: Ty<'tcx>, 14 | target: Ty<'tcx>, 15 | old_info: Option, 16 | ) -> Value { 17 | let (source, target) = 18 | fx.tcx 19 | .struct_lockstep_tails_erasing_lifetimes(source, target, ParamEnv::reveal_all()); 20 | match (&source.kind, &target.kind) { 21 | (&ty::Array(_, len), &ty::Slice(_)) => fx.bcx.ins().iconst( 22 | fx.pointer_type, 23 | len.eval_usize(fx.tcx, ParamEnv::reveal_all()) as i64, 24 | ), 25 | (&ty::Dynamic(..), &ty::Dynamic(..)) => { 26 | // For now, upcasts are limited to changes in marker 27 | // traits, and hence never actually require an actual 28 | // change to the vtable. 29 | old_info.expect("unsized_info: missing old info for trait upcast") 30 | } 31 | (_, &ty::Dynamic(ref data, ..)) => crate::vtable::get_vtable(fx, source, data.principal()), 32 | _ => bug!( 33 | "unsized_info: invalid unsizing {:?} -> {:?}", 34 | source, 35 | target 36 | ), 37 | } 38 | } 39 | 40 | /// Coerce `src` to `dst_ty`. `src_ty` must be a thin pointer. 41 | pub fn unsize_thin_ptr<'tcx>( 42 | fx: &mut FunctionCx<'_, 'tcx, impl Backend>, 43 | src: Value, 44 | src_ty: Ty<'tcx>, 45 | dst_ty: Ty<'tcx>, 46 | ) -> (Value, Value) { 47 | match (&src_ty.kind, &dst_ty.kind) { 48 | (&ty::Ref(_, a, _), &ty::Ref(_, b, _)) 49 | | (&ty::Ref(_, a, _), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) 50 | | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => { 51 | assert!(!fx.layout_of(a).is_unsized()); 52 | (src, unsized_info(fx, a, b, None)) 53 | } 54 | (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => { 55 | let (a, b) = (src_ty.boxed_ty(), dst_ty.boxed_ty()); 56 | assert!(!fx.layout_of(a).is_unsized()); 57 | (src, unsized_info(fx, a, b, None)) 58 | } 59 | (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => { 60 | assert_eq!(def_a, def_b); 61 | 62 | let src_layout = fx.layout_of(src_ty); 63 | let dst_layout = fx.layout_of(dst_ty); 64 | let mut result = None; 65 | for i in 0..src_layout.fields.count() { 66 | let src_f = src_layout.field(fx, i); 67 | assert_eq!(src_layout.fields.offset(i).bytes(), 0); 68 | assert_eq!(dst_layout.fields.offset(i).bytes(), 0); 69 | if src_f.is_zst() { 70 | continue; 71 | } 72 | assert_eq!(src_layout.size, src_f.size); 73 | 74 | let dst_f = dst_layout.field(fx, i); 75 | assert_ne!(src_f.ty, dst_f.ty); 76 | assert_eq!(result, None); 77 | result = Some(unsize_thin_ptr(fx, src, src_f.ty, dst_f.ty)); 78 | } 79 | result.unwrap() 80 | } 81 | _ => bug!("unsize_thin_ptr: called on bad types"), 82 | } 83 | } 84 | 85 | /// Coerce `src`, which is a reference to a value of type `src_ty`, 86 | /// to a value of type `dst_ty` and store the result in `dst` 87 | pub fn coerce_unsized_into<'tcx>( 88 | fx: &mut FunctionCx<'_, 'tcx, impl Backend>, 89 | src: CValue<'tcx>, 90 | dst: CPlace<'tcx>, 91 | ) { 92 | let src_ty = src.layout().ty; 93 | let dst_ty = dst.layout().ty; 94 | let mut coerce_ptr = || { 95 | let (base, info) = if fx 96 | .layout_of(src.layout().ty.builtin_deref(true).unwrap().ty) 97 | .is_unsized() 98 | { 99 | // fat-ptr to fat-ptr unsize preserves the vtable 100 | // i.e., &'a fmt::Debug+Send => &'a fmt::Debug 101 | src.load_scalar_pair(fx) 102 | } else { 103 | let base = src.load_scalar(fx); 104 | unsize_thin_ptr(fx, base, src_ty, dst_ty) 105 | }; 106 | dst.write_cvalue(fx, CValue::by_val_pair(base, info, dst.layout())); 107 | }; 108 | match (&src_ty.kind, &dst_ty.kind) { 109 | (&ty::Ref(..), &ty::Ref(..)) 110 | | (&ty::Ref(..), &ty::RawPtr(..)) 111 | | (&ty::RawPtr(..), &ty::RawPtr(..)) => coerce_ptr(), 112 | (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => { 113 | assert_eq!(def_a, def_b); 114 | 115 | for i in 0..def_a.variants[VariantIdx::new(0)].fields.len() { 116 | let src_f = src.value_field(fx, mir::Field::new(i)); 117 | let dst_f = dst.place_field(fx, mir::Field::new(i)); 118 | 119 | if dst_f.layout().is_zst() { 120 | continue; 121 | } 122 | 123 | if src_f.layout().ty == dst_f.layout().ty { 124 | dst_f.write_cvalue(fx, src_f); 125 | } else { 126 | coerce_unsized_into(fx, src_f, dst_f); 127 | } 128 | } 129 | } 130 | _ => bug!( 131 | "coerce_unsized_into: invalid coercion {:?} -> {:?}", 132 | src_ty, 133 | dst_ty 134 | ), 135 | } 136 | } 137 | 138 | // Adapted from https://github.com/rust-lang/rust/blob/2a663555ddf36f6b041445894a8c175cd1bc718c/src/librustc_codegen_ssa/glue.rs 139 | 140 | pub fn size_and_align_of_dst<'tcx>( 141 | fx: &mut FunctionCx<'_, 'tcx, impl Backend>, 142 | ty: Ty<'tcx>, 143 | info: Value, 144 | ) -> (Value, Value) { 145 | let layout = fx.layout_of(ty); 146 | if !layout.is_unsized() { 147 | let size = fx 148 | .bcx 149 | .ins() 150 | .iconst(fx.pointer_type, layout.size.bytes() as i64); 151 | let align = fx 152 | .bcx 153 | .ins() 154 | .iconst(fx.pointer_type, layout.align.abi.bytes() as i64); 155 | return (size, align); 156 | } 157 | match ty.kind { 158 | ty::Dynamic(..) => { 159 | // load size/align from vtable 160 | ( 161 | crate::vtable::size_of_obj(fx, info), 162 | crate::vtable::min_align_of_obj(fx, info), 163 | ) 164 | } 165 | ty::Slice(_) | ty::Str => { 166 | let unit = layout.field(fx, 0); 167 | // The info in this case is the length of the str, so the size is that 168 | // times the unit size. 169 | ( 170 | fx.bcx.ins().imul_imm(info, unit.size.bytes() as i64), 171 | fx.bcx 172 | .ins() 173 | .iconst(fx.pointer_type, unit.align.abi.bytes() as i64), 174 | ) 175 | } 176 | _ => { 177 | // First get the size of all statically known fields. 178 | // Don't use size_of because it also rounds up to alignment, which we 179 | // want to avoid, as the unsized field's alignment could be smaller. 180 | assert!(!ty.is_simd()); 181 | 182 | let i = layout.fields.count() - 1; 183 | let sized_size = layout.fields.offset(i).bytes(); 184 | let sized_align = layout.align.abi.bytes(); 185 | let sized_align = fx.bcx.ins().iconst(fx.pointer_type, sized_align as i64); 186 | 187 | // Recurse to get the size of the dynamically sized field (must be 188 | // the last field). 189 | let field_ty = layout.field(fx, i).ty; 190 | let (unsized_size, mut unsized_align) = size_and_align_of_dst(fx, field_ty, info); 191 | 192 | // FIXME (#26403, #27023): We should be adding padding 193 | // to `sized_size` (to accommodate the `unsized_align` 194 | // required of the unsized field that follows) before 195 | // summing it with `sized_size`. (Note that since #26403 196 | // is unfixed, we do not yet add the necessary padding 197 | // here. But this is where the add would go.) 198 | 199 | // Return the sum of sizes and max of aligns. 200 | let size = fx.bcx.ins().iadd_imm(unsized_size, sized_size as i64); 201 | 202 | // Packed types ignore the alignment of their fields. 203 | if let ty::Adt(def, _) = ty.kind { 204 | if def.repr.packed() { 205 | unsized_align = sized_align; 206 | } 207 | } 208 | 209 | // Choose max of two known alignments (combined value must 210 | // be aligned according to more restrictive of the two). 211 | let cmp = fx 212 | .bcx 213 | .ins() 214 | .icmp(IntCC::UnsignedGreaterThan, sized_align, unsized_align); 215 | let align = fx.bcx.ins().select(cmp, sized_align, unsized_align); 216 | 217 | // Issue #27023: must add any necessary padding to `size` 218 | // (to make it a multiple of `align`) before returning it. 219 | // 220 | // Namely, the returned size should be, in C notation: 221 | // 222 | // `size + ((size & (align-1)) ? align : 0)` 223 | // 224 | // emulated via the semi-standard fast bit trick: 225 | // 226 | // `(size + (align-1)) & -align` 227 | let addend = fx.bcx.ins().iadd_imm(align, -1); 228 | let add = fx.bcx.ins().iadd(size, addend); 229 | let zero = fx.bcx.ins().iconst(fx.pointer_type, 0); 230 | let neg = fx.bcx.ins().isub(zero, align); 231 | let size = fx.bcx.ins().band(add, neg); 232 | 233 | (size, align) 234 | } 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(rustc_private, never_type, decl_macro)] 2 | #![allow(intra_doc_link_resolution_failure)] 3 | 4 | extern crate flate2; 5 | extern crate tempfile; 6 | extern crate rustc; 7 | extern crate rustc_codegen_ssa; 8 | extern crate rustc_codegen_utils; 9 | extern crate rustc_data_structures; 10 | extern crate rustc_driver; 11 | extern crate rustc_fs_util; 12 | extern crate rustc_incremental; 13 | extern crate rustc_index; 14 | extern crate rustc_mir; 15 | extern crate rustc_target; 16 | extern crate syntax; 17 | 18 | use std::any::Any; 19 | 20 | use rustc::dep_graph::DepGraph; 21 | use rustc::middle::cstore::{EncodedMetadata, MetadataLoader}; 22 | use rustc::session::config::OutputFilenames; 23 | use rustc::ty::query::Providers; 24 | use rustc::util::common::ErrorReported; 25 | use rustc_codegen_utils::codegen_backend::CodegenBackend; 26 | 27 | use cranelift::codegen::settings; 28 | 29 | use crate::constant::ConstantCx; 30 | use crate::prelude::*; 31 | 32 | mod abi; 33 | mod allocator; 34 | mod analyze; 35 | mod archive; 36 | mod base; 37 | mod cast; 38 | mod codegen_i128; 39 | mod common; 40 | mod constant; 41 | mod debuginfo; 42 | mod discriminant; 43 | mod driver; 44 | mod intrinsics; 45 | mod linkage; 46 | mod llvm_intrinsics; 47 | mod main_shim; 48 | mod metadata; 49 | mod num; 50 | mod pretty_clif; 51 | mod target_features_whitelist; 52 | mod trap; 53 | mod unimpl; 54 | mod unsize; 55 | mod value_and_place; 56 | mod vtable; 57 | 58 | mod prelude { 59 | pub use std::any::Any; 60 | pub use std::collections::{HashMap, HashSet}; 61 | pub use std::convert::{TryFrom, TryInto}; 62 | 63 | pub use syntax::ast::{FloatTy, IntTy, UintTy}; 64 | pub use syntax::source_map::{Pos, Span, DUMMY_SP}; 65 | 66 | pub use rustc::bug; 67 | pub use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; 68 | pub use rustc::mir::{self, interpret::AllocId, mono::MonoItem, *}; 69 | pub use rustc::session::{ 70 | config::{CrateType, Lto}, 71 | Session, 72 | }; 73 | pub use rustc::ty::layout::{self, Abi, LayoutOf, Scalar, Size, TyLayout, VariantIdx}; 74 | pub use rustc::ty::{ 75 | self, FnSig, Instance, InstanceDef, ParamEnv, PolyFnSig, Ty, TyCtxt, TypeAndMut, 76 | TypeFoldable, 77 | }; 78 | 79 | pub use rustc_data_structures::{ 80 | fx::{FxHashMap, FxHashSet}, 81 | sync::Lrc, 82 | }; 83 | 84 | pub use rustc_index::vec::Idx; 85 | 86 | pub use rustc_mir::monomorphize::collector; 87 | 88 | pub use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; 89 | pub use rustc_codegen_ssa::traits::*; 90 | pub use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleKind}; 91 | 92 | pub use cranelift::codegen::ir::{ 93 | condcodes::IntCC, function::Function, ExternalName, FuncRef, Inst, SourceLoc, StackSlot, 94 | }; 95 | pub use cranelift::codegen::isa::CallConv; 96 | pub use cranelift::codegen::Context; 97 | pub use cranelift::prelude::*; 98 | pub use cranelift_module::{ 99 | self, Backend, DataContext, DataId, FuncId, FuncOrDataId, Linkage, Module, 100 | }; 101 | 102 | pub use crate::abi::*; 103 | pub use crate::base::{trans_operand, trans_place}; 104 | pub use crate::cast::*; 105 | pub use crate::common::*; 106 | pub use crate::debuginfo::{DebugContext, FunctionDebugContext}; 107 | pub use crate::trap::*; 108 | pub use crate::unimpl::unimpl; 109 | pub use crate::value_and_place::{CPlace, CPlaceInner, CValue}; 110 | pub use crate::{Caches, CodegenCx}; 111 | 112 | pub struct PrintOnPanic String>(pub F); 113 | impl String> Drop for PrintOnPanic { 114 | fn drop(&mut self) { 115 | if ::std::thread::panicking() { 116 | println!("{}", (self.0)()); 117 | } 118 | } 119 | } 120 | } 121 | 122 | pub struct Caches<'tcx> { 123 | pub context: Context, 124 | pub vtables: HashMap<(Ty<'tcx>, Option>), DataId>, 125 | } 126 | 127 | impl Default for Caches<'_> { 128 | fn default() -> Self { 129 | Caches { 130 | context: Context::new(), 131 | vtables: HashMap::new(), 132 | } 133 | } 134 | } 135 | 136 | pub struct CodegenCx<'clif, 'tcx, B: Backend + 'static> { 137 | tcx: TyCtxt<'tcx>, 138 | module: &'clif mut Module, 139 | constants_cx: ConstantCx, 140 | caches: Caches<'tcx>, 141 | debug_context: Option<&'clif mut DebugContext<'tcx>>, 142 | } 143 | 144 | impl<'clif, 'tcx, B: Backend + 'static> CodegenCx<'clif, 'tcx, B> { 145 | fn new( 146 | tcx: TyCtxt<'tcx>, 147 | module: &'clif mut Module, 148 | debug_context: Option<&'clif mut DebugContext<'tcx>>, 149 | ) -> Self { 150 | CodegenCx { 151 | tcx, 152 | module, 153 | constants_cx: ConstantCx::default(), 154 | caches: Caches::default(), 155 | debug_context, 156 | } 157 | } 158 | 159 | fn finalize(self) { 160 | self.constants_cx.finalize(self.tcx, self.module); 161 | } 162 | } 163 | 164 | struct CraneliftCodegenBackend; 165 | 166 | impl CodegenBackend for CraneliftCodegenBackend { 167 | fn init(&self, _sess: &Session) {} 168 | 169 | fn metadata_loader(&self) -> Box { 170 | Box::new(crate::metadata::CraneliftMetadataLoader) 171 | } 172 | 173 | fn provide(&self, providers: &mut Providers) { 174 | rustc_codegen_utils::symbol_names::provide(providers); 175 | rustc_codegen_ssa::back::symbol_export::provide(providers); 176 | rustc_codegen_ssa::base::provide_both(providers); 177 | 178 | providers.target_features_whitelist = |tcx, cnum| { 179 | assert_eq!(cnum, LOCAL_CRATE); 180 | if tcx.sess.opts.actually_rustdoc { 181 | // rustdoc needs to be able to document functions that use all the features, so 182 | // whitelist them all 183 | tcx.arena.alloc( 184 | target_features_whitelist::all_known_features() 185 | .map(|(a, b)| (a.to_string(), b)) 186 | .collect(), 187 | ) 188 | } else { 189 | tcx.arena.alloc( 190 | target_features_whitelist::target_feature_whitelist(tcx.sess) 191 | .iter() 192 | .map(|&(a, b)| (a.to_string(), b)) 193 | .collect(), 194 | ) 195 | } 196 | }; 197 | } 198 | fn provide_extern(&self, providers: &mut Providers) { 199 | rustc_codegen_ssa::back::symbol_export::provide_extern(providers); 200 | rustc_codegen_ssa::base::provide_both(providers); 201 | } 202 | 203 | fn codegen_crate<'tcx>( 204 | &self, 205 | tcx: TyCtxt<'tcx>, 206 | metadata: EncodedMetadata, 207 | need_metadata_module: bool, 208 | ) -> Box { 209 | rustc_codegen_utils::check_for_rustc_errors_attr(tcx); 210 | 211 | let res = driver::codegen_crate(tcx, metadata, need_metadata_module); 212 | 213 | rustc_incremental::assert_module_sources::assert_module_sources(tcx); 214 | rustc_codegen_utils::symbol_names_test::report_symbol_names(tcx); 215 | 216 | res 217 | } 218 | 219 | fn join_codegen_and_link( 220 | &self, 221 | res: Box, 222 | sess: &Session, 223 | _dep_graph: &DepGraph, 224 | outputs: &OutputFilenames, 225 | ) -> Result<(), ErrorReported> { 226 | use rustc_codegen_ssa::back::link::link_binary; 227 | 228 | let codegen_results = *res 229 | .downcast::() 230 | .expect("Expected CraneliftCodegenBackend's CodegenResult, found Box"); 231 | 232 | let _timer = sess.prof.generic_activity("link_crate"); 233 | 234 | rustc::util::common::time(sess, "linking", || { 235 | let target_cpu = crate::target_triple(sess).to_string(); 236 | link_binary::>( 237 | sess, 238 | &codegen_results, 239 | outputs, 240 | &codegen_results.crate_name.as_str(), 241 | &target_cpu, 242 | ); 243 | }); 244 | 245 | Ok(()) 246 | } 247 | } 248 | 249 | fn target_triple(sess: &Session) -> target_lexicon::Triple { 250 | sess.target.target.llvm_target.parse().unwrap() 251 | } 252 | 253 | fn default_call_conv(sess: &Session) -> CallConv { 254 | CallConv::triple_default(&target_triple(sess)) 255 | } 256 | 257 | fn build_isa(sess: &Session, enable_pic: bool) -> Box { 258 | let mut flags_builder = settings::builder(); 259 | if enable_pic { 260 | flags_builder.enable("is_pic").unwrap(); 261 | } else { 262 | flags_builder.set("is_pic", "false").unwrap(); 263 | } 264 | flags_builder.set("probestack_enabled", "false").unwrap(); // __cranelift_probestack is not provided 265 | flags_builder 266 | .set( 267 | "enable_verifier", 268 | if cfg!(debug_assertions) { 269 | "true" 270 | } else { 271 | "false" 272 | }, 273 | ) 274 | .unwrap(); 275 | 276 | // FIXME(CraneStation/cranelift#732) fix LICM in presence of jump tables 277 | /* 278 | use rustc::session::config::OptLevel; 279 | match sess.opts.optimize { 280 | OptLevel::No => { 281 | flags_builder.set("opt_level", "fastest").unwrap(); 282 | } 283 | OptLevel::Less | OptLevel::Default => {} 284 | OptLevel::Aggressive => { 285 | flags_builder.set("opt_level", "best").unwrap(); 286 | } 287 | OptLevel::Size | OptLevel::SizeMin => { 288 | sess.warn("Optimizing for size is not supported. Just ignoring the request"); 289 | } 290 | }*/ 291 | 292 | let target_triple = crate::target_triple(sess); 293 | let flags = settings::Flags::new(flags_builder); 294 | cranelift::codegen::isa::lookup(target_triple) 295 | .unwrap() 296 | .finish(flags) 297 | } 298 | 299 | /// This is the entrypoint for a hot plugged rustc_codegen_cranelift 300 | #[no_mangle] 301 | pub fn __rustc_codegen_backend() -> Box { 302 | Box::new(CraneliftCodegenBackend) 303 | } 304 | -------------------------------------------------------------------------------- /src/archive.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::path::{Path, PathBuf}; 3 | 4 | use crate::prelude::*; 5 | 6 | use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder}; 7 | use rustc_codegen_ssa::{METADATA_FILENAME, RLIB_BYTECODE_EXTENSION}; 8 | 9 | struct ArchiveConfig<'a> { 10 | sess: &'a Session, 11 | dst: PathBuf, 12 | lib_search_paths: Vec, 13 | use_native_ar: bool, 14 | use_gnu_style_archive: bool, 15 | } 16 | 17 | #[derive(Debug)] 18 | enum ArchiveEntry { 19 | FromArchive { 20 | archive_index: usize, 21 | entry_index: usize, 22 | }, 23 | File(PathBuf), 24 | } 25 | 26 | pub struct ArArchiveBuilder<'a> { 27 | config: ArchiveConfig<'a>, 28 | src_archives: Vec<(PathBuf, ar::Archive)>, 29 | // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at 30 | // the end of an archive for linkers to not get confused. 31 | entries: Vec<(String, ArchiveEntry)>, 32 | update_symbols: bool, 33 | } 34 | 35 | impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { 36 | fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self { 37 | use rustc_codegen_ssa::back::link::archive_search_paths; 38 | let config = ArchiveConfig { 39 | sess, 40 | dst: output.to_path_buf(), 41 | lib_search_paths: archive_search_paths(sess), 42 | use_native_ar: false, 43 | // FIXME test for linux and System V derivatives instead 44 | use_gnu_style_archive: !sess.target.target.options.is_like_osx, 45 | }; 46 | 47 | let (src_archives, entries) = if let Some(input) = input { 48 | let mut archive = ar::Archive::new(File::open(input).unwrap()); 49 | let mut entries = Vec::new(); 50 | 51 | let mut i = 0; 52 | while let Some(entry) = archive.next_entry() { 53 | let entry = entry.unwrap(); 54 | entries.push(( 55 | String::from_utf8(entry.header().identifier().to_vec()).unwrap(), 56 | ArchiveEntry::FromArchive { 57 | archive_index: 0, 58 | entry_index: i, 59 | }, 60 | )); 61 | i += 1; 62 | } 63 | 64 | (vec![(input.to_owned(), archive)], entries) 65 | } else { 66 | (vec![], Vec::new()) 67 | }; 68 | 69 | ArArchiveBuilder { 70 | config, 71 | src_archives, 72 | entries, 73 | update_symbols: false, 74 | } 75 | } 76 | 77 | fn src_files(&mut self) -> Vec { 78 | self.entries.iter().map(|(name, _)| name.clone()).collect() 79 | } 80 | 81 | fn remove_file(&mut self, name: &str) { 82 | let index = self 83 | .entries 84 | .iter() 85 | .position(|(entry_name, _)| entry_name == name) 86 | .expect("Tried to remove file not existing in src archive"); 87 | self.entries.remove(index); 88 | } 89 | 90 | fn add_file(&mut self, file: &Path) { 91 | self.entries.push(( 92 | file.file_name().unwrap().to_str().unwrap().to_string(), 93 | ArchiveEntry::File(file.to_owned()), 94 | )); 95 | } 96 | 97 | fn add_native_library(&mut self, name: syntax::ast::Name) { 98 | let location = find_library(name, &self.config.lib_search_paths, self.config.sess); 99 | self.add_archive(location.clone(), |_| false) 100 | .unwrap_or_else(|e| { 101 | panic!( 102 | "failed to add native library {}: {}", 103 | location.to_string_lossy(), 104 | e 105 | ); 106 | }); 107 | } 108 | 109 | fn add_rlib( 110 | &mut self, 111 | rlib: &Path, 112 | name: &str, 113 | lto: bool, 114 | skip_objects: bool, 115 | ) -> std::io::Result<()> { 116 | let obj_start = name.to_owned(); 117 | 118 | self.add_archive(rlib.to_owned(), move |fname: &str| { 119 | // Ignore bytecode/metadata files, no matter the name. 120 | if fname.ends_with(RLIB_BYTECODE_EXTENSION) || fname == METADATA_FILENAME { 121 | return true; 122 | } 123 | 124 | // Don't include Rust objects if LTO is enabled 125 | if lto && fname.starts_with(&obj_start) && fname.ends_with(".o") { 126 | return true; 127 | } 128 | 129 | // Otherwise if this is *not* a rust object and we're skipping 130 | // objects then skip this file 131 | if skip_objects && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) { 132 | return true; 133 | } 134 | 135 | // ok, don't skip this 136 | return false; 137 | }) 138 | } 139 | 140 | fn update_symbols(&mut self) { 141 | self.update_symbols = true; 142 | } 143 | 144 | fn build(mut self) { 145 | use std::process::Command; 146 | 147 | fn add_file_using_ar(archive: &Path, file: &Path) { 148 | Command::new("ar") 149 | .arg("r") // add or replace file 150 | .arg("-c") // silence created file message 151 | .arg(archive) 152 | .arg(&file) 153 | .status() 154 | .unwrap(); 155 | } 156 | 157 | enum BuilderKind<'a> { 158 | Bsd(ar::Builder), 159 | Gnu(ar::GnuBuilder), 160 | NativeAr(&'a Path), 161 | } 162 | 163 | let mut builder = if self.config.use_native_ar { 164 | BuilderKind::NativeAr(&self.config.dst) 165 | } else if self.config.use_gnu_style_archive { 166 | BuilderKind::Gnu(ar::GnuBuilder::new( 167 | File::create(&self.config.dst).unwrap(), 168 | self.entries 169 | .iter() 170 | .map(|(name, _)| name.as_bytes().to_vec()) 171 | .collect(), 172 | )) 173 | } else { 174 | BuilderKind::Bsd(ar::Builder::new(File::create(&self.config.dst).unwrap())) 175 | }; 176 | 177 | // Add all files 178 | for (entry_name, entry) in self.entries.into_iter() { 179 | match entry { 180 | ArchiveEntry::FromArchive { 181 | archive_index, 182 | entry_index, 183 | } => { 184 | let (ref src_archive_path, ref mut src_archive) = 185 | self.src_archives[archive_index]; 186 | let entry = src_archive.jump_to_entry(entry_index).unwrap(); 187 | let orig_header = entry.header(); 188 | 189 | // FIXME implement clone for `ar::Archive`. 190 | let mut header = 191 | ar::Header::new(orig_header.identifier().to_vec(), orig_header.size()); 192 | header.set_mtime(orig_header.mtime()); 193 | header.set_uid(orig_header.uid()); 194 | header.set_gid(orig_header.gid()); 195 | header.set_mode(orig_header.mode()); 196 | 197 | match builder { 198 | BuilderKind::Bsd(ref mut builder) => { 199 | builder.append(&header, entry).unwrap() 200 | } 201 | BuilderKind::Gnu(ref mut builder) => { 202 | builder.append(&header, entry).unwrap() 203 | } 204 | BuilderKind::NativeAr(archive_file) => { 205 | Command::new("ar") 206 | .arg("x") 207 | .arg(src_archive_path) 208 | .arg(&entry_name) 209 | .status() 210 | .unwrap(); 211 | add_file_using_ar(archive_file, Path::new(&entry_name)); 212 | std::fs::remove_file(entry_name).unwrap(); 213 | } 214 | } 215 | } 216 | ArchiveEntry::File(file) => match builder { 217 | BuilderKind::Bsd(ref mut builder) => builder 218 | .append_file(entry_name.as_bytes(), &mut File::open(file).unwrap()) 219 | .unwrap(), 220 | BuilderKind::Gnu(ref mut builder) => builder 221 | .append_file(entry_name.as_bytes(), &mut File::open(file).unwrap()) 222 | .unwrap(), 223 | BuilderKind::NativeAr(archive_file) => add_file_using_ar(archive_file, &file), 224 | }, 225 | } 226 | } 227 | 228 | // Finalize archive 229 | std::mem::drop(builder); 230 | 231 | // Run ranlib to be able to link the archive 232 | let status = std::process::Command::new("ranlib") 233 | .arg(self.config.dst) 234 | .status() 235 | .expect("Couldn't run ranlib"); 236 | assert!( 237 | status.success(), 238 | "Ranlib exited with code {:?}", 239 | status.code() 240 | ); 241 | } 242 | } 243 | 244 | impl<'a> ArArchiveBuilder<'a> { 245 | fn add_archive(&mut self, archive_path: PathBuf, mut skip: F) -> std::io::Result<()> 246 | where 247 | F: FnMut(&str) -> bool + 'static, 248 | { 249 | let mut archive = ar::Archive::new(std::fs::File::open(&archive_path)?); 250 | let archive_index = self.src_archives.len(); 251 | 252 | let mut i = 0; 253 | while let Some(entry) = archive.next_entry() { 254 | let entry = entry.unwrap(); 255 | let file_name = String::from_utf8(entry.header().identifier().to_vec()).unwrap(); 256 | if !skip(&file_name) { 257 | self.entries.push(( 258 | file_name, 259 | ArchiveEntry::FromArchive { 260 | archive_index, 261 | entry_index: i, 262 | }, 263 | )); 264 | } 265 | i += 1; 266 | } 267 | 268 | self.src_archives.push((archive_path, archive)); 269 | Ok(()) 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /example/mini_core_hello_world.rs: -------------------------------------------------------------------------------- 1 | // Adapted from https://github.com/sunfishcode/mir2cranelift/blob/master/rust-examples/nocore-hello-world.rs 2 | 3 | #![feature(no_core, unboxed_closures, start, lang_items, box_syntax, slice_patterns, never_type, linkage, extern_types)] 4 | #![no_core] 5 | #![allow(dead_code)] 6 | 7 | extern crate mini_core; 8 | 9 | use mini_core::*; 10 | use mini_core::libc::*; 11 | 12 | unsafe extern "C" fn my_puts(s: *const u8) { 13 | puts(s); 14 | } 15 | 16 | #[lang = "termination"] 17 | trait Termination { 18 | fn report(self) -> i32; 19 | } 20 | 21 | impl Termination for () { 22 | fn report(self) -> i32 { 23 | unsafe { 24 | NUM = 6 * 7 + 1 + (1u8 == 1u8) as u8; // 44 25 | *NUM_REF as i32 26 | } 27 | } 28 | } 29 | 30 | trait SomeTrait { 31 | fn object_safe(&self); 32 | } 33 | 34 | impl SomeTrait for &'static str { 35 | fn object_safe(&self) { 36 | unsafe { 37 | puts(*self as *const str as *const u8); 38 | } 39 | } 40 | } 41 | 42 | struct NoisyDrop { 43 | text: &'static str, 44 | inner: NoisyDropInner, 45 | } 46 | 47 | struct NoisyDropInner; 48 | 49 | impl Drop for NoisyDrop { 50 | fn drop(&mut self) { 51 | unsafe { 52 | puts(self.text as *const str as *const u8); 53 | } 54 | } 55 | } 56 | 57 | impl Drop for NoisyDropInner { 58 | fn drop(&mut self) { 59 | unsafe { 60 | puts("Inner got dropped!\0" as *const str as *const u8); 61 | } 62 | } 63 | } 64 | 65 | impl SomeTrait for NoisyDrop { 66 | fn object_safe(&self) {} 67 | } 68 | 69 | enum Ordering { 70 | Less = -1, 71 | Equal = 0, 72 | Greater = 1, 73 | } 74 | 75 | #[lang = "start"] 76 | fn start( 77 | main: fn() -> T, 78 | argc: isize, 79 | argv: *const *const u8, 80 | ) -> isize { 81 | if argc == 3 { 82 | unsafe { puts(*argv); } 83 | unsafe { puts(*((argv as usize + intrinsics::size_of::<*const u8>()) as *const *const u8)); } 84 | unsafe { puts(*((argv as usize + 2 * intrinsics::size_of::<*const u8>()) as *const *const u8)); } 85 | } 86 | 87 | main().report(); 88 | 0 89 | } 90 | 91 | static mut NUM: u8 = 6 * 7; 92 | static NUM_REF: &'static u8 = unsafe { &NUM }; 93 | 94 | macro_rules! assert { 95 | ($e:expr) => { 96 | if !$e { 97 | panic(&(stringify!(! $e), file!(), line!(), 0)); 98 | } 99 | }; 100 | } 101 | 102 | macro_rules! assert_eq { 103 | ($l:expr, $r: expr) => { 104 | if $l != $r { 105 | panic(&(stringify!($l != $r), file!(), line!(), 0)); 106 | } 107 | } 108 | } 109 | 110 | struct Unique { 111 | pointer: *const T, 112 | _marker: PhantomData, 113 | } 114 | 115 | impl CoerceUnsized> for Unique where T: Unsize {} 116 | 117 | fn take_f32(_f: f32) {} 118 | fn take_unique(_u: Unique<()>) {} 119 | 120 | fn return_u128_pair() -> (u128, u128) { 121 | (0, 0) 122 | } 123 | 124 | fn call_return_u128_pair() { 125 | return_u128_pair(); 126 | } 127 | 128 | fn main() { 129 | take_unique(Unique { 130 | pointer: 0 as *const (), 131 | _marker: PhantomData, 132 | }); 133 | take_f32(0.1); 134 | 135 | call_return_u128_pair(); 136 | 137 | let slice = &[0, 1] as &[i32]; 138 | let slice_ptr = slice as *const [i32] as *const i32; 139 | 140 | assert_eq!(slice_ptr as usize % 4, 0); 141 | 142 | //return; 143 | 144 | unsafe { 145 | printf("Hello %s\n\0" as *const str as *const i8, "printf\0" as *const str as *const i8); 146 | 147 | let hello: &[u8] = b"Hello\0" as &[u8; 6]; 148 | let ptr: *const u8 = hello as *const [u8] as *const u8; 149 | puts(ptr); 150 | 151 | let world: Box<&str> = box "World!\0"; 152 | puts(*world as *const str as *const u8); 153 | world as Box; 154 | 155 | assert_eq!(intrinsics::bitreverse(0b10101000u8), 0b00010101u8); 156 | 157 | assert_eq!(intrinsics::bswap(0xabu8), 0xabu8); 158 | assert_eq!(intrinsics::bswap(0xddccu16), 0xccddu16); 159 | assert_eq!(intrinsics::bswap(0xffee_ddccu32), 0xccdd_eeffu32); 160 | assert_eq!(intrinsics::bswap(0x1234_5678_ffee_ddccu64), 0xccdd_eeff_7856_3412u64); 161 | 162 | assert_eq!(intrinsics::size_of_val(hello) as u8, 6); 163 | 164 | let chars = &['C', 'h', 'a', 'r', 's']; 165 | let chars = chars as &[char]; 166 | assert_eq!(intrinsics::size_of_val(chars) as u8, 4 * 5); 167 | 168 | let a: &dyn SomeTrait = &"abc\0"; 169 | a.object_safe(); 170 | 171 | assert_eq!(intrinsics::size_of_val(a) as u8, 16); 172 | assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4); 173 | 174 | assert_eq!(intrinsics::min_align_of::() as u8, 2); 175 | assert_eq!(intrinsics::min_align_of_val(&a) as u8, intrinsics::min_align_of::<&str>() as u8); 176 | 177 | assert!(!intrinsics::needs_drop::()); 178 | assert!(intrinsics::needs_drop::()); 179 | 180 | Unique { 181 | pointer: 0 as *const &str, 182 | _marker: PhantomData, 183 | } as Unique; 184 | 185 | struct MyDst(T); 186 | 187 | intrinsics::size_of_val(&MyDst([0u8; 4]) as &MyDst<[u8]>); 188 | 189 | struct Foo { 190 | x: u8, 191 | y: !, 192 | } 193 | 194 | unsafe fn zeroed() -> T { 195 | intrinsics::init::() 196 | } 197 | 198 | unsafe fn uninitialized() -> T { 199 | MaybeUninit { uninit: () }.value 200 | } 201 | 202 | zeroed::<(u8, u8)>(); 203 | #[allow(unreachable_code)] 204 | { 205 | if false { 206 | zeroed::(); 207 | zeroed::(); 208 | uninitialized::(); 209 | } 210 | } 211 | } 212 | 213 | let _ = box NoisyDrop { 214 | text: "Boxed outer got dropped!\0", 215 | inner: NoisyDropInner, 216 | } as Box; 217 | 218 | const FUNC_REF: Option = Some(main); 219 | match FUNC_REF { 220 | Some(_) => {}, 221 | None => assert!(false), 222 | } 223 | 224 | match Ordering::Less { 225 | Ordering::Less => {}, 226 | _ => assert!(false), 227 | } 228 | 229 | [NoisyDropInner, NoisyDropInner]; 230 | 231 | let x = &[0u32, 42u32] as &[u32]; 232 | match x { 233 | [] => assert_eq!(0u32, 1), 234 | [_, ref y @ ..] => assert_eq!(&x[1] as *const u32 as usize, &y[0] as *const u32 as usize), 235 | } 236 | 237 | assert_eq!(((|()| 42u8) as fn(()) -> u8)(()), 42); 238 | 239 | extern { 240 | #[linkage = "weak"] 241 | static ABC: *const u8; 242 | } 243 | 244 | { 245 | extern { 246 | #[linkage = "weak"] 247 | static ABC: *const u8; 248 | } 249 | } 250 | 251 | unsafe { assert_eq!(ABC as usize, 0); } 252 | 253 | &mut (|| Some(0 as *const ())) as &mut dyn FnMut() -> Option<*const ()>; 254 | 255 | let f = 1000.0; 256 | assert_eq!(f as u8, 255); 257 | let f2 = -1000.0; 258 | assert_eq!(f2 as i8, -128); 259 | assert_eq!(f2 as u8, 0); 260 | 261 | static ANOTHER_STATIC: &u8 = &A_STATIC; 262 | assert_eq!(*ANOTHER_STATIC, 42); 263 | 264 | check_niche_behavior(); 265 | 266 | extern "C" { 267 | type ExternType; 268 | } 269 | 270 | struct ExternTypeWrapper { 271 | _a: ExternType, 272 | } 273 | 274 | let nullptr = 0 as *const (); 275 | let extern_nullptr = nullptr as *const ExternTypeWrapper; 276 | extern_nullptr as *const (); 277 | let slice_ptr = &[] as *const [u8]; 278 | slice_ptr as *const u8; 279 | } 280 | 281 | // Copied ui/issues/issue-61696.rs 282 | 283 | pub enum Infallible {} 284 | 285 | // The check that the `bool` field of `V1` is encoding a "niche variant" 286 | // (i.e. not `V1`, so `V3` or `V4`) used to be mathematically incorrect, 287 | // causing valid `V1` values to be interpreted as other variants. 288 | pub enum E1 { 289 | V1 { f: bool }, 290 | V2 { f: Infallible }, 291 | V3, 292 | V4, 293 | } 294 | 295 | // Computing the discriminant used to be done using the niche type (here `u8`, 296 | // from the `bool` field of `V1`), overflowing for variants with large enough 297 | // indices (`V3` and `V4`), causing them to be interpreted as other variants. 298 | pub enum E2 { 299 | V1 { f: bool }, 300 | 301 | /*_00*/ _01(X), _02(X), _03(X), _04(X), _05(X), _06(X), _07(X), 302 | _08(X), _09(X), _0A(X), _0B(X), _0C(X), _0D(X), _0E(X), _0F(X), 303 | _10(X), _11(X), _12(X), _13(X), _14(X), _15(X), _16(X), _17(X), 304 | _18(X), _19(X), _1A(X), _1B(X), _1C(X), _1D(X), _1E(X), _1F(X), 305 | _20(X), _21(X), _22(X), _23(X), _24(X), _25(X), _26(X), _27(X), 306 | _28(X), _29(X), _2A(X), _2B(X), _2C(X), _2D(X), _2E(X), _2F(X), 307 | _30(X), _31(X), _32(X), _33(X), _34(X), _35(X), _36(X), _37(X), 308 | _38(X), _39(X), _3A(X), _3B(X), _3C(X), _3D(X), _3E(X), _3F(X), 309 | _40(X), _41(X), _42(X), _43(X), _44(X), _45(X), _46(X), _47(X), 310 | _48(X), _49(X), _4A(X), _4B(X), _4C(X), _4D(X), _4E(X), _4F(X), 311 | _50(X), _51(X), _52(X), _53(X), _54(X), _55(X), _56(X), _57(X), 312 | _58(X), _59(X), _5A(X), _5B(X), _5C(X), _5D(X), _5E(X), _5F(X), 313 | _60(X), _61(X), _62(X), _63(X), _64(X), _65(X), _66(X), _67(X), 314 | _68(X), _69(X), _6A(X), _6B(X), _6C(X), _6D(X), _6E(X), _6F(X), 315 | _70(X), _71(X), _72(X), _73(X), _74(X), _75(X), _76(X), _77(X), 316 | _78(X), _79(X), _7A(X), _7B(X), _7C(X), _7D(X), _7E(X), _7F(X), 317 | _80(X), _81(X), _82(X), _83(X), _84(X), _85(X), _86(X), _87(X), 318 | _88(X), _89(X), _8A(X), _8B(X), _8C(X), _8D(X), _8E(X), _8F(X), 319 | _90(X), _91(X), _92(X), _93(X), _94(X), _95(X), _96(X), _97(X), 320 | _98(X), _99(X), _9A(X), _9B(X), _9C(X), _9D(X), _9E(X), _9F(X), 321 | _A0(X), _A1(X), _A2(X), _A3(X), _A4(X), _A5(X), _A6(X), _A7(X), 322 | _A8(X), _A9(X), _AA(X), _AB(X), _AC(X), _AD(X), _AE(X), _AF(X), 323 | _B0(X), _B1(X), _B2(X), _B3(X), _B4(X), _B5(X), _B6(X), _B7(X), 324 | _B8(X), _B9(X), _BA(X), _BB(X), _BC(X), _BD(X), _BE(X), _BF(X), 325 | _C0(X), _C1(X), _C2(X), _C3(X), _C4(X), _C5(X), _C6(X), _C7(X), 326 | _C8(X), _C9(X), _CA(X), _CB(X), _CC(X), _CD(X), _CE(X), _CF(X), 327 | _D0(X), _D1(X), _D2(X), _D3(X), _D4(X), _D5(X), _D6(X), _D7(X), 328 | _D8(X), _D9(X), _DA(X), _DB(X), _DC(X), _DD(X), _DE(X), _DF(X), 329 | _E0(X), _E1(X), _E2(X), _E3(X), _E4(X), _E5(X), _E6(X), _E7(X), 330 | _E8(X), _E9(X), _EA(X), _EB(X), _EC(X), _ED(X), _EE(X), _EF(X), 331 | _F0(X), _F1(X), _F2(X), _F3(X), _F4(X), _F5(X), _F6(X), _F7(X), 332 | _F8(X), _F9(X), _FA(X), _FB(X), _FC(X), _FD(X), _FE(X), _FF(X), 333 | 334 | V3, 335 | V4, 336 | } 337 | 338 | fn check_niche_behavior () { 339 | if let E1::V2 { .. } = (E1::V1 { f: true }) { 340 | unsafe { intrinsics::abort(); } 341 | } 342 | 343 | if let E2::V1 { .. } = E2::V3:: { 344 | unsafe { intrinsics::abort(); } 345 | } 346 | } 347 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /example/mini_core.rs: -------------------------------------------------------------------------------- 1 | #![feature( 2 | no_core, lang_items, intrinsics, unboxed_closures, type_ascription, extern_types, 3 | untagged_unions, decl_macro, rustc_attrs 4 | )] 5 | #![no_core] 6 | #![allow(dead_code)] 7 | 8 | #[lang = "sized"] 9 | pub trait Sized {} 10 | 11 | #[lang = "unsize"] 12 | pub trait Unsize {} 13 | 14 | #[lang = "coerce_unsized"] 15 | pub trait CoerceUnsized {} 16 | 17 | impl<'a, 'b: 'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} 18 | impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} 19 | impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} 20 | impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} 21 | 22 | #[lang = "dispatch_from_dyn"] 23 | pub trait DispatchFromDyn {} 24 | 25 | // &T -> &U 26 | impl<'a, T: ?Sized+Unsize, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {} 27 | // &mut T -> &mut U 28 | impl<'a, T: ?Sized+Unsize, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {} 29 | // *const T -> *const U 30 | impl, U: ?Sized> DispatchFromDyn<*const U> for *const T {} 31 | // *mut T -> *mut U 32 | impl, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {} 33 | impl, U: ?Sized> DispatchFromDyn> for Box {} 34 | 35 | #[lang = "receiver"] 36 | pub trait Receiver {} 37 | 38 | impl Receiver for &T {} 39 | impl Receiver for &mut T {} 40 | impl Receiver for Box {} 41 | 42 | #[lang = "copy"] 43 | pub unsafe trait Copy {} 44 | 45 | unsafe impl Copy for bool {} 46 | unsafe impl Copy for u8 {} 47 | unsafe impl Copy for u16 {} 48 | unsafe impl Copy for u32 {} 49 | unsafe impl Copy for u64 {} 50 | unsafe impl Copy for usize {} 51 | unsafe impl Copy for i8 {} 52 | unsafe impl Copy for i16 {} 53 | unsafe impl Copy for i32 {} 54 | unsafe impl Copy for isize {} 55 | unsafe impl Copy for f32 {} 56 | unsafe impl Copy for char {} 57 | unsafe impl<'a, T: ?Sized> Copy for &'a T {} 58 | unsafe impl Copy for *const T {} 59 | unsafe impl Copy for *mut T {} 60 | 61 | #[lang = "sync"] 62 | pub unsafe trait Sync {} 63 | 64 | unsafe impl Sync for bool {} 65 | unsafe impl Sync for u8 {} 66 | unsafe impl Sync for u16 {} 67 | unsafe impl Sync for u32 {} 68 | unsafe impl Sync for u64 {} 69 | unsafe impl Sync for usize {} 70 | unsafe impl Sync for i8 {} 71 | unsafe impl Sync for i16 {} 72 | unsafe impl Sync for i32 {} 73 | unsafe impl Sync for isize {} 74 | unsafe impl Sync for char {} 75 | unsafe impl<'a, T: ?Sized> Sync for &'a T {} 76 | unsafe impl Sync for [u8; 16] {} 77 | 78 | #[lang = "freeze"] 79 | trait Freeze {} 80 | 81 | #[lang = "not"] 82 | pub trait Not { 83 | type Output; 84 | 85 | fn not(self) -> Self::Output; 86 | } 87 | 88 | impl Not for bool { 89 | type Output = bool; 90 | 91 | fn not(self) -> bool { 92 | !self 93 | } 94 | } 95 | 96 | #[lang = "mul"] 97 | pub trait Mul { 98 | type Output; 99 | 100 | #[must_use] 101 | fn mul(self, rhs: RHS) -> Self::Output; 102 | } 103 | 104 | impl Mul for u8 { 105 | type Output = Self; 106 | 107 | fn mul(self, rhs: Self) -> Self::Output { 108 | self * rhs 109 | } 110 | } 111 | 112 | impl Mul for usize { 113 | type Output = Self; 114 | 115 | fn mul(self, rhs: Self) -> Self::Output { 116 | self * rhs 117 | } 118 | } 119 | 120 | #[lang = "add"] 121 | pub trait Add { 122 | type Output; 123 | 124 | fn add(self, rhs: RHS) -> Self::Output; 125 | } 126 | 127 | impl Add for u8 { 128 | type Output = Self; 129 | 130 | fn add(self, rhs: Self) -> Self { 131 | self + rhs 132 | } 133 | } 134 | 135 | impl Add for i8 { 136 | type Output = Self; 137 | 138 | fn add(self, rhs: Self) -> Self { 139 | self + rhs 140 | } 141 | } 142 | 143 | impl Add for usize { 144 | type Output = Self; 145 | 146 | fn add(self, rhs: Self) -> Self { 147 | self + rhs 148 | } 149 | } 150 | 151 | #[lang = "sub"] 152 | pub trait Sub { 153 | type Output; 154 | 155 | fn sub(self, rhs: RHS) -> Self::Output; 156 | } 157 | 158 | impl Sub for usize { 159 | type Output = Self; 160 | 161 | fn sub(self, rhs: Self) -> Self { 162 | self - rhs 163 | } 164 | } 165 | 166 | impl Sub for u8 { 167 | type Output = Self; 168 | 169 | fn sub(self, rhs: Self) -> Self { 170 | self - rhs 171 | } 172 | } 173 | 174 | impl Sub for i8 { 175 | type Output = Self; 176 | 177 | fn sub(self, rhs: Self) -> Self { 178 | self - rhs 179 | } 180 | } 181 | 182 | impl Sub for i16 { 183 | type Output = Self; 184 | 185 | fn sub(self, rhs: Self) -> Self { 186 | self - rhs 187 | } 188 | } 189 | 190 | #[lang = "rem"] 191 | pub trait Rem { 192 | type Output; 193 | 194 | fn rem(self, rhs: RHS) -> Self::Output; 195 | } 196 | 197 | impl Rem for usize { 198 | type Output = Self; 199 | 200 | fn rem(self, rhs: Self) -> Self { 201 | self % rhs 202 | } 203 | } 204 | 205 | #[lang = "bitor"] 206 | pub trait BitOr { 207 | type Output; 208 | 209 | #[must_use] 210 | fn bitor(self, rhs: RHS) -> Self::Output; 211 | } 212 | 213 | impl BitOr for bool { 214 | type Output = bool; 215 | 216 | fn bitor(self, rhs: bool) -> bool { 217 | self | rhs 218 | } 219 | } 220 | 221 | impl<'a> BitOr for &'a bool { 222 | type Output = bool; 223 | 224 | fn bitor(self, rhs: bool) -> bool { 225 | *self | rhs 226 | } 227 | } 228 | 229 | #[lang = "eq"] 230 | pub trait PartialEq { 231 | fn eq(&self, other: &Rhs) -> bool; 232 | fn ne(&self, other: &Rhs) -> bool; 233 | } 234 | 235 | impl PartialEq for u8 { 236 | fn eq(&self, other: &u8) -> bool { 237 | (*self) == (*other) 238 | } 239 | fn ne(&self, other: &u8) -> bool { 240 | (*self) != (*other) 241 | } 242 | } 243 | 244 | impl PartialEq for u16 { 245 | fn eq(&self, other: &u16) -> bool { 246 | (*self) == (*other) 247 | } 248 | fn ne(&self, other: &u16) -> bool { 249 | (*self) != (*other) 250 | } 251 | } 252 | 253 | impl PartialEq for u32 { 254 | fn eq(&self, other: &u32) -> bool { 255 | (*self) == (*other) 256 | } 257 | fn ne(&self, other: &u32) -> bool { 258 | (*self) != (*other) 259 | } 260 | } 261 | 262 | 263 | impl PartialEq for u64 { 264 | fn eq(&self, other: &u64) -> bool { 265 | (*self) == (*other) 266 | } 267 | fn ne(&self, other: &u64) -> bool { 268 | (*self) != (*other) 269 | } 270 | } 271 | 272 | impl PartialEq for usize { 273 | fn eq(&self, other: &usize) -> bool { 274 | (*self) == (*other) 275 | } 276 | fn ne(&self, other: &usize) -> bool { 277 | (*self) != (*other) 278 | } 279 | } 280 | 281 | impl PartialEq for i8 { 282 | fn eq(&self, other: &i8) -> bool { 283 | (*self) == (*other) 284 | } 285 | fn ne(&self, other: &i8) -> bool { 286 | (*self) != (*other) 287 | } 288 | } 289 | 290 | impl PartialEq for i32 { 291 | fn eq(&self, other: &i32) -> bool { 292 | (*self) == (*other) 293 | } 294 | fn ne(&self, other: &i32) -> bool { 295 | (*self) != (*other) 296 | } 297 | } 298 | 299 | impl PartialEq for isize { 300 | fn eq(&self, other: &isize) -> bool { 301 | (*self) == (*other) 302 | } 303 | fn ne(&self, other: &isize) -> bool { 304 | (*self) != (*other) 305 | } 306 | } 307 | 308 | impl PartialEq for char { 309 | fn eq(&self, other: &char) -> bool { 310 | (*self) == (*other) 311 | } 312 | fn ne(&self, other: &char) -> bool { 313 | (*self) != (*other) 314 | } 315 | } 316 | 317 | impl PartialEq for *const T { 318 | fn eq(&self, other: &*const T) -> bool { 319 | *self == *other 320 | } 321 | fn ne(&self, other: &*const T) -> bool { 322 | *self != *other 323 | } 324 | } 325 | 326 | #[lang = "neg"] 327 | pub trait Neg { 328 | type Output; 329 | 330 | fn neg(self) -> Self::Output; 331 | } 332 | 333 | impl Neg for i8 { 334 | type Output = i8; 335 | 336 | fn neg(self) -> i8 { 337 | -self 338 | } 339 | } 340 | 341 | impl Neg for i16 { 342 | type Output = i16; 343 | 344 | fn neg(self) -> i16 { 345 | self 346 | } 347 | } 348 | 349 | impl Neg for isize { 350 | type Output = isize; 351 | 352 | fn neg(self) -> isize { 353 | -self 354 | } 355 | } 356 | 357 | impl Neg for f32 { 358 | type Output = f32; 359 | 360 | fn neg(self) -> f32 { 361 | -self 362 | } 363 | } 364 | 365 | pub enum Option { 366 | Some(T), 367 | None, 368 | } 369 | 370 | pub use Option::*; 371 | 372 | #[lang = "phantom_data"] 373 | pub struct PhantomData; 374 | 375 | #[lang = "fn_once"] 376 | #[rustc_paren_sugar] 377 | pub trait FnOnce { 378 | type Output; 379 | 380 | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; 381 | } 382 | 383 | #[lang = "fn_mut"] 384 | #[rustc_paren_sugar] 385 | pub trait FnMut: FnOnce { 386 | extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; 387 | } 388 | 389 | #[lang = "panic"] 390 | pub fn panic(&(_msg, _file, _line, _col): &(&'static str, &'static str, u32, u32)) -> ! { 391 | unsafe { 392 | libc::puts("Panicking\0" as *const str as *const u8); 393 | intrinsics::abort(); 394 | } 395 | } 396 | 397 | #[lang = "eh_personality"] 398 | fn eh_personality() -> ! { 399 | loop {} 400 | } 401 | 402 | #[lang = "drop_in_place"] 403 | #[allow(unconditional_recursion)] 404 | pub unsafe fn drop_in_place(to_drop: *mut T) { 405 | // Code here does not matter - this is replaced by the 406 | // real drop glue by the compiler. 407 | drop_in_place(to_drop); 408 | } 409 | 410 | #[lang = "deref"] 411 | pub trait Deref { 412 | type Target: ?Sized; 413 | 414 | fn deref(&self) -> &Self::Target; 415 | } 416 | 417 | #[lang = "owned_box"] 418 | pub struct Box(*mut T); 419 | 420 | impl, U: ?Sized> CoerceUnsized> for Box {} 421 | 422 | impl Drop for Box { 423 | fn drop(&mut self) { 424 | // drop is currently performed by compiler. 425 | } 426 | } 427 | 428 | impl Deref for Box { 429 | type Target = T; 430 | 431 | fn deref(&self) -> &Self::Target { 432 | &**self 433 | } 434 | } 435 | 436 | #[lang = "exchange_malloc"] 437 | unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { 438 | libc::malloc(size) 439 | } 440 | 441 | #[lang = "box_free"] 442 | unsafe fn box_free(ptr: *mut T) { 443 | libc::free(ptr as *mut u8); 444 | } 445 | 446 | #[lang = "drop"] 447 | pub trait Drop { 448 | fn drop(&mut self); 449 | } 450 | 451 | #[allow(unions_with_drop_fields)] 452 | pub union MaybeUninit { 453 | pub uninit: (), 454 | pub value: T, 455 | } 456 | 457 | pub mod intrinsics { 458 | extern "rust-intrinsic" { 459 | pub fn abort() -> !; 460 | pub fn size_of() -> usize; 461 | pub fn size_of_val(val: &T) -> usize; 462 | pub fn min_align_of() -> usize; 463 | pub fn min_align_of_val(val: &T) -> usize; 464 | pub fn copy(src: *const T, dst: *mut T, count: usize); 465 | pub fn transmute(e: T) -> U; 466 | pub fn init() -> T; 467 | pub fn ctlz_nonzero(x: T) -> T; 468 | pub fn needs_drop() -> bool; 469 | pub fn bitreverse(x: T) -> T; 470 | pub fn bswap(x: T) -> T; 471 | } 472 | } 473 | 474 | pub mod libc { 475 | #[link(name = "c")] 476 | extern "C" { 477 | pub fn puts(s: *const u8); 478 | pub fn printf(format: *const i8, ...) -> i32; 479 | pub fn malloc(size: usize) -> *mut u8; 480 | pub fn free(ptr: *mut u8); 481 | pub fn memcpy(dst: *mut u8, src: *const u8, size: usize); 482 | pub fn memmove(dst: *mut u8, src: *const u8, size: usize); 483 | pub fn strncpy(dst: *mut u8, src: *const u8, size: usize); 484 | } 485 | } 486 | 487 | #[lang = "index"] 488 | pub trait Index { 489 | type Output: ?Sized; 490 | fn index(&self, index: Idx) -> &Self::Output; 491 | } 492 | 493 | impl Index for [T; 3] { 494 | type Output = T; 495 | 496 | fn index(&self, index: usize) -> &Self::Output { 497 | &self[index] 498 | } 499 | } 500 | 501 | impl Index for [T] { 502 | type Output = T; 503 | 504 | fn index(&self, index: usize) -> &Self::Output { 505 | &self[index] 506 | } 507 | } 508 | 509 | extern { 510 | type VaListImpl; 511 | } 512 | 513 | #[lang = "va_list"] 514 | #[repr(transparent)] 515 | pub struct VaList<'a>(&'a mut VaListImpl); 516 | 517 | #[rustc_builtin_macro] 518 | #[rustc_macro_transparency = "semitransparent"] 519 | pub macro stringify($($t:tt)*) { /* compiler built-in */ } 520 | 521 | #[rustc_builtin_macro] 522 | #[rustc_macro_transparency = "semitransparent"] 523 | pub macro file() { /* compiler built-in */ } 524 | 525 | #[rustc_builtin_macro] 526 | #[rustc_macro_transparency = "semitransparent"] 527 | pub macro line() { /* compiler built-in */ } 528 | 529 | #[rustc_builtin_macro] 530 | #[rustc_macro_transparency = "semitransparent"] 531 | pub macro cfg() { /* compiler built-in */ } 532 | 533 | pub static A_STATIC: u8 = 42; 534 | -------------------------------------------------------------------------------- /src/common.rs: -------------------------------------------------------------------------------- 1 | use rustc::ty::layout::{FloatTy, Integer, Primitive}; 2 | use rustc_target::spec::{HasTargetSpec, Target}; 3 | 4 | use cranelift::codegen::ir::{InstructionData, Opcode, ValueDef}; 5 | 6 | use crate::prelude::*; 7 | 8 | pub fn mir_var(loc: Local) -> Variable { 9 | Variable::with_u32(loc.index() as u32) 10 | } 11 | 12 | pub fn pointer_ty(tcx: TyCtxt) -> types::Type { 13 | match tcx.data_layout.pointer_size.bits() { 14 | 16 => types::I16, 15 | 32 => types::I32, 16 | 64 => types::I64, 17 | bits => bug!("ptr_sized_integer: unknown pointer bit size {}", bits), 18 | } 19 | } 20 | 21 | pub fn scalar_to_clif_type(tcx: TyCtxt, scalar: Scalar) -> Type { 22 | match scalar.value { 23 | Primitive::Int(int, _sign) => match int { 24 | Integer::I8 => types::I8, 25 | Integer::I16 => types::I16, 26 | Integer::I32 => types::I32, 27 | Integer::I64 => types::I64, 28 | Integer::I128 => types::I128, 29 | }, 30 | Primitive::Float(flt) => match flt { 31 | FloatTy::F32 => types::F32, 32 | FloatTy::F64 => types::F64, 33 | }, 34 | Primitive::Pointer => pointer_ty(tcx), 35 | } 36 | } 37 | 38 | pub fn clif_type_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option { 39 | Some(match ty.kind { 40 | ty::Bool => types::I8, 41 | ty::Uint(size) => match size { 42 | UintTy::U8 => types::I8, 43 | UintTy::U16 => types::I16, 44 | UintTy::U32 => types::I32, 45 | UintTy::U64 => types::I64, 46 | UintTy::U128 => types::I128, 47 | UintTy::Usize => pointer_ty(tcx), 48 | }, 49 | ty::Int(size) => match size { 50 | IntTy::I8 => types::I8, 51 | IntTy::I16 => types::I16, 52 | IntTy::I32 => types::I32, 53 | IntTy::I64 => types::I64, 54 | IntTy::I128 => types::I128, 55 | IntTy::Isize => pointer_ty(tcx), 56 | }, 57 | ty::Char => types::I32, 58 | ty::Float(size) => match size { 59 | FloatTy::F32 => types::F32, 60 | FloatTy::F64 => types::F64, 61 | }, 62 | ty::FnPtr(_) => pointer_ty(tcx), 63 | ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl: _ }) | ty::Ref(_, pointee_ty, _) => { 64 | if has_ptr_meta(tcx, pointee_ty) { 65 | return None; 66 | } else { 67 | pointer_ty(tcx) 68 | } 69 | } 70 | ty::Param(_) => bug!("ty param {:?}", ty), 71 | _ => return None, 72 | }) 73 | } 74 | 75 | /// Is a pointer to this type a fat ptr? 76 | pub fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { 77 | let ptr_ty = tcx.mk_ptr(TypeAndMut { ty, mutbl: rustc::hir::Mutability::MutImmutable }); 78 | match &tcx.layout_of(ParamEnv::reveal_all().and(ptr_ty)).unwrap().abi { 79 | Abi::Scalar(_) => false, 80 | Abi::ScalarPair(_, _) => true, 81 | abi => unreachable!("Abi of ptr to {:?} is {:?}???", ty, abi), 82 | } 83 | } 84 | 85 | pub fn codegen_select(bcx: &mut FunctionBuilder, cond: Value, lhs: Value, rhs: Value) -> Value { 86 | let lhs_ty = bcx.func.dfg.value_type(lhs); 87 | let rhs_ty = bcx.func.dfg.value_type(rhs); 88 | assert_eq!(lhs_ty, rhs_ty); 89 | if lhs_ty == types::I8 || lhs_ty == types::I16 { 90 | // FIXME workaround for missing encoding for select.i8 91 | let lhs = bcx.ins().uextend(types::I32, lhs); 92 | let rhs = bcx.ins().uextend(types::I32, rhs); 93 | let res = bcx.ins().select(cond, lhs, rhs); 94 | bcx.ins().ireduce(lhs_ty, res) 95 | } else { 96 | bcx.ins().select(cond, lhs, rhs) 97 | } 98 | } 99 | 100 | pub fn codegen_icmp( 101 | fx: &mut FunctionCx<'_, '_, impl Backend>, 102 | intcc: IntCC, 103 | lhs: Value, 104 | rhs: Value, 105 | ) -> Value { 106 | let lhs_ty = fx.bcx.func.dfg.value_type(lhs); 107 | let rhs_ty = fx.bcx.func.dfg.value_type(rhs); 108 | assert_eq!(lhs_ty, rhs_ty); 109 | if lhs_ty == types::I128 { 110 | // FIXME legalize `icmp.i128` in Cranelift 111 | 112 | let (lhs_lsb, lhs_msb) = fx.bcx.ins().isplit(lhs); 113 | let (rhs_lsb, rhs_msb) = fx.bcx.ins().isplit(rhs); 114 | 115 | match intcc { 116 | IntCC::Equal => { 117 | let lsb_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_lsb, rhs_lsb); 118 | let msb_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_msb, rhs_msb); 119 | fx.bcx.ins().band(lsb_eq, msb_eq) 120 | } 121 | IntCC::NotEqual => { 122 | let lsb_ne = fx.bcx.ins().icmp(IntCC::NotEqual, lhs_lsb, rhs_lsb); 123 | let msb_ne = fx.bcx.ins().icmp(IntCC::NotEqual, lhs_msb, rhs_msb); 124 | fx.bcx.ins().bor(lsb_ne, msb_ne) 125 | } 126 | _ => { 127 | // if msb_eq { 128 | // lsb_cc 129 | // } else { 130 | // msb_cc 131 | // } 132 | 133 | let msb_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_msb, rhs_msb); 134 | let lsb_cc = fx.bcx.ins().icmp(intcc, lhs_lsb, rhs_lsb); 135 | let msb_cc = fx.bcx.ins().icmp(intcc, lhs_msb, rhs_msb); 136 | 137 | fx.bcx.ins().select(msb_eq, lsb_cc, msb_cc) 138 | } 139 | } 140 | } else { 141 | fx.bcx.ins().icmp(intcc, lhs, rhs) 142 | } 143 | } 144 | 145 | pub fn codegen_icmp_imm( 146 | fx: &mut FunctionCx<'_, '_, impl Backend>, 147 | intcc: IntCC, 148 | lhs: Value, 149 | rhs: i128, 150 | ) -> Value { 151 | let lhs_ty = fx.bcx.func.dfg.value_type(lhs); 152 | if lhs_ty == types::I128 { 153 | // FIXME legalize `icmp_imm.i128` in Cranelift 154 | 155 | let (lhs_lsb, lhs_msb) = fx.bcx.ins().isplit(lhs); 156 | let (rhs_lsb, rhs_msb) = (rhs as u128 as u64 as i64, (rhs as u128 >> 64) as u64 as i64); 157 | 158 | match intcc { 159 | IntCC::Equal => { 160 | let lsb_eq = fx.bcx.ins().icmp_imm(IntCC::Equal, lhs_lsb, rhs_lsb); 161 | let msb_eq = fx.bcx.ins().icmp_imm(IntCC::Equal, lhs_msb, rhs_msb); 162 | fx.bcx.ins().band(lsb_eq, msb_eq) 163 | } 164 | IntCC::NotEqual => { 165 | let lsb_ne = fx.bcx.ins().icmp_imm(IntCC::NotEqual, lhs_lsb, rhs_lsb); 166 | let msb_ne = fx.bcx.ins().icmp_imm(IntCC::NotEqual, lhs_msb, rhs_msb); 167 | fx.bcx.ins().bor(lsb_ne, msb_ne) 168 | } 169 | _ => { 170 | // if msb_eq { 171 | // lsb_cc 172 | // } else { 173 | // msb_cc 174 | // } 175 | 176 | let msb_eq = fx.bcx.ins().icmp_imm(IntCC::Equal, lhs_msb, rhs_msb); 177 | let lsb_cc = fx.bcx.ins().icmp_imm(intcc, lhs_lsb, rhs_lsb); 178 | let msb_cc = fx.bcx.ins().icmp_imm(intcc, lhs_msb, rhs_msb); 179 | 180 | fx.bcx.ins().select(msb_eq, lsb_cc, msb_cc) 181 | } 182 | } 183 | } else { 184 | let rhs = i64::try_from(rhs).expect("codegen_icmp_imm rhs out of range for <128bit int"); 185 | fx.bcx.ins().icmp_imm(intcc, lhs, rhs) 186 | } 187 | } 188 | 189 | fn resolve_normal_value_imm(func: &Function, val: Value) -> Option { 190 | if let ValueDef::Result(inst, 0 /*param*/) = func.dfg.value_def(val) { 191 | if let InstructionData::UnaryImm { 192 | opcode: Opcode::Iconst, 193 | imm, 194 | } = func.dfg[inst] 195 | { 196 | Some(imm.into()) 197 | } else { 198 | None 199 | } 200 | } else { 201 | None 202 | } 203 | } 204 | 205 | fn resolve_128bit_value_imm(func: &Function, val: Value) -> Option { 206 | let (lsb, msb) = if let ValueDef::Result(inst, 0 /*param*/) = func.dfg.value_def(val) { 207 | if let InstructionData::Binary { 208 | opcode: Opcode::Iconcat, 209 | args: [lsb, msb], 210 | } = func.dfg[inst] 211 | { 212 | (lsb, msb) 213 | } else { 214 | return None; 215 | } 216 | } else { 217 | return None; 218 | }; 219 | 220 | let lsb = resolve_normal_value_imm(func, lsb)? as u64 as u128; 221 | let msb = resolve_normal_value_imm(func, msb)? as u64 as u128; 222 | 223 | Some(msb << 64 | lsb) 224 | } 225 | 226 | pub fn resolve_value_imm(func: &Function, val: Value) -> Option { 227 | if func.dfg.value_type(val) == types::I128 { 228 | resolve_128bit_value_imm(func, val) 229 | } else { 230 | resolve_normal_value_imm(func, val).map(|imm| imm as u64 as u128) 231 | } 232 | } 233 | 234 | pub fn type_min_max_value(ty: Type, signed: bool) -> (i64, i64) { 235 | assert!(ty.is_int()); 236 | let min = match (ty, signed) { 237 | (types::I8, false) | (types::I16, false) | (types::I32, false) | (types::I64, false) => { 238 | 0i64 239 | } 240 | (types::I8, true) => i8::min_value() as i64, 241 | (types::I16, true) => i16::min_value() as i64, 242 | (types::I32, true) => i32::min_value() as i64, 243 | (types::I64, true) => i64::min_value(), 244 | (types::I128, _) => unimplemented!(), 245 | _ => unreachable!(), 246 | }; 247 | 248 | let max = match (ty, signed) { 249 | (types::I8, false) => u8::max_value() as i64, 250 | (types::I16, false) => u16::max_value() as i64, 251 | (types::I32, false) => u32::max_value() as i64, 252 | (types::I64, false) => u64::max_value() as i64, 253 | (types::I8, true) => i8::max_value() as i64, 254 | (types::I16, true) => i16::max_value() as i64, 255 | (types::I32, true) => i32::max_value() as i64, 256 | (types::I64, true) => i64::max_value(), 257 | (types::I128, _) => unimplemented!(), 258 | _ => unreachable!(), 259 | }; 260 | 261 | (min, max) 262 | } 263 | 264 | pub fn type_sign(ty: Ty<'_>) -> bool { 265 | match ty.kind { 266 | ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..) | ty::Char | ty::Uint(..) | ty::Bool => false, 267 | ty::Int(..) => true, 268 | ty::Float(..) => false, // `signed` is unused for floats 269 | _ => panic!("{}", ty), 270 | } 271 | } 272 | 273 | pub struct FunctionCx<'clif, 'tcx, B: Backend + 'static> { 274 | // FIXME use a reference to `CodegenCx` instead of `tcx`, `module` and `constants` and `caches` 275 | pub tcx: TyCtxt<'tcx>, 276 | pub module: &'clif mut Module, 277 | pub pointer_type: Type, // Cached from module 278 | 279 | pub instance: Instance<'tcx>, 280 | pub mir: &'tcx Body<'tcx>, 281 | 282 | pub bcx: FunctionBuilder<'clif>, 283 | pub ebb_map: HashMap, 284 | pub local_map: HashMap>, 285 | 286 | pub clif_comments: crate::pretty_clif::CommentWriter, 287 | pub constants_cx: &'clif mut crate::constant::ConstantCx, 288 | pub caches: &'clif mut Caches<'tcx>, 289 | pub source_info_set: indexmap::IndexSet, 290 | } 291 | 292 | impl<'tcx, B: Backend> LayoutOf for FunctionCx<'_, 'tcx, B> { 293 | type Ty = Ty<'tcx>; 294 | type TyLayout = TyLayout<'tcx>; 295 | 296 | fn layout_of(&self, ty: Ty<'tcx>) -> TyLayout<'tcx> { 297 | let ty = self.monomorphize(&ty); 298 | self.tcx 299 | .layout_of(ParamEnv::reveal_all().and(&ty)) 300 | .unwrap_or_else(|e| { 301 | if let layout::LayoutError::SizeOverflow(_) = e { 302 | self.tcx.sess.fatal(&e.to_string()) 303 | } else { 304 | bug!("failed to get layout for `{}`: {}", ty, e) 305 | } 306 | }) 307 | } 308 | } 309 | 310 | impl<'tcx, B: Backend + 'static> layout::HasTyCtxt<'tcx> for FunctionCx<'_, 'tcx, B> { 311 | fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { 312 | self.tcx 313 | } 314 | } 315 | 316 | impl<'tcx, B: Backend + 'static> layout::HasDataLayout for FunctionCx<'_, 'tcx, B> { 317 | fn data_layout(&self) -> &layout::TargetDataLayout { 318 | &self.tcx.data_layout 319 | } 320 | } 321 | 322 | impl<'tcx, B: Backend + 'static> layout::HasParamEnv<'tcx> for FunctionCx<'_, 'tcx, B> { 323 | fn param_env(&self) -> ParamEnv<'tcx> { 324 | ParamEnv::reveal_all() 325 | } 326 | } 327 | 328 | impl<'tcx, B: Backend + 'static> HasTargetSpec for FunctionCx<'_, 'tcx, B> { 329 | fn target_spec(&self) -> &Target { 330 | &self.tcx.sess.target.target 331 | } 332 | } 333 | 334 | impl<'tcx, B: Backend> BackendTypes for FunctionCx<'_, 'tcx, B> { 335 | type Value = Value; 336 | type BasicBlock = Ebb; 337 | type Type = Type; 338 | type Funclet = !; 339 | type DIScope = !; 340 | } 341 | 342 | impl<'tcx, B: Backend + 'static> FunctionCx<'_, 'tcx, B> { 343 | pub fn monomorphize(&self, value: &T) -> T 344 | where 345 | T: TypeFoldable<'tcx>, 346 | { 347 | self.tcx.subst_and_normalize_erasing_regions( 348 | self.instance.substs, 349 | ty::ParamEnv::reveal_all(), 350 | value, 351 | ) 352 | } 353 | 354 | pub fn clif_type(&self, ty: Ty<'tcx>) -> Option { 355 | clif_type_from_ty(self.tcx, self.monomorphize(&ty)) 356 | } 357 | 358 | pub fn get_ebb(&self, bb: BasicBlock) -> Ebb { 359 | *self.ebb_map.get(&bb).unwrap() 360 | } 361 | 362 | pub fn get_local_place(&mut self, local: Local) -> CPlace<'tcx> { 363 | *self.local_map.get(&local).unwrap() 364 | } 365 | 366 | pub fn set_debug_loc(&mut self, source_info: mir::SourceInfo) { 367 | let (index, _) = self.source_info_set.insert_full(source_info); 368 | self.bcx.set_srcloc(SourceLoc::new(index as u32)); 369 | } 370 | } 371 | -------------------------------------------------------------------------------- /src/driver.rs: -------------------------------------------------------------------------------- 1 | use std::any::Any; 2 | use std::ffi::CString; 3 | use std::os::raw::{c_char, c_int}; 4 | 5 | use rustc::middle::cstore::EncodedMetadata; 6 | use rustc::mir::mono::{Linkage as RLinkage, Visibility}; 7 | use rustc::session::config::{DebugInfo, OutputType}; 8 | use rustc_codegen_ssa::back::linker::LinkerInfo; 9 | use rustc_codegen_ssa::CrateInfo; 10 | 11 | use cranelift_faerie::*; 12 | 13 | use crate::prelude::*; 14 | 15 | pub fn codegen_crate( 16 | tcx: TyCtxt<'_>, 17 | metadata: EncodedMetadata, 18 | need_metadata_module: bool, 19 | ) -> Box { 20 | tcx.sess.abort_if_errors(); 21 | 22 | if std::env::var("SHOULD_RUN").is_ok() 23 | && tcx.sess.crate_types.get().contains(&CrateType::Executable) 24 | { 25 | #[cfg(not(target_arch = "wasm32"))] 26 | let _: ! = run_jit(tcx); 27 | 28 | #[cfg(target_arch = "wasm32")] 29 | panic!("jit not supported on wasm"); 30 | } 31 | 32 | run_aot(tcx, metadata, need_metadata_module) 33 | } 34 | 35 | #[cfg(not(target_arch = "wasm32"))] 36 | fn run_jit(tcx: TyCtxt<'_>) -> ! { 37 | use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder}; 38 | 39 | let imported_symbols = load_imported_symbols_for_jit(tcx); 40 | 41 | let mut jit_builder = SimpleJITBuilder::with_isa( 42 | crate::build_isa(tcx.sess, false), 43 | cranelift_module::default_libcall_names(), 44 | ); 45 | jit_builder.symbols(imported_symbols); 46 | let mut jit_module: Module = Module::new(jit_builder); 47 | assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type()); 48 | 49 | let sig = Signature { 50 | params: vec![ 51 | AbiParam::new(jit_module.target_config().pointer_type()), 52 | AbiParam::new(jit_module.target_config().pointer_type()), 53 | ], 54 | returns: vec![AbiParam::new( 55 | jit_module.target_config().pointer_type(), /*isize*/ 56 | )], 57 | call_conv: crate::default_call_conv(tcx.sess), 58 | }; 59 | let main_func_id = jit_module 60 | .declare_function("main", Linkage::Import, &sig) 61 | .unwrap(); 62 | 63 | codegen_cgus(tcx, &mut jit_module, &mut None); 64 | crate::allocator::codegen(tcx, &mut jit_module); 65 | jit_module.finalize_definitions(); 66 | 67 | tcx.sess.abort_if_errors(); 68 | 69 | let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id); 70 | 71 | println!("Rustc codegen cranelift will JIT run the executable, because the SHOULD_RUN env var is set"); 72 | 73 | let f: extern "C" fn(c_int, *const *const c_char) -> c_int = 74 | unsafe { ::std::mem::transmute(finalized_main) }; 75 | 76 | let args = ::std::env::var("JIT_ARGS").unwrap_or_else(|_| String::new()); 77 | let args = args 78 | .split(" ") 79 | .chain(Some(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string())) 80 | .map(|arg| CString::new(arg).unwrap()) 81 | .collect::>(); 82 | let argv = args.iter().map(|arg| arg.as_ptr()).collect::>(); 83 | // TODO: Rust doesn't care, but POSIX argv has a NULL sentinel at the end 84 | 85 | let ret = f(args.len() as c_int, argv.as_ptr()); 86 | 87 | jit_module.finish(); 88 | std::process::exit(ret); 89 | } 90 | 91 | fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> { 92 | use rustc::middle::dependency_format::Linkage; 93 | 94 | let mut dylib_paths = Vec::new(); 95 | 96 | let crate_info = CrateInfo::new(tcx); 97 | let formats = tcx.dependency_formats(LOCAL_CRATE); 98 | let data = &formats 99 | .iter() 100 | .find(|(crate_type, _data)| *crate_type == CrateType::Executable) 101 | .unwrap() 102 | .1; 103 | for &(cnum, _) in &crate_info.used_crates_dynamic { 104 | let src = &crate_info.used_crate_source[&cnum]; 105 | match data[cnum.as_usize() - 1] { 106 | Linkage::NotLinked | Linkage::IncludedFromDylib => {} 107 | Linkage::Static => { 108 | let name = tcx.crate_name(cnum); 109 | let mut err = tcx 110 | .sess 111 | .struct_err(&format!("Can't load static lib {}", name.as_str())); 112 | err.note("rustc_codegen_cranelift can only load dylibs in JIT mode."); 113 | err.emit(); 114 | } 115 | Linkage::Dynamic => { 116 | dylib_paths.push(src.dylib.as_ref().unwrap().0.clone()); 117 | } 118 | } 119 | } 120 | 121 | let mut imported_symbols = Vec::new(); 122 | for path in dylib_paths { 123 | use object::Object; 124 | let lib = libloading::Library::new(&path).unwrap(); 125 | let obj = std::fs::read(path).unwrap(); 126 | let obj = object::File::parse(&obj).unwrap(); 127 | imported_symbols.extend(obj.dynamic_symbols().filter_map(|(_idx, symbol)| { 128 | let name = symbol.name().unwrap().to_string(); 129 | if name.is_empty() || !symbol.is_global() || symbol.is_undefined() { 130 | return None; 131 | } 132 | let symbol: libloading::Symbol<*const u8> = 133 | unsafe { lib.get(name.as_bytes()) }.unwrap(); 134 | Some((name, *symbol)) 135 | })); 136 | std::mem::forget(lib) 137 | } 138 | 139 | tcx.sess.abort_if_errors(); 140 | 141 | imported_symbols 142 | } 143 | 144 | fn run_aot( 145 | tcx: TyCtxt<'_>, 146 | metadata: EncodedMetadata, 147 | need_metadata_module: bool, 148 | ) -> Box { 149 | let new_module = |name: String| { 150 | let module: Module = Module::new( 151 | FaerieBuilder::new( 152 | crate::build_isa(tcx.sess, true), 153 | name + ".o", 154 | FaerieTrapCollection::Disabled, 155 | cranelift_module::default_libcall_names(), 156 | ) 157 | .unwrap(), 158 | ); 159 | assert_eq!(pointer_ty(tcx), module.target_config().pointer_type()); 160 | module 161 | }; 162 | 163 | let emit_module = |kind: ModuleKind, 164 | mut module: Module, 165 | debug: Option| { 166 | module.finalize_definitions(); 167 | let mut artifact = module.finish().artifact; 168 | 169 | if let Some(mut debug) = debug { 170 | debug.emit(&mut artifact); 171 | } 172 | 173 | let tmp_file = tcx 174 | .output_filenames(LOCAL_CRATE) 175 | .temp_path(OutputType::Object, Some(&artifact.name)); 176 | let obj = artifact.emit().unwrap(); 177 | std::fs::write(&tmp_file, obj).unwrap(); 178 | CompiledModule { 179 | name: artifact.name, 180 | kind, 181 | object: Some(tmp_file), 182 | bytecode: None, 183 | bytecode_compressed: None, 184 | } 185 | }; 186 | 187 | let mut faerie_module = new_module("some_file".to_string()); 188 | 189 | let mut debug = if tcx.sess.opts.debuginfo != DebugInfo::None 190 | // macOS debuginfo doesn't work yet (see #303) 191 | && !tcx.sess.target.target.options.is_like_osx 192 | { 193 | let debug = DebugContext::new( 194 | tcx, 195 | faerie_module.target_config().pointer_type().bytes() as u8, 196 | ); 197 | Some(debug) 198 | } else { 199 | None 200 | }; 201 | 202 | codegen_cgus(tcx, &mut faerie_module, &mut debug); 203 | 204 | tcx.sess.abort_if_errors(); 205 | 206 | let mut allocator_module = new_module("allocator_shim".to_string()); 207 | let created_alloc_shim = crate::allocator::codegen(tcx, &mut allocator_module); 208 | 209 | rustc_incremental::assert_dep_graph(tcx); 210 | rustc_incremental::save_dep_graph(tcx); 211 | rustc_incremental::finalize_session_directory(tcx.sess, tcx.crate_hash(LOCAL_CRATE)); 212 | 213 | let metadata_module = if need_metadata_module { 214 | let _timer = tcx.prof.generic_activity("codegen crate metadata"); 215 | let (metadata_cgu_name, tmp_file) = rustc::util::common::time(tcx.sess, "write compressed metadata", || { 216 | use rustc::mir::mono::CodegenUnitNameBuilder; 217 | 218 | let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); 219 | let metadata_cgu_name = cgu_name_builder 220 | .build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata")) 221 | .as_str() 222 | .to_string(); 223 | 224 | let mut metadata_artifact = faerie::Artifact::new( 225 | crate::build_isa(tcx.sess, true).triple().clone(), 226 | metadata_cgu_name.clone(), 227 | ); 228 | crate::metadata::write_metadata(tcx, &mut metadata_artifact); 229 | 230 | let tmp_file = tcx 231 | .output_filenames(LOCAL_CRATE) 232 | .temp_path(OutputType::Metadata, Some(&metadata_cgu_name)); 233 | 234 | let obj = metadata_artifact.emit().unwrap(); 235 | std::fs::write(&tmp_file, obj).unwrap(); 236 | 237 | (metadata_cgu_name, tmp_file) 238 | }); 239 | 240 | Some(CompiledModule { 241 | name: metadata_cgu_name, 242 | kind: ModuleKind::Metadata, 243 | object: Some(tmp_file), 244 | bytecode: None, 245 | bytecode_compressed: None, 246 | }) 247 | } else { 248 | None 249 | }; 250 | 251 | Box::new(CodegenResults { 252 | crate_name: tcx.crate_name(LOCAL_CRATE), 253 | modules: vec![emit_module( 254 | ModuleKind::Regular, 255 | faerie_module, 256 | debug, 257 | )], 258 | allocator_module: if created_alloc_shim { 259 | Some(emit_module( 260 | ModuleKind::Allocator, 261 | allocator_module, 262 | None, 263 | )) 264 | } else { 265 | None 266 | }, 267 | metadata_module, 268 | crate_hash: tcx.crate_hash(LOCAL_CRATE), 269 | metadata, 270 | windows_subsystem: None, // Windows is not yet supported 271 | linker_info: LinkerInfo::new(tcx), 272 | crate_info: CrateInfo::new(tcx), 273 | }) 274 | } 275 | 276 | fn codegen_cgus<'tcx>( 277 | tcx: TyCtxt<'tcx>, 278 | module: &mut Module, 279 | debug: &mut Option>, 280 | ) { 281 | let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); 282 | let mono_items = cgus 283 | .iter() 284 | .map(|cgu| cgu.items_in_deterministic_order(tcx).into_iter()) 285 | .flatten() 286 | .collect::>(); 287 | 288 | codegen_mono_items(tcx, module, debug.as_mut(), mono_items); 289 | 290 | crate::main_shim::maybe_create_entry_wrapper(tcx, module); 291 | } 292 | 293 | fn codegen_mono_items<'tcx>( 294 | tcx: TyCtxt<'tcx>, 295 | module: &mut Module, 296 | debug_context: Option<&mut DebugContext<'tcx>>, 297 | mono_items: FxHashMap, (RLinkage, Visibility)>, 298 | ) { 299 | let mut cx = CodegenCx::new(tcx, module, debug_context); 300 | 301 | time("codegen mono items", move || { 302 | for (&mono_item, &(linkage, visibility)) in &mono_items { 303 | match mono_item { 304 | MonoItem::Fn(instance) => { 305 | let (name, sig) = get_function_name_and_sig(tcx, instance, false); 306 | let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility); 307 | cx.module.declare_function(&name, linkage, &sig).unwrap(); 308 | } 309 | MonoItem::Static(_) | MonoItem::GlobalAsm(_) => {} 310 | } 311 | } 312 | 313 | for (mono_item, (linkage, visibility)) in mono_items { 314 | crate::unimpl::try_unimpl(tcx, mono_item.to_string(tcx, true), || { 315 | let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility); 316 | trans_mono_item(&mut cx, mono_item, linkage); 317 | }); 318 | } 319 | 320 | cx.finalize(); 321 | }); 322 | } 323 | 324 | fn trans_mono_item<'clif, 'tcx, B: Backend + 'static>( 325 | cx: &mut crate::CodegenCx<'clif, 'tcx, B>, 326 | mono_item: MonoItem<'tcx>, 327 | linkage: Linkage, 328 | ) { 329 | let tcx = cx.tcx; 330 | match mono_item { 331 | MonoItem::Fn(inst) => { 332 | let _inst_guard = 333 | PrintOnPanic(|| format!("{:?} {}", inst, tcx.symbol_name(inst).name.as_str())); 334 | debug_assert!(!inst.substs.needs_infer()); 335 | let _mir_guard = PrintOnPanic(|| { 336 | match inst.def { 337 | InstanceDef::Item(_) 338 | | InstanceDef::DropGlue(_, _) 339 | | InstanceDef::Virtual(_, _) => { 340 | let mut mir = ::std::io::Cursor::new(Vec::new()); 341 | crate::rustc_mir::util::write_mir_pretty( 342 | tcx, 343 | Some(inst.def_id()), 344 | &mut mir, 345 | ) 346 | .unwrap(); 347 | String::from_utf8(mir.into_inner()).unwrap() 348 | } 349 | _ => { 350 | // FIXME fix write_mir_pretty for these instances 351 | format!("{:#?}", tcx.instance_mir(inst.def)) 352 | } 353 | } 354 | }); 355 | 356 | crate::base::trans_fn(cx, inst, linkage); 357 | } 358 | MonoItem::Static(def_id) => { 359 | crate::constant::codegen_static(&mut cx.constants_cx, def_id); 360 | } 361 | MonoItem::GlobalAsm(node_id) => tcx 362 | .sess 363 | .fatal(&format!("Unimplemented global asm mono item {:?}", node_id)), 364 | } 365 | } 366 | 367 | fn time(name: &str, f: impl FnOnce() -> R) -> R { 368 | println!("[{}] start", name); 369 | let before = std::time::Instant::now(); 370 | let res = f(); 371 | let after = std::time::Instant::now(); 372 | println!("[{}] end time: {:?}", name, after - before); 373 | res 374 | } 375 | --------------------------------------------------------------------------------