]> git.lizzy.rs Git - rust.git/blob - src/lib.rs
Pass target_cpu to LinkerInfo::new instead of link_binary
[rust.git] / src / lib.rs
1 #![feature(rustc_private, decl_macro, never_type, hash_drain_filter)]
2 #![warn(rust_2018_idioms)]
3 #![warn(unused_lifetimes)]
4 #![warn(unreachable_pub)]
5
6 extern crate snap;
7 #[macro_use]
8 extern crate rustc_middle;
9 extern crate rustc_ast;
10 extern crate rustc_codegen_ssa;
11 extern crate rustc_data_structures;
12 extern crate rustc_errors;
13 extern crate rustc_fs_util;
14 extern crate rustc_hir;
15 extern crate rustc_incremental;
16 extern crate rustc_index;
17 extern crate rustc_session;
18 extern crate rustc_span;
19 extern crate rustc_target;
20
21 // This prevents duplicating functions and statics that are already part of the host rustc process.
22 #[allow(unused_extern_crates)]
23 extern crate rustc_driver;
24
25 use std::any::Any;
26 use std::str::FromStr;
27
28 use rustc_codegen_ssa::traits::CodegenBackend;
29 use rustc_codegen_ssa::CodegenResults;
30 use rustc_errors::ErrorReported;
31 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
32 use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader};
33 use rustc_middle::ty::query::Providers;
34 use rustc_session::config::OutputFilenames;
35 use rustc_session::Session;
36
37 use cranelift_codegen::settings::{self, Configurable};
38
39 use crate::constant::ConstantCx;
40 use crate::prelude::*;
41
42 mod abi;
43 mod allocator;
44 mod analyze;
45 mod archive;
46 mod backend;
47 mod base;
48 mod cast;
49 mod codegen_i128;
50 mod common;
51 mod compiler_builtins;
52 mod constant;
53 mod debuginfo;
54 mod discriminant;
55 mod driver;
56 mod inline_asm;
57 mod intrinsics;
58 mod linkage;
59 mod main_shim;
60 mod metadata;
61 mod num;
62 mod optimize;
63 mod pointer;
64 mod pretty_clif;
65 mod toolchain;
66 mod trap;
67 mod unsize;
68 mod value_and_place;
69 mod vtable;
70
71 mod prelude {
72     pub(crate) use std::convert::{TryFrom, TryInto};
73
74     pub(crate) use rustc_span::Span;
75
76     pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE};
77     pub(crate) use rustc_middle::bug;
78     pub(crate) use rustc_middle::mir::{self, *};
79     pub(crate) use rustc_middle::ty::layout::{self, TyAndLayout};
80     pub(crate) use rustc_middle::ty::{
81         self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut,
82         TypeFoldable, UintTy,
83     };
84     pub(crate) use rustc_target::abi::{Abi, LayoutOf, Scalar, Size, VariantIdx};
85
86     pub(crate) use rustc_data_structures::fx::FxHashMap;
87
88     pub(crate) use rustc_index::vec::Idx;
89
90     pub(crate) use cranelift_codegen::entity::EntitySet;
91     pub(crate) use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
92     pub(crate) use cranelift_codegen::ir::function::Function;
93     pub(crate) use cranelift_codegen::ir::types;
94     pub(crate) use cranelift_codegen::ir::{
95         AbiParam, Block, ExternalName, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc,
96         StackSlot, StackSlotData, StackSlotKind, TrapCode, Type, Value,
97     };
98     pub(crate) use cranelift_codegen::isa::{self, CallConv};
99     pub(crate) use cranelift_codegen::Context;
100     pub(crate) use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
101     pub(crate) use cranelift_module::{self, DataContext, DataId, FuncId, Linkage, Module};
102
103     pub(crate) use crate::abi::*;
104     pub(crate) use crate::base::{codegen_operand, codegen_place};
105     pub(crate) use crate::cast::*;
106     pub(crate) use crate::common::*;
107     pub(crate) use crate::debuginfo::{DebugContext, UnwindContext};
108     pub(crate) use crate::pointer::Pointer;
109     pub(crate) use crate::trap::*;
110     pub(crate) use crate::value_and_place::{CPlace, CPlaceInner, CValue};
111 }
112
113 struct PrintOnPanic<F: Fn() -> String>(F);
114 impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
115     fn drop(&mut self) {
116         if ::std::thread::panicking() {
117             println!("{}", (self.0)());
118         }
119     }
120 }
121
122 struct CodegenCx<'m, 'tcx: 'm> {
123     tcx: TyCtxt<'tcx>,
124     module: &'m mut dyn Module,
125     global_asm: String,
126     constants_cx: ConstantCx,
127     cached_context: Context,
128     vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
129     debug_context: Option<DebugContext<'tcx>>,
130     unwind_context: UnwindContext<'tcx>,
131 }
132
133 impl<'m, 'tcx> CodegenCx<'m, 'tcx> {
134     fn new(
135         tcx: TyCtxt<'tcx>,
136         backend_config: BackendConfig,
137         module: &'m mut dyn Module,
138         debug_info: bool,
139     ) -> Self {
140         let unwind_context = UnwindContext::new(
141             tcx,
142             module.isa(),
143             matches!(backend_config.codegen_mode, CodegenMode::Aot),
144         );
145         let debug_context =
146             if debug_info { Some(DebugContext::new(tcx, module.isa())) } else { None };
147         CodegenCx {
148             tcx,
149             module,
150             global_asm: String::new(),
151             constants_cx: ConstantCx::default(),
152             cached_context: Context::new(),
153             vtables: FxHashMap::default(),
154             debug_context,
155             unwind_context,
156         }
157     }
158
159     fn finalize(self) -> (String, Option<DebugContext<'tcx>>, UnwindContext<'tcx>) {
160         self.constants_cx.finalize(self.tcx, self.module);
161         (self.global_asm, self.debug_context, self.unwind_context)
162     }
163 }
164
165 #[derive(Copy, Clone, Debug)]
166 pub enum CodegenMode {
167     Aot,
168     Jit,
169     JitLazy,
170 }
171
172 impl Default for CodegenMode {
173     fn default() -> Self {
174         CodegenMode::Aot
175     }
176 }
177
178 impl FromStr for CodegenMode {
179     type Err = String;
180
181     fn from_str(s: &str) -> Result<Self, Self::Err> {
182         match s {
183             "aot" => Ok(CodegenMode::Aot),
184             "jit" => Ok(CodegenMode::Jit),
185             "jit-lazy" => Ok(CodegenMode::JitLazy),
186             _ => Err(format!("Unknown codegen mode `{}`", s)),
187         }
188     }
189 }
190
191 #[derive(Copy, Clone, Debug, Default)]
192 pub struct BackendConfig {
193     pub codegen_mode: CodegenMode,
194 }
195
196 impl BackendConfig {
197     fn from_opts(opts: &[String]) -> Result<Self, String> {
198         let mut config = BackendConfig::default();
199         for opt in opts {
200             if let Some((name, value)) = opt.split_once('=') {
201                 match name {
202                     "mode" => config.codegen_mode = value.parse()?,
203                     _ => return Err(format!("Unknown option `{}`", name)),
204                 }
205             } else {
206                 return Err(format!("Invalid option `{}`", opt));
207             }
208         }
209         Ok(config)
210     }
211 }
212
213 pub struct CraneliftCodegenBackend {
214     pub config: Option<BackendConfig>,
215 }
216
217 impl CodegenBackend for CraneliftCodegenBackend {
218     fn init(&self, sess: &Session) {
219         use rustc_session::config::Lto;
220         match sess.lto() {
221             Lto::No | Lto::ThinLocal => {}
222             Lto::Thin | Lto::Fat => sess.warn("LTO is not supported. You may get a linker error."),
223         }
224     }
225
226     fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
227         Box::new(crate::metadata::CraneliftMetadataLoader)
228     }
229
230     fn provide(&self, _providers: &mut Providers) {}
231     fn provide_extern(&self, _providers: &mut Providers) {}
232
233     fn target_features(&self, _sess: &Session) -> Vec<rustc_span::Symbol> {
234         vec![]
235     }
236
237     fn codegen_crate(
238         &self,
239         tcx: TyCtxt<'_>,
240         metadata: EncodedMetadata,
241         need_metadata_module: bool,
242     ) -> Box<dyn Any> {
243         let config = if let Some(config) = self.config {
244             config
245         } else {
246             BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
247                 .unwrap_or_else(|err| tcx.sess.fatal(&err))
248         };
249         driver::codegen_crate(tcx, metadata, need_metadata_module, config)
250     }
251
252     fn join_codegen(
253         &self,
254         ongoing_codegen: Box<dyn Any>,
255         _sess: &Session,
256     ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
257         Ok(*ongoing_codegen
258             .downcast::<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)>()
259             .unwrap())
260     }
261
262     fn link(
263         &self,
264         sess: &Session,
265         codegen_results: CodegenResults,
266         outputs: &OutputFilenames,
267     ) -> Result<(), ErrorReported> {
268         use rustc_codegen_ssa::back::link::link_binary;
269
270         link_binary::<crate::archive::ArArchiveBuilder<'_>>(
271             sess,
272             &codegen_results,
273             outputs,
274             &codegen_results.crate_name.as_str(),
275         );
276
277         Ok(())
278     }
279 }
280
281 fn target_triple(sess: &Session) -> target_lexicon::Triple {
282     sess.target.llvm_target.parse().unwrap()
283 }
284
285 fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> {
286     use target_lexicon::BinaryFormat;
287
288     let target_triple = crate::target_triple(sess);
289
290     let mut flags_builder = settings::builder();
291     flags_builder.enable("is_pic").unwrap();
292     flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
293     let enable_verifier =
294         cfg!(debug_assertions) || std::env::var("CG_CLIF_ENABLE_VERIFIER").is_ok();
295     flags_builder.set("enable_verifier", if enable_verifier { "true" } else { "false" }).unwrap();
296
297     let tls_model = match target_triple.binary_format {
298         BinaryFormat::Elf => "elf_gd",
299         BinaryFormat::Macho => "macho",
300         BinaryFormat::Coff => "coff",
301         _ => "none",
302     };
303     flags_builder.set("tls_model", tls_model).unwrap();
304
305     flags_builder.set("enable_simd", "true").unwrap();
306
307     flags_builder.set("enable_llvm_abi_extensions", "true").unwrap();
308
309     use rustc_session::config::OptLevel;
310     match sess.opts.optimize {
311         OptLevel::No => {
312             flags_builder.set("opt_level", "none").unwrap();
313         }
314         OptLevel::Less | OptLevel::Default => {}
315         OptLevel::Size | OptLevel::SizeMin | OptLevel::Aggressive => {
316             flags_builder.set("opt_level", "speed_and_size").unwrap();
317         }
318     }
319
320     let flags = settings::Flags::new(flags_builder);
321
322     let variant = cranelift_codegen::isa::BackendVariant::MachInst;
323     let mut isa_builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
324     // Don't use "haswell", as it implies `has_lzcnt`.macOS CI is still at Ivy Bridge EP, so `lzcnt`
325     // is interpreted as `bsr`.
326     isa_builder.enable("nehalem").unwrap();
327     isa_builder.finish(flags)
328 }
329
330 /// This is the entrypoint for a hot plugged rustc_codegen_cranelift
331 #[no_mangle]
332 pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
333     Box::new(CraneliftCodegenBackend { config: None })
334 }