1 #![feature(rustc_private, never_type, decl_macro)]
2 #![allow(intra_doc_link_resolution_failure)]
6 extern crate rustc_allocator;
7 extern crate rustc_codegen_ssa;
8 extern crate rustc_codegen_utils;
9 extern crate rustc_data_structures;
10 extern crate rustc_fs_util;
11 extern crate rustc_incremental;
12 extern crate rustc_mir;
13 extern crate rustc_target;
17 use std::ffi::CString;
19 use std::os::raw::{c_char, c_int};
22 use rustc::dep_graph::DepGraph;
23 use rustc::middle::cstore::MetadataLoader;
24 use rustc::mir::mono::{Linkage as RLinkage, Visibility};
26 config::{DebugInfo, OutputFilenames, OutputType},
29 use rustc::ty::query::Providers;
30 use rustc_codegen_ssa::back::linker::LinkerInfo;
31 use rustc_codegen_ssa::CrateInfo;
32 use rustc_codegen_utils::codegen_backend::CodegenBackend;
33 use rustc_codegen_utils::link::out_filename;
35 use cranelift::codegen::settings;
36 use cranelift_faerie::*;
38 use crate::constant::ConstantCx;
39 use crate::prelude::*;
61 pub use std::any::Any;
62 pub use std::collections::{HashMap, HashSet};
64 pub use syntax::ast::{FloatTy, IntTy, UintTy};
65 pub use syntax::source_map::{Pos, Span, DUMMY_SP};
68 pub use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
69 pub use rustc::mir::{self, interpret::AllocId, *};
70 pub use rustc::session::{
71 config::{CrateType, Lto},
74 pub use rustc::ty::layout::{self, Abi, LayoutOf, Scalar, Size, TyLayout, VariantIdx};
76 self, subst::Substs, FnSig, Instance, InstanceDef, ParamEnv, PolyFnSig, Ty, TyCtxt,
77 TypeAndMut, TypeFoldable,
79 pub use rustc_data_structures::{
80 fx::{FxHashMap, FxHashSet},
84 pub use rustc_mir::monomorphize::{collector, MonoItem};
86 pub use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
87 pub use rustc_codegen_ssa::traits::*;
88 pub use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleKind};
90 pub use cranelift::codegen::ir::{
91 condcodes::IntCC, function::Function, ExternalName, FuncRef, Inst, SourceLoc, StackSlot,
93 pub use cranelift::codegen::isa::CallConv;
94 pub use cranelift::codegen::Context;
95 pub use cranelift::prelude::*;
96 pub use cranelift_module::{
97 self, Backend, DataContext, DataId, FuncId, FuncOrDataId, Linkage, Module,
99 pub use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder};
101 pub use crate::abi::*;
102 pub use crate::base::{trans_operand, trans_place};
103 pub use crate::common::*;
104 pub use crate::debuginfo::{DebugContext, FunctionDebugContext};
105 pub use crate::trap::*;
106 pub use crate::unimpl::{unimpl, with_unimpl_span};
107 pub use crate::{Caches, CodegenCx};
110 pub struct Caches<'tcx> {
111 pub context: Context,
112 pub vtables: HashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
115 impl<'tcx> Default for Caches<'tcx> {
116 fn default() -> Self {
118 context: Context::new(),
119 vtables: HashMap::new(),
124 pub struct CodegenCx<'a, 'clif, 'tcx, B: Backend + 'static> {
125 tcx: TyCtxt<'a, 'tcx, 'tcx>,
126 module: &'clif mut Module<B>,
128 caches: Caches<'tcx>,
129 debug_context: Option<&'clif mut DebugContext<'tcx>>,
132 impl<'a, 'clif, 'tcx, B: Backend + 'static> CodegenCx<'a, 'clif, 'tcx, B> {
134 tcx: TyCtxt<'a, 'tcx, 'tcx>,
135 module: &'clif mut Module<B>,
136 debug_context: Option<&'clif mut DebugContext<'tcx>>,
141 ccx: ConstantCx::default(),
142 caches: Caches::default(),
148 self.ccx.finalize(self.tcx, self.module);
152 struct CraneliftCodegenBackend;
154 impl CodegenBackend for CraneliftCodegenBackend {
155 fn init(&self, sess: &Session) {
156 for cty in sess.opts.crate_types.iter() {
158 CrateType::Rlib | CrateType::Dylib | CrateType::Executable => {}
161 "Rustc codegen cranelift doesn't support output type {}",
168 Lto::Fat | Lto::Thin | Lto::ThinLocal => {
169 sess.warn("Rustc codegen cranelift doesn't support lto");
173 if sess.opts.cg.rpath {
174 sess.err("rpath is not yet supported");
176 if sess.opts.debugging_opts.pgo_gen.is_some() {
177 sess.err("pgo is not supported");
181 fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
182 Box::new(crate::metadata::CraneliftMetadataLoader)
185 fn provide(&self, providers: &mut Providers) {
186 rustc_codegen_utils::symbol_names::provide(providers);
187 rustc_codegen_ssa::back::symbol_export::provide(providers);
189 providers.target_features_whitelist = |_tcx, _cnum| Lrc::new(Default::default());
191 fn provide_extern(&self, providers: &mut Providers) {
192 rustc_codegen_ssa::back::symbol_export::provide_extern(providers);
195 fn codegen_crate<'a, 'tcx>(
197 tcx: TyCtxt<'a, 'tcx, 'tcx>,
198 _rx: mpsc::Receiver<Box<dyn Any + Send>>,
201 if !tcx.sess.crate_types.get().contains(&CrateType::Executable)
202 && std::env::var("SHOULD_RUN").is_ok()
205 .err("Can't JIT run non executable (SHOULD_RUN env var is set)");
208 tcx.sess.abort_if_errors();
210 let metadata = tcx.encode_metadata();
212 // TODO: move to the end of this function when compiling libcore doesn't have unimplemented stuff anymore
213 save_incremental(tcx);
214 tcx.sess.warn("Saved incremental data");
216 let mut log = if cfg!(debug_assertions) {
217 Some(File::create(concat!(env!("CARGO_MANIFEST_DIR"), "/target/out/log.txt")).unwrap())
222 if std::env::var("SHOULD_RUN").is_ok() {
223 let mut jit_module: Module<SimpleJITBackend> = Module::new(SimpleJITBuilder::new());
224 assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type());
226 let sig = Signature {
228 AbiParam::new(jit_module.target_config().pointer_type()),
229 AbiParam::new(jit_module.target_config().pointer_type()),
231 returns: vec![AbiParam::new(
232 jit_module.target_config().pointer_type(), /*isize*/
234 call_conv: CallConv::SystemV,
236 let main_func_id = jit_module
237 .declare_function("main", Linkage::Import, &sig)
240 codegen_cgus(tcx, &mut jit_module, &mut None, &mut log);
241 crate::allocator::codegen(tcx.sess, &mut jit_module);
242 jit_module.finalize_definitions();
244 tcx.sess.abort_if_errors();
246 let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id);
248 println!("Rustc codegen cranelift will JIT run the executable, because the SHOULD_RUN env var is set");
250 let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
251 unsafe { ::std::mem::transmute(finalized_main) };
253 let args = ::std::env::var("JIT_ARGS").unwrap_or_else(|_| String::new());
256 .chain(Some(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string()))
257 .map(|arg| CString::new(arg).unwrap())
258 .collect::<Vec<_>>();
259 let argv = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<_>>();
260 // TODO: Rust doesn't care, but POSIX argv has a NULL sentinel at the end
262 let ret = f(args.len() as c_int, argv.as_ptr());
265 std::process::exit(ret);
267 let new_module = |name: String| {
268 let module: Module<FaerieBackend> = Module::new(
272 FaerieTrapCollection::Disabled,
273 FaerieBuilder::default_libcall_names(),
277 assert_eq!(pointer_ty(tcx), module.target_config().pointer_type());
281 let emit_module = |name: &str,
283 mut module: Module<FaerieBackend>,
284 debug: Option<DebugContext>| {
285 module.finalize_definitions();
286 let mut artifact = module.finish().artifact;
288 if let Some(mut debug) = debug {
289 debug.emit(&mut artifact);
293 .output_filenames(LOCAL_CRATE)
294 .temp_path(OutputType::Object, Some(name));
295 let obj = artifact.emit().unwrap();
296 std::fs::write(&tmp_file, obj).unwrap();
298 name: name.to_string(),
300 object: Some(tmp_file),
302 bytecode_compressed: None,
306 let mut faerie_module = new_module("some_file".to_string());
308 let mut debug = if tcx.sess.opts.debuginfo != DebugInfo::None
309 // macOS debuginfo doesn't work yet (see #303)
310 && !tcx.sess.target.target.options.is_like_osx
312 let debug = DebugContext::new(
314 faerie_module.target_config().pointer_type().bytes() as u8,
321 codegen_cgus(tcx, &mut faerie_module, &mut debug, &mut log);
323 tcx.sess.abort_if_errors();
325 let mut allocator_module = new_module("allocator_shim.o".to_string());
326 let created_alloc_shim = crate::allocator::codegen(tcx.sess, &mut allocator_module);
328 return Box::new(CodegenResults {
329 crate_name: tcx.crate_name(LOCAL_CRATE),
330 modules: vec![emit_module(
336 allocator_module: if created_alloc_shim {
339 ModuleKind::Allocator,
346 metadata_module: CompiledModule {
347 name: "dummy_metadata".to_string(),
348 kind: ModuleKind::Metadata,
351 bytecode_compressed: None,
353 crate_hash: tcx.crate_hash(LOCAL_CRATE),
355 windows_subsystem: None, // Windows is not yet supported
356 linker_info: LinkerInfo::new(tcx),
357 crate_info: CrateInfo::new(tcx),
362 fn join_codegen_and_link(
366 _dep_graph: &DepGraph,
367 outputs: &OutputFilenames,
368 ) -> Result<(), CompileIncomplete> {
370 .downcast::<CodegenResults>()
371 .expect("Expected CraneliftCodegenBackend's CodegenResult, found Box<Any>");
373 for &crate_type in sess.opts.crate_types.iter() {
374 let output_name = out_filename(sess, crate_type, &outputs, &res.crate_name.as_str());
376 CrateType::Rlib => link::link_rlib(sess, &res, output_name),
377 CrateType::Dylib | CrateType::Executable => {
378 link::link_natively(sess, crate_type, &res, &output_name);
380 _ => sess.fatal(&format!("Unsupported crate type: {:?}", crate_type)),
387 fn build_isa(sess: &Session) -> Box<isa::TargetIsa + 'static> {
388 use rustc::session::config::OptLevel;
390 let mut flags_builder = settings::builder();
391 flags_builder.enable("is_pic").unwrap();
392 flags_builder.set("probestack_enabled", "false").unwrap(); // ___cranelift_probestack is not provided
393 flags_builder.set("enable_verifier", if cfg!(debug_assertions) {
399 // FIXME enable again when https://github.com/CraneStation/cranelift/issues/664 is fixed
400 /*match sess.opts.optimize {
402 flags_builder.set("opt_level", "fastest").unwrap();
404 OptLevel::Less | OptLevel::Default => {}
405 OptLevel::Aggressive => {
406 flags_builder.set("opt_level", "best").unwrap();
408 OptLevel::Size | OptLevel::SizeMin => {
409 sess.warn("Optimizing for size is not supported. Just ignoring the request");
413 let flags = settings::Flags::new(flags_builder);
414 cranelift::codegen::isa::lookup(sess.target.target.llvm_target.parse().unwrap())
419 fn codegen_cgus<'a, 'tcx: 'a>(
420 tcx: TyCtxt<'a, 'tcx, 'tcx>,
421 module: &mut Module<impl Backend + 'static>,
422 debug: &mut Option<DebugContext<'tcx>>,
423 log: &mut Option<File>,
425 let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
426 let mono_items = cgus
428 .map(|cgu| cgu.items().iter())
430 .map(|(&mono_item, &(linkage, vis))| (mono_item, (linkage, vis)))
431 .collect::<FxHashMap<_, (_, _)>>();
433 codegen_mono_items(tcx, module, debug.as_mut(), log, mono_items);
435 crate::main_shim::maybe_create_entry_wrapper(tcx, module);
438 fn codegen_mono_items<'a, 'tcx: 'a>(
439 tcx: TyCtxt<'a, 'tcx, 'tcx>,
440 module: &mut Module<impl Backend + 'static>,
441 debug_context: Option<&mut DebugContext<'tcx>>,
442 log: &mut Option<File>,
443 mono_items: FxHashMap<MonoItem<'tcx>, (RLinkage, Visibility)>,
445 let mut cx = CodegenCx::new(tcx, module, debug_context);
446 time("codegen mono items", move || {
447 for (mono_item, (linkage, vis)) in mono_items {
448 unimpl::try_unimpl(tcx, log, || {
449 let linkage = match (linkage, vis) {
450 (RLinkage::External, Visibility::Default) => Linkage::Export,
451 (RLinkage::Internal, Visibility::Default) => Linkage::Local,
452 // FIXME this should get external linkage, but hidden visibility,
453 // not internal linkage and default visibility
454 (RLinkage::External, Visibility::Hidden) => Linkage::Export,
455 _ => panic!("{:?} = {:?} {:?}", mono_item, linkage, vis),
457 base::trans_mono_item(&mut cx, mono_item, linkage);
465 fn time<R>(name: &str, f: impl FnOnce() -> R) -> R {
466 println!("[{}] start", name);
467 let before = ::std::time::Instant::now();
469 let after = ::std::time::Instant::now();
470 println!("[{}] end time: {:?}", name, after - before);
474 fn save_incremental<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
475 rustc_incremental::assert_dep_graph(tcx);
476 rustc_incremental::save_dep_graph(tcx);
477 rustc_incremental::finalize_session_directory(tcx.sess, tcx.crate_hash(LOCAL_CRATE));
480 /// This is the entrypoint for a hot plugged rustc_codegen_cranelift
482 pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
483 Box::new(CraneliftCodegenBackend)