#![feature( rustc_private, decl_macro, type_alias_impl_trait, associated_type_bounds, never_type, try_blocks, hash_drain_filter, str_split_once )] #![warn(rust_2018_idioms)] #![warn(unused_lifetimes)] #![warn(unreachable_pub)] #[cfg(feature = "jit")] extern crate libc; extern crate snap; #[macro_use] extern crate rustc_middle; extern crate rustc_ast; extern crate rustc_codegen_ssa; extern crate rustc_data_structures; extern crate rustc_errors; extern crate rustc_fs_util; extern crate rustc_hir; extern crate rustc_incremental; extern crate rustc_index; extern crate rustc_session; extern crate rustc_span; extern crate rustc_symbol_mangling; extern crate rustc_target; // This prevents duplicating functions and statics that are already part of the host rustc process. #[allow(unused_extern_crates)] extern crate rustc_driver; use std::any::Any; use std::str::FromStr; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::CodegenResults; use rustc_errors::ErrorReported; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader}; use rustc_middle::ty::query::Providers; use rustc_session::config::OutputFilenames; use rustc_session::Session; use cranelift_codegen::settings::{self, Configurable}; use crate::constant::ConstantCx; use crate::prelude::*; mod abi; mod allocator; mod analyze; mod archive; mod atomic_shim; mod backend; mod base; mod cast; mod codegen_i128; mod common; mod constant; mod debuginfo; mod discriminant; mod driver; mod inline_asm; mod intrinsics; mod linkage; mod main_shim; mod metadata; mod num; mod optimize; mod pointer; mod pretty_clif; mod toolchain; mod trap; mod unsize; mod value_and_place; mod vtable; mod prelude { pub(crate) use std::convert::{TryFrom, TryInto}; pub(crate) use rustc_ast::ast::{FloatTy, IntTy, UintTy}; pub(crate) use rustc_span::Span; pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE}; pub(crate) use rustc_middle::bug; pub(crate) use rustc_middle::mir::{self, *}; pub(crate) use rustc_middle::ty::layout::{self, TyAndLayout}; pub(crate) use rustc_middle::ty::{ self, FnSig, Instance, InstanceDef, ParamEnv, Ty, TyCtxt, TypeAndMut, TypeFoldable, }; pub(crate) use rustc_target::abi::{Abi, LayoutOf, Scalar, Size, VariantIdx}; pub(crate) use rustc_data_structures::fx::FxHashMap; pub(crate) use rustc_index::vec::Idx; pub(crate) use cranelift_codegen::entity::EntitySet; pub(crate) use cranelift_codegen::ir::condcodes::{FloatCC, IntCC}; pub(crate) use cranelift_codegen::ir::function::Function; pub(crate) use cranelift_codegen::ir::types; pub(crate) use cranelift_codegen::ir::{ AbiParam, Block, ExternalName, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc, StackSlot, StackSlotData, StackSlotKind, TrapCode, Type, Value, }; pub(crate) use cranelift_codegen::isa::{self, CallConv}; pub(crate) use cranelift_codegen::Context; pub(crate) use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; pub(crate) use cranelift_module::{self, DataContext, DataId, FuncId, Linkage, Module}; pub(crate) use crate::abi::*; pub(crate) use crate::base::{codegen_operand, codegen_place}; pub(crate) use crate::cast::*; pub(crate) use crate::common::*; pub(crate) use crate::debuginfo::{DebugContext, UnwindContext}; pub(crate) use crate::pointer::Pointer; pub(crate) use crate::trap::*; pub(crate) use crate::value_and_place::{CPlace, CPlaceInner, CValue}; } struct PrintOnPanic String>(F); impl String> Drop for PrintOnPanic { fn drop(&mut self) { if ::std::thread::panicking() { println!("{}", (self.0)()); } } } struct CodegenCx<'tcx, M: Module> { tcx: TyCtxt<'tcx>, module: M, global_asm: String, constants_cx: ConstantCx, cached_context: Context, vtables: FxHashMap<(Ty<'tcx>, Option>), DataId>, debug_context: Option>, unwind_context: UnwindContext<'tcx>, } impl<'tcx, M: Module> CodegenCx<'tcx, M> { fn new(tcx: TyCtxt<'tcx>, module: M, debug_info: bool, pic_eh_frame: bool) -> Self { let unwind_context = UnwindContext::new(tcx, module.isa(), pic_eh_frame); let debug_context = if debug_info { Some(DebugContext::new(tcx, module.isa())) } else { None }; CodegenCx { tcx, module, global_asm: String::new(), constants_cx: ConstantCx::default(), cached_context: Context::new(), vtables: FxHashMap::default(), debug_context, unwind_context, } } fn finalize(mut self) -> (M, String, Option>, UnwindContext<'tcx>) { self.constants_cx.finalize(self.tcx, &mut self.module); ( self.module, self.global_asm, self.debug_context, self.unwind_context, ) } } #[derive(Copy, Clone, Debug)] pub enum CodegenMode { Aot, Jit, JitLazy, } impl Default for CodegenMode { fn default() -> Self { CodegenMode::Aot } } impl FromStr for CodegenMode { type Err = String; fn from_str(s: &str) -> Result { match s { "aot" => Ok(CodegenMode::Aot), "jit" => Ok(CodegenMode::Jit), "jit-lazy" => Ok(CodegenMode::JitLazy), _ => Err(format!("Unknown codegen mode `{}`", s)), } } } #[derive(Copy, Clone, Debug, Default)] pub struct BackendConfig { pub codegen_mode: CodegenMode, } impl BackendConfig { fn from_opts(opts: &[String]) -> Result { let mut config = BackendConfig::default(); for opt in opts { if let Some((name, value)) = opt.split_once('=') { match name { "mode" => config.codegen_mode = value.parse()?, _ => return Err(format!("Unknown option `{}`", name)), } } else { return Err(format!("Invalid option `{}`", opt)); } } Ok(config) } } pub struct CraneliftCodegenBackend { pub config: Option, } impl CodegenBackend for CraneliftCodegenBackend { fn init(&self, sess: &Session) { if sess.lto() != rustc_session::config::Lto::No && sess.opts.cg.embed_bitcode { sess.warn("LTO is not supported. You may get a linker error."); } } fn metadata_loader(&self) -> Box { Box::new(crate::metadata::CraneliftMetadataLoader) } fn provide(&self, _providers: &mut Providers) {} fn provide_extern(&self, _providers: &mut Providers) {} fn target_features(&self, _sess: &Session) -> Vec { vec![] } fn codegen_crate<'tcx>( &self, tcx: TyCtxt<'tcx>, metadata: EncodedMetadata, need_metadata_module: bool, ) -> Box { let config = if let Some(config) = self.config { config } else { BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args) .unwrap_or_else(|err| tcx.sess.fatal(&err)) }; let res = driver::codegen_crate(tcx, metadata, need_metadata_module, config); rustc_symbol_mangling::test::report_symbol_names(tcx); res } fn join_codegen( &self, ongoing_codegen: Box, _sess: &Session, ) -> Result<(CodegenResults, FxHashMap), ErrorReported> { Ok(*ongoing_codegen .downcast::<(CodegenResults, FxHashMap)>() .unwrap()) } fn link( &self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames, ) -> Result<(), ErrorReported> { use rustc_codegen_ssa::back::link::link_binary; let _timer = sess.prof.generic_activity("link_crate"); sess.time("linking", || { let target_cpu = crate::target_triple(sess).to_string(); link_binary::>( sess, &codegen_results, outputs, &codegen_results.crate_name.as_str(), &target_cpu, ); }); Ok(()) } } fn target_triple(sess: &Session) -> target_lexicon::Triple { sess.target.llvm_target.parse().unwrap() } fn build_isa(sess: &Session) -> Box { use target_lexicon::BinaryFormat; let target_triple = crate::target_triple(sess); let mut flags_builder = settings::builder(); flags_builder.enable("is_pic").unwrap(); flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided flags_builder .set( "enable_verifier", if cfg!(debug_assertions) { "true" } else { "false" }, ) .unwrap(); let tls_model = match target_triple.binary_format { BinaryFormat::Elf => "elf_gd", BinaryFormat::Macho => "macho", BinaryFormat::Coff => "coff", _ => "none", }; flags_builder.set("tls_model", tls_model).unwrap(); flags_builder.set("enable_simd", "true").unwrap(); use rustc_session::config::OptLevel; match sess.opts.optimize { OptLevel::No => { flags_builder.set("opt_level", "none").unwrap(); } OptLevel::Less | OptLevel::Default => {} OptLevel::Aggressive => { flags_builder.set("opt_level", "speed_and_size").unwrap(); } OptLevel::Size | OptLevel::SizeMin => { sess.warn("Optimizing for size is not supported. Just ignoring the request"); } } let flags = settings::Flags::new(flags_builder); let mut isa_builder = cranelift_codegen::isa::lookup(target_triple).unwrap(); // Don't use "haswell", as it implies `has_lzcnt`.macOS CI is still at Ivy Bridge EP, so `lzcnt` // is interpreted as `bsr`. isa_builder.enable("nehalem").unwrap(); isa_builder.finish(flags) } /// This is the entrypoint for a hot plugged rustc_codegen_cranelift #[no_mangle] pub fn __rustc_codegen_backend() -> Box { Box::new(CraneliftCodegenBackend { config: None }) }