]> git.lizzy.rs Git - rust.git/blob - src/lib.rs
Make codegen_call_inner a bit more readable
[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::fs::File;
18 use std::sync::mpsc;
19
20 use rustc::dep_graph::DepGraph;
21 use rustc::middle::cstore::MetadataLoader;
22 use rustc::session::{
23     config::{DebugInfo, OutputFilenames, OutputType},
24     CompileIncomplete,
25 };
26 use rustc::ty::query::Providers;
27 use rustc::mir::mono::{Linkage as RLinkage, Visibility};
28 use rustc_codegen_ssa::back::linker::LinkerInfo;
29 use rustc_codegen_ssa::CrateInfo;
30 use rustc_codegen_utils::codegen_backend::CodegenBackend;
31 use rustc_codegen_utils::link::out_filename;
32
33 use cranelift::codegen::settings;
34 use cranelift_faerie::*;
35
36 use crate::constant::ConstantCx;
37 use crate::prelude::*;
38
39 mod abi;
40 mod allocator;
41 mod analyze;
42 mod archive;
43 mod base;
44 mod common;
45 mod constant;
46 mod debuginfo;
47 mod intrinsics;
48 mod link;
49 mod link_copied;
50 mod main_shim;
51 mod metadata;
52 mod pretty_clif;
53 mod trap;
54 mod unimpl;
55 mod unsize;
56 mod vtable;
57
58 mod prelude {
59     pub use std::any::Any;
60     pub use std::collections::{HashMap, HashSet};
61
62     pub use syntax::ast::{FloatTy, IntTy, UintTy};
63     pub use syntax::source_map::{DUMMY_SP, Span, Pos};
64
65     pub use rustc::bug;
66     pub use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
67     pub use rustc::mir::{self, interpret::AllocId, *};
68     pub use rustc::session::{
69         config::{CrateType, Lto},
70         Session,
71     };
72     pub use rustc::ty::layout::{self, Abi, LayoutOf, Scalar, Size, TyLayout, VariantIdx};
73     pub use rustc::ty::{
74         self, subst::Substs, FnSig, Instance, InstanceDef, ParamEnv, PolyFnSig, Ty, TyCtxt,
75         TypeAndMut, TypeFoldable,
76     };
77     pub use rustc_data_structures::{
78         fx::{FxHashMap, FxHashSet},
79         indexed_vec::Idx,
80         sync::Lrc,
81     };
82     pub use rustc_mir::monomorphize::{collector, MonoItem};
83
84     pub use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
85     pub use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleKind};
86     pub use rustc_codegen_ssa::traits::*;
87
88     pub use cranelift::codegen::ir::{
89         condcodes::IntCC, function::Function, ExternalName, FuncRef, Inst, StackSlot, SourceLoc,
90     };
91     pub use cranelift::codegen::isa::CallConv;
92     pub use cranelift::codegen::Context;
93     pub use cranelift::prelude::*;
94     pub use cranelift_module::{
95         self, Backend, DataContext, DataId, FuncId, FuncOrDataId, Linkage,
96         Module,
97     };
98     pub use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder};
99
100     pub use crate::abi::*;
101     pub use crate::base::{trans_operand, trans_place};
102     pub use crate::common::*;
103     pub use crate::debuginfo::{DebugContext, FunctionDebugContext};
104     pub use crate::trap::*;
105     pub use crate::unimpl::{unimpl, with_unimpl_span};
106     pub use crate::{Caches, CodegenCx};
107 }
108
109 pub struct Caches<'tcx> {
110     pub context: Context,
111     pub vtables: HashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
112 }
113
114 impl<'tcx> Default for Caches<'tcx> {
115     fn default() -> Self {
116         Caches {
117             context: Context::new(),
118             vtables: HashMap::new(),
119         }
120     }
121 }
122
123 pub struct CodegenCx<'a, 'clif, 'tcx, B: Backend + 'static> {
124     tcx: TyCtxt<'a, 'tcx, 'tcx>,
125     module: &'clif mut Module<B>,
126     ccx: ConstantCx,
127     caches: Caches<'tcx>,
128     debug_context: Option<&'clif mut DebugContext<'tcx>>,
129 }
130
131 impl<'a, 'clif, 'tcx, B: Backend + 'static> CodegenCx<'a, 'clif, 'tcx, B> {
132     fn new(
133         tcx: TyCtxt<'a, 'tcx, 'tcx>,
134         module: &'clif mut Module<B>,
135         debug_context: Option<&'clif mut DebugContext<'tcx>>,
136     ) -> Self {
137         CodegenCx {
138             tcx,
139             module,
140             ccx: ConstantCx::default(),
141             caches: Caches::default(),
142             debug_context,
143         }
144     }
145
146     fn finalize(self) {
147         self.ccx.finalize(self.tcx, self.module);
148     }
149 }
150
151 struct CraneliftCodegenBackend;
152
153 impl CodegenBackend for CraneliftCodegenBackend {
154     fn init(&self, sess: &Session) {
155         for cty in sess.opts.crate_types.iter() {
156             match *cty {
157                 CrateType::Rlib | CrateType::Dylib | CrateType::Executable => {}
158                 _ => {
159                     sess.err(&format!(
160                         "Rustc codegen cranelift doesn't support output type {}",
161                         cty
162                     ));
163                 }
164             }
165         }
166         match sess.lto() {
167             Lto::Fat | Lto::Thin | Lto::ThinLocal => {
168                 sess.warn("Rustc codegen cranelift doesn't support lto");
169             }
170             Lto::No => {}
171         }
172         if sess.opts.cg.rpath {
173             sess.err("rpath is not yet supported");
174         }
175         if sess.opts.debugging_opts.pgo_gen.is_some() {
176             sess.err("pgo is not supported");
177         }
178     }
179
180     fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
181         Box::new(crate::metadata::CraneliftMetadataLoader)
182     }
183
184     fn provide(&self, providers: &mut Providers) {
185         rustc_codegen_utils::symbol_names::provide(providers);
186         rustc_codegen_ssa::back::symbol_export::provide(providers);
187
188         providers.target_features_whitelist = |_tcx, _cnum| Lrc::new(Default::default());
189     }
190     fn provide_extern(&self, providers: &mut Providers) {
191         rustc_codegen_ssa::back::symbol_export::provide_extern(providers);
192     }
193
194     fn codegen_crate<'a, 'tcx>(
195         &self,
196         tcx: TyCtxt<'a, 'tcx, 'tcx>,
197         _rx: mpsc::Receiver<Box<dyn Any + Send>>,
198     ) -> Box<dyn Any> {
199         env_logger::init();
200         if !tcx.sess.crate_types.get().contains(&CrateType::Executable)
201             && std::env::var("SHOULD_RUN").is_ok()
202         {
203             tcx.sess
204                 .err("Can't JIT run non executable (SHOULD_RUN env var is set)");
205         }
206
207         tcx.sess.abort_if_errors();
208
209         let metadata = tcx.encode_metadata();
210
211         // TODO: move to the end of this function when compiling libcore doesn't have unimplemented stuff anymore
212         save_incremental(tcx);
213         tcx.sess.warn("Saved incremental data");
214
215         let mut log = if cfg!(debug_assertions) {
216             Some(File::create(concat!(env!("CARGO_MANIFEST_DIR"), "/target/out/log.txt")).unwrap())
217         } else {
218             None
219         };
220
221         if std::env::var("SHOULD_RUN").is_ok() {
222             let mut jit_module: Module<SimpleJITBackend> = Module::new(SimpleJITBuilder::new());
223             assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type());
224
225             let sig = Signature {
226                 params: vec![
227                     AbiParam::new(jit_module.target_config().pointer_type()),
228                     AbiParam::new(jit_module.target_config().pointer_type()),
229                 ],
230                 returns: vec![AbiParam::new(
231                     jit_module.target_config().pointer_type(), /*isize*/
232                 )],
233                 call_conv: CallConv::SystemV,
234             };
235             let main_func_id = jit_module
236                 .declare_function("main", Linkage::Import, &sig)
237                 .unwrap();
238
239             codegen_cgus(tcx, &mut jit_module, &mut None, &mut log);
240             crate::allocator::codegen(tcx.sess, &mut jit_module);
241             jit_module.finalize_definitions();
242
243             tcx.sess.abort_if_errors();
244             println!("Compiled everything");
245             println!("Rustc codegen cranelift will JIT run the executable, because the SHOULD_RUN env var is set");
246
247             let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id);
248             println!("🎉 Finalized everything");
249
250             let f: extern "C" fn(isize, *const *const u8) -> isize =
251                 unsafe { ::std::mem::transmute(finalized_main) };
252             let res = f(0, 0 as *const _);
253             tcx.sess.warn(&format!("🚀 main returned {}", res));
254
255             jit_module.finish();
256             ::std::process::exit(0);
257         } else {
258             let new_module = |name: String| {
259                 let module: Module<FaerieBackend> = Module::new(
260                     FaerieBuilder::new(
261                         build_isa(tcx.sess),
262                         name + ".o",
263                         FaerieTrapCollection::Disabled,
264                         FaerieBuilder::default_libcall_names(),
265                     )
266                     .unwrap(),
267                 );
268                 assert_eq!(
269                     pointer_ty(tcx),
270                     module.target_config().pointer_type()
271                 );
272                 module
273             };
274
275             let emit_module = |name: &str, kind: ModuleKind, mut module: Module<FaerieBackend>, debug: Option<DebugContext>| {
276                 module.finalize_definitions();
277                 let mut artifact = module.finish().artifact;
278
279                 if let Some(mut debug) = debug {
280                     debug.emit(&mut artifact);
281                 }
282
283                 let tmp_file = tcx
284                     .output_filenames(LOCAL_CRATE)
285                     .temp_path(OutputType::Object, Some(name));
286                 let obj = artifact.emit().unwrap();
287                 std::fs::write(&tmp_file, obj).unwrap();
288                 CompiledModule {
289                     name: name.to_string(),
290                     kind,
291                     object: Some(tmp_file),
292                     bytecode: None,
293                     bytecode_compressed: None,
294                 }
295             };
296
297             let mut faerie_module = new_module("some_file".to_string());
298
299             let mut debug = if tcx.sess.opts.debuginfo != DebugInfo::None {
300                 let debug = DebugContext::new(tcx, faerie_module.target_config().pointer_type().bytes() as u8);
301                 Some(debug)
302             } else {
303                 None
304             };
305
306             codegen_cgus(tcx, &mut faerie_module, &mut debug, &mut log);
307
308             tcx.sess.abort_if_errors();
309
310             let mut allocator_module = new_module("allocator_shim.o".to_string());
311             let created_alloc_shim =
312                 crate::allocator::codegen(tcx.sess, &mut allocator_module);
313
314             return Box::new(CodegenResults {
315                 crate_name: tcx.crate_name(LOCAL_CRATE),
316                 modules: vec![emit_module("dummy_name", ModuleKind::Regular, faerie_module, debug)],
317                 allocator_module: if created_alloc_shim {
318                     Some(emit_module("allocator_shim", ModuleKind::Allocator, allocator_module, None))
319                 } else {
320                     None
321                 },
322                 metadata_module: CompiledModule {
323                     name: "dummy_metadata".to_string(),
324                     kind: ModuleKind::Metadata,
325                     object: None,
326                     bytecode: None,
327                     bytecode_compressed: None,
328                 },
329                 crate_hash: tcx.crate_hash(LOCAL_CRATE),
330                 metadata,
331                 windows_subsystem: None, // Windows is not yet supported
332                 linker_info: LinkerInfo::new(tcx),
333                 crate_info: CrateInfo::new(tcx),
334             });
335         }
336     }
337
338     fn join_codegen_and_link(
339         &self,
340         res: Box<dyn Any>,
341         sess: &Session,
342         _dep_graph: &DepGraph,
343         outputs: &OutputFilenames,
344     ) -> Result<(), CompileIncomplete> {
345         let res = *res
346             .downcast::<CodegenResults>()
347             .expect("Expected CraneliftCodegenBackend's CodegenResult, found Box<Any>");
348
349         for &crate_type in sess.opts.crate_types.iter() {
350             let output_name = out_filename(sess, crate_type, &outputs, &res.crate_name.as_str());
351             match crate_type {
352                 CrateType::Rlib => link::link_rlib(sess, &res, output_name),
353                 CrateType::Dylib | CrateType::Executable => {
354                     link::link_natively(sess, crate_type, &res, &output_name);
355                 }
356                 _ => sess.fatal(&format!("Unsupported crate type: {:?}", crate_type)),
357             }
358         }
359         Ok(())
360     }
361 }
362
363 fn build_isa(sess: &Session) -> Box<isa::TargetIsa + 'static> {
364     use rustc::session::config::OptLevel;
365
366     let mut flags_builder = settings::builder();
367     flags_builder.enable("is_pic").unwrap();
368     flags_builder.set("probestack_enabled", "false").unwrap(); // ___cranelift_probestack is not provided
369     flags_builder.set("enable_verifier", if cfg!(debug_assertions) {
370         "true"
371     } else {
372         "false"
373     }).unwrap();
374
375     match sess.opts.optimize {
376         OptLevel::No => {
377             flags_builder.set("opt_level", "fastest").unwrap();
378         }
379         OptLevel::Less | OptLevel::Default => {}
380         OptLevel::Aggressive => {
381             flags_builder.set("opt_level", "best").unwrap();
382         }
383         OptLevel::Size | OptLevel::SizeMin => {
384             sess.warn("Optimizing for size is not supported. Just ignoring the request");
385         }
386     }
387
388     let flags = settings::Flags::new(flags_builder);
389     cranelift::codegen::isa::lookup(sess.target.target.llvm_target.parse().unwrap())
390         .unwrap()
391         .finish(flags)
392 }
393
394 fn codegen_cgus<'a, 'tcx: 'a>(
395     tcx: TyCtxt<'a, 'tcx, 'tcx>,
396     module: &mut Module<impl Backend + 'static>,
397     debug: &mut Option<DebugContext<'tcx>>,
398     log: &mut Option<File>,
399 ) {
400     let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
401     let mono_items = cgus
402         .iter()
403         .map(|cgu| cgu.items().iter())
404         .flatten()
405         .map(|(&mono_item, &(linkage, vis))| (mono_item, (linkage, vis)))
406         .collect::<FxHashMap<_, (_, _)>>();
407
408     codegen_mono_items(tcx, module, debug.as_mut(), log, mono_items);
409
410     crate::main_shim::maybe_create_entry_wrapper(tcx, module);
411 }
412
413 fn codegen_mono_items<'a, 'tcx: 'a>(
414     tcx: TyCtxt<'a, 'tcx, 'tcx>,
415     module: &mut Module<impl Backend + 'static>,
416     debug_context: Option<&mut DebugContext<'tcx>>,
417     log: &mut Option<File>,
418     mono_items: FxHashMap<MonoItem<'tcx>, (RLinkage, Visibility)>,
419 ) {
420     let mut cx = CodegenCx::new(tcx, module, debug_context);
421     time("codegen mono items", move || {
422         for (mono_item, (linkage, vis)) in mono_items {
423             unimpl::try_unimpl(tcx, log, || {
424                 let linkage = match (linkage, vis) {
425                     (RLinkage::External, Visibility::Default) => Linkage::Export,
426                     (RLinkage::Internal, Visibility::Default) => Linkage::Local,
427                     // FIXME this should get external linkage, but hidden visibility,
428                     // not internal linkage and default visibility
429                     | (RLinkage::External, Visibility::Hidden) => Linkage::Local,
430                     _ => panic!("{:?} = {:?} {:?}", mono_item, linkage, vis),
431                 };
432                 base::trans_mono_item(&mut cx, mono_item, linkage);
433             });
434         }
435
436         cx.finalize();
437     });
438 }
439
440 fn time<R>(name: &str, f: impl FnOnce() -> R) -> R {
441     println!("[{}] start", name);
442     let before = ::std::time::Instant::now();
443     let res = f();
444     let after = ::std::time::Instant::now();
445     println!("[{}] end time: {:?}", name, after - before);
446     res
447 }
448
449 fn save_incremental<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
450     rustc_incremental::assert_dep_graph(tcx);
451     rustc_incremental::save_dep_graph(tcx);
452     rustc_incremental::finalize_session_directory(tcx.sess, tcx.crate_hash(LOCAL_CRATE));
453 }
454
455 /// This is the entrypoint for a hot plugged rustc_codegen_cranelift
456 #[no_mangle]
457 pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
458     Box::new(CraneliftCodegenBackend)
459 }