]> git.lizzy.rs Git - rust.git/blob - src/lib.rs
Bump rand_pcg from 0.1.1 to 0.1.2
[rust.git] / src / lib.rs
1 #![feature(rustc_private, never_type, decl_macro)]
2 #![allow(intra_doc_link_resolution_failure)]
3
4 extern crate log;
5 extern crate rustc;
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;
14 extern crate syntax;
15
16 use std::any::Any;
17 use std::ffi::CString;
18 use std::fs::File;
19 use std::os::raw::{c_char, c_int};
20 use std::sync::mpsc;
21
22 use rustc::dep_graph::DepGraph;
23 use rustc::middle::cstore::MetadataLoader;
24 use rustc::mir::mono::{Linkage as RLinkage, Visibility};
25 use rustc::session::{
26     config::{DebugInfo, OutputFilenames, OutputType},
27     CompileIncomplete,
28 };
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;
34
35 use cranelift::codegen::settings;
36 use cranelift_faerie::*;
37
38 use crate::constant::ConstantCx;
39 use crate::prelude::*;
40
41 mod abi;
42 mod allocator;
43 mod analyze;
44 mod archive;
45 mod base;
46 mod common;
47 mod constant;
48 mod debuginfo;
49 mod intrinsics;
50 mod link;
51 mod link_copied;
52 mod main_shim;
53 mod metadata;
54 mod pretty_clif;
55 mod trap;
56 mod unimpl;
57 mod unsize;
58 mod vtable;
59
60 mod prelude {
61     pub use std::any::Any;
62     pub use std::collections::{HashMap, HashSet};
63
64     pub use syntax::ast::{FloatTy, IntTy, UintTy};
65     pub use syntax::source_map::{Pos, Span, DUMMY_SP};
66
67     pub use rustc::bug;
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},
72         Session,
73     };
74     pub use rustc::ty::layout::{self, Abi, LayoutOf, Scalar, Size, TyLayout, VariantIdx};
75     pub use rustc::ty::{
76         self, subst::Substs, FnSig, Instance, InstanceDef, ParamEnv, PolyFnSig, Ty, TyCtxt,
77         TypeAndMut, TypeFoldable,
78     };
79     pub use rustc_data_structures::{
80         fx::{FxHashMap, FxHashSet},
81         indexed_vec::Idx,
82         sync::Lrc,
83     };
84     pub use rustc_mir::monomorphize::{collector, MonoItem};
85
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};
89
90     pub use cranelift::codegen::ir::{
91         condcodes::IntCC, function::Function, ExternalName, FuncRef, Inst, SourceLoc, StackSlot,
92     };
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,
98     };
99     pub use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder};
100
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};
108 }
109
110 pub struct Caches<'tcx> {
111     pub context: Context,
112     pub vtables: HashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
113 }
114
115 impl<'tcx> Default for Caches<'tcx> {
116     fn default() -> Self {
117         Caches {
118             context: Context::new(),
119             vtables: HashMap::new(),
120         }
121     }
122 }
123
124 pub struct CodegenCx<'a, 'clif, 'tcx, B: Backend + 'static> {
125     tcx: TyCtxt<'a, 'tcx, 'tcx>,
126     module: &'clif mut Module<B>,
127     ccx: ConstantCx,
128     caches: Caches<'tcx>,
129     debug_context: Option<&'clif mut DebugContext<'tcx>>,
130 }
131
132 impl<'a, 'clif, 'tcx, B: Backend + 'static> CodegenCx<'a, 'clif, 'tcx, B> {
133     fn new(
134         tcx: TyCtxt<'a, 'tcx, 'tcx>,
135         module: &'clif mut Module<B>,
136         debug_context: Option<&'clif mut DebugContext<'tcx>>,
137     ) -> Self {
138         CodegenCx {
139             tcx,
140             module,
141             ccx: ConstantCx::default(),
142             caches: Caches::default(),
143             debug_context,
144         }
145     }
146
147     fn finalize(self) {
148         self.ccx.finalize(self.tcx, self.module);
149     }
150 }
151
152 struct CraneliftCodegenBackend;
153
154 impl CodegenBackend for CraneliftCodegenBackend {
155     fn init(&self, sess: &Session) {
156         for cty in sess.opts.crate_types.iter() {
157             match *cty {
158                 CrateType::Rlib | CrateType::Dylib | CrateType::Executable => {}
159                 _ => {
160                     sess.err(&format!(
161                         "Rustc codegen cranelift doesn't support output type {}",
162                         cty
163                     ));
164                 }
165             }
166         }
167         match sess.lto() {
168             Lto::Fat | Lto::Thin | Lto::ThinLocal => {
169                 sess.warn("Rustc codegen cranelift doesn't support lto");
170             }
171             Lto::No => {}
172         }
173         if sess.opts.cg.rpath {
174             sess.err("rpath is not yet supported");
175         }
176         if sess.opts.debugging_opts.pgo_gen.is_some() {
177             sess.err("pgo is not supported");
178         }
179     }
180
181     fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
182         Box::new(crate::metadata::CraneliftMetadataLoader)
183     }
184
185     fn provide(&self, providers: &mut Providers) {
186         rustc_codegen_utils::symbol_names::provide(providers);
187         rustc_codegen_ssa::back::symbol_export::provide(providers);
188
189         providers.target_features_whitelist = |_tcx, _cnum| Lrc::new(Default::default());
190     }
191     fn provide_extern(&self, providers: &mut Providers) {
192         rustc_codegen_ssa::back::symbol_export::provide_extern(providers);
193     }
194
195     fn codegen_crate<'a, 'tcx>(
196         &self,
197         tcx: TyCtxt<'a, 'tcx, 'tcx>,
198         _rx: mpsc::Receiver<Box<dyn Any + Send>>,
199     ) -> Box<dyn Any> {
200         env_logger::init();
201         if !tcx.sess.crate_types.get().contains(&CrateType::Executable)
202             && std::env::var("SHOULD_RUN").is_ok()
203         {
204             tcx.sess
205                 .err("Can't JIT run non executable (SHOULD_RUN env var is set)");
206         }
207
208         tcx.sess.abort_if_errors();
209
210         let metadata = tcx.encode_metadata();
211
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");
215
216         let mut log = if cfg!(debug_assertions) {
217             Some(File::create(concat!(env!("CARGO_MANIFEST_DIR"), "/target/out/log.txt")).unwrap())
218         } else {
219             None
220         };
221
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());
225
226             let sig = Signature {
227                 params: vec![
228                     AbiParam::new(jit_module.target_config().pointer_type()),
229                     AbiParam::new(jit_module.target_config().pointer_type()),
230                 ],
231                 returns: vec![AbiParam::new(
232                     jit_module.target_config().pointer_type(), /*isize*/
233                 )],
234                 call_conv: CallConv::SystemV,
235             };
236             let main_func_id = jit_module
237                 .declare_function("main", Linkage::Import, &sig)
238                 .unwrap();
239
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();
243
244             tcx.sess.abort_if_errors();
245
246             let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id);
247
248             println!("Rustc codegen cranelift will JIT run the executable, because the SHOULD_RUN env var is set");
249
250             let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
251                 unsafe { ::std::mem::transmute(finalized_main) };
252
253             let args = ::std::env::var("JIT_ARGS").unwrap_or_else(|_| String::new());
254             let args = args
255                 .split(" ")
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
261
262             let ret = f(args.len() as c_int, argv.as_ptr());
263
264             jit_module.finish();
265             std::process::exit(ret);
266         } else {
267             let new_module = |name: String| {
268                 let module: Module<FaerieBackend> = Module::new(
269                     FaerieBuilder::new(
270                         build_isa(tcx.sess),
271                         name + ".o",
272                         FaerieTrapCollection::Disabled,
273                         FaerieBuilder::default_libcall_names(),
274                     )
275                     .unwrap(),
276                 );
277                 assert_eq!(pointer_ty(tcx), module.target_config().pointer_type());
278                 module
279             };
280
281             let emit_module = |name: &str,
282                                kind: ModuleKind,
283                                mut module: Module<FaerieBackend>,
284                                debug: Option<DebugContext>| {
285                 module.finalize_definitions();
286                 let mut artifact = module.finish().artifact;
287
288                 if let Some(mut debug) = debug {
289                     debug.emit(&mut artifact);
290                 }
291
292                 let tmp_file = tcx
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();
297                 CompiledModule {
298                     name: name.to_string(),
299                     kind,
300                     object: Some(tmp_file),
301                     bytecode: None,
302                     bytecode_compressed: None,
303                 }
304             };
305
306             let mut faerie_module = new_module("some_file".to_string());
307
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
311             {
312                 let debug = DebugContext::new(
313                     tcx,
314                     faerie_module.target_config().pointer_type().bytes() as u8,
315                 );
316                 Some(debug)
317             } else {
318                 None
319             };
320
321             codegen_cgus(tcx, &mut faerie_module, &mut debug, &mut log);
322
323             tcx.sess.abort_if_errors();
324
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);
327
328             return Box::new(CodegenResults {
329                 crate_name: tcx.crate_name(LOCAL_CRATE),
330                 modules: vec![emit_module(
331                     "dummy_name",
332                     ModuleKind::Regular,
333                     faerie_module,
334                     debug,
335                 )],
336                 allocator_module: if created_alloc_shim {
337                     Some(emit_module(
338                         "allocator_shim",
339                         ModuleKind::Allocator,
340                         allocator_module,
341                         None,
342                     ))
343                 } else {
344                     None
345                 },
346                 metadata_module: CompiledModule {
347                     name: "dummy_metadata".to_string(),
348                     kind: ModuleKind::Metadata,
349                     object: None,
350                     bytecode: None,
351                     bytecode_compressed: None,
352                 },
353                 crate_hash: tcx.crate_hash(LOCAL_CRATE),
354                 metadata,
355                 windows_subsystem: None, // Windows is not yet supported
356                 linker_info: LinkerInfo::new(tcx),
357                 crate_info: CrateInfo::new(tcx),
358             });
359         }
360     }
361
362     fn join_codegen_and_link(
363         &self,
364         res: Box<dyn Any>,
365         sess: &Session,
366         _dep_graph: &DepGraph,
367         outputs: &OutputFilenames,
368     ) -> Result<(), CompileIncomplete> {
369         let res = *res
370             .downcast::<CodegenResults>()
371             .expect("Expected CraneliftCodegenBackend's CodegenResult, found Box<Any>");
372
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());
375             match crate_type {
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);
379                 }
380                 _ => sess.fatal(&format!("Unsupported crate type: {:?}", crate_type)),
381             }
382         }
383         Ok(())
384     }
385 }
386
387 fn build_isa(sess: &Session) -> Box<isa::TargetIsa + 'static> {
388     use rustc::session::config::OptLevel;
389
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) {
394         "true"
395     } else {
396         "false"
397     }).unwrap();
398
399     // FIXME enable again when https://github.com/CraneStation/cranelift/issues/664 is fixed
400     /*match sess.opts.optimize {
401         OptLevel::No => {
402             flags_builder.set("opt_level", "fastest").unwrap();
403         }
404         OptLevel::Less | OptLevel::Default => {}
405         OptLevel::Aggressive => {
406             flags_builder.set("opt_level", "best").unwrap();
407         }
408         OptLevel::Size | OptLevel::SizeMin => {
409             sess.warn("Optimizing for size is not supported. Just ignoring the request");
410         }
411     }*/
412
413     let flags = settings::Flags::new(flags_builder);
414     cranelift::codegen::isa::lookup(sess.target.target.llvm_target.parse().unwrap())
415         .unwrap()
416         .finish(flags)
417 }
418
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>,
424 ) {
425     let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
426     let mono_items = cgus
427         .iter()
428         .map(|cgu| cgu.items().iter())
429         .flatten()
430         .map(|(&mono_item, &(linkage, vis))| (mono_item, (linkage, vis)))
431         .collect::<FxHashMap<_, (_, _)>>();
432
433     codegen_mono_items(tcx, module, debug.as_mut(), log, mono_items);
434
435     crate::main_shim::maybe_create_entry_wrapper(tcx, module);
436 }
437
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)>,
444 ) {
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),
456                 };
457                 base::trans_mono_item(&mut cx, mono_item, linkage);
458             });
459         }
460
461         cx.finalize();
462     });
463 }
464
465 fn time<R>(name: &str, f: impl FnOnce() -> R) -> R {
466     println!("[{}] start", name);
467     let before = ::std::time::Instant::now();
468     let res = f();
469     let after = ::std::time::Instant::now();
470     println!("[{}] end time: {:?}", name, after - before);
471     res
472 }
473
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));
478 }
479
480 /// This is the entrypoint for a hot plugged rustc_codegen_cranelift
481 #[no_mangle]
482 pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
483     Box::new(CraneliftCodegenBackend)
484 }