]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_gcc/src/lib.rs
Rollup merge of #95376 - WaffleLapkin:drain_keep_rest, r=dtolnay
[rust.git] / compiler / rustc_codegen_gcc / src / lib.rs
1 /*
2  * TODO(antoyo): implement equality in libgccjit based on https://zpz.github.io/blog/overloading-equality-operator-in-cpp-class-hierarchy/ (for type equality?)
3  * TODO(antoyo): support #[inline] attributes.
4  * TODO(antoyo): support LTO (gcc's equivalent to Thin LTO is enabled by -fwhopr: https://stackoverflow.com/questions/64954525/does-gcc-have-thin-lto).
5  *
6  * TODO(antoyo): remove the patches.
7  */
8
9 #![feature(
10     rustc_private,
11     decl_macro,
12     associated_type_bounds,
13     never_type,
14     trusted_len,
15     hash_raw_entry
16 )]
17 #![allow(broken_intra_doc_links)]
18 #![recursion_limit="256"]
19 #![warn(rust_2018_idioms)]
20 #![warn(unused_lifetimes)]
21
22 extern crate rustc_ast;
23 extern crate rustc_codegen_ssa;
24 extern crate rustc_data_structures;
25 extern crate rustc_errors;
26 extern crate rustc_hir;
27 extern crate rustc_metadata;
28 extern crate rustc_middle;
29 extern crate rustc_session;
30 extern crate rustc_span;
31 extern crate rustc_target;
32 extern crate tempfile;
33
34 // This prevents duplicating functions and statics that are already part of the host rustc process.
35 #[allow(unused_extern_crates)]
36 extern crate rustc_driver;
37
38 mod abi;
39 mod allocator;
40 mod archive;
41 mod asm;
42 mod back;
43 mod base;
44 mod builder;
45 mod callee;
46 mod common;
47 mod consts;
48 mod context;
49 mod coverageinfo;
50 mod debuginfo;
51 mod declare;
52 mod int;
53 mod intrinsic;
54 mod mono_item;
55 mod type_;
56 mod type_of;
57
58 use std::any::Any;
59 use std::sync::{Arc, Mutex};
60
61 use gccjit::{Context, OptimizationLevel, CType};
62 use rustc_ast::expand::allocator::AllocatorKind;
63 use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
64 use rustc_codegen_ssa::base::codegen_crate;
65 use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryFn};
66 use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
67 use rustc_codegen_ssa::target_features::supported_target_features;
68 use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};
69 use rustc_data_structures::fx::FxHashMap;
70 use rustc_errors::{ErrorGuaranteed, Handler};
71 use rustc_metadata::EncodedMetadata;
72 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
73 use rustc_middle::ty::TyCtxt;
74 use rustc_middle::ty::query::Providers;
75 use rustc_session::config::{Lto, OptLevel, OutputFilenames};
76 use rustc_session::Session;
77 use rustc_span::Symbol;
78 use rustc_span::fatal_error::FatalError;
79 use tempfile::TempDir;
80
81 pub struct PrintOnPanic<F: Fn() -> String>(pub F);
82
83 impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
84     fn drop(&mut self) {
85         if ::std::thread::panicking() {
86             println!("{}", (self.0)());
87         }
88     }
89 }
90
91 #[derive(Clone)]
92 pub struct GccCodegenBackend {
93     supports_128bit_integers: Arc<Mutex<bool>>,
94 }
95
96 impl CodegenBackend for GccCodegenBackend {
97     fn init(&self, sess: &Session) {
98         if sess.lto() != Lto::No {
99             sess.warn("LTO is not supported. You may get a linker error.");
100         }
101
102         let temp_dir = TempDir::new().expect("cannot create temporary directory");
103         let temp_file = temp_dir.into_path().join("result.asm");
104         let check_context = Context::default();
105         check_context.set_print_errors_to_stderr(false);
106         let _int128_ty = check_context.new_c_type(CType::UInt128t);
107         // NOTE: we cannot just call compile() as this would require other files than libgccjit.so.
108         check_context.compile_to_file(gccjit::OutputKind::Assembler, temp_file.to_str().expect("path to str"));
109         *self.supports_128bit_integers.lock().expect("lock") = check_context.get_last_error() == Ok(None);
110     }
111
112     fn provide(&self, providers: &mut Providers) {
113         // FIXME(antoyo) compute list of enabled features from cli flags
114         providers.global_backend_features = |_tcx, ()| vec![];
115     }
116
117     fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>, metadata: EncodedMetadata, need_metadata_module: bool) -> Box<dyn Any> {
118         let target_cpu = target_cpu(tcx.sess);
119         let res = codegen_crate(self.clone(), tcx, target_cpu.to_string(), metadata, need_metadata_module);
120
121         Box::new(res)
122     }
123
124     fn join_codegen(&self, ongoing_codegen: Box<dyn Any>, sess: &Session, _outputs: &OutputFilenames) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorGuaranteed> {
125         let (codegen_results, work_products) = ongoing_codegen
126             .downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<GccCodegenBackend>>()
127             .expect("Expected GccCodegenBackend's OngoingCodegen, found Box<Any>")
128             .join(sess);
129
130         Ok((codegen_results, work_products))
131     }
132
133     fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) -> Result<(), ErrorGuaranteed> {
134         use rustc_codegen_ssa::back::link::link_binary;
135
136         link_binary(
137             sess,
138             &crate::archive::ArArchiveBuilderBuilder,
139             &codegen_results,
140             outputs,
141         )
142     }
143
144     fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
145         target_features(sess, allow_unstable)
146     }
147 }
148
149 impl ExtraBackendMethods for GccCodegenBackend {
150     fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) -> Self::Module {
151         let mut mods = GccContext {
152             context: Context::default(),
153         };
154         unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, has_alloc_error_handler); }
155         mods
156     }
157
158     fn compile_codegen_unit<'tcx>(&self, tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (ModuleCodegen<Self::Module>, u64) {
159         base::compile_codegen_unit(tcx, cgu_name, *self.supports_128bit_integers.lock().expect("lock"))
160     }
161
162     fn target_machine_factory(&self, _sess: &Session, _opt_level: OptLevel, _features: &[String]) -> TargetMachineFactoryFn<Self> {
163         // TODO(antoyo): set opt level.
164         Arc::new(|_| {
165             Ok(())
166         })
167     }
168
169     fn target_cpu<'b>(&self, _sess: &'b Session) -> &'b str {
170         unimplemented!();
171     }
172
173     fn tune_cpu<'b>(&self, _sess: &'b Session) -> Option<&'b str> {
174         None
175         // TODO(antoyo)
176     }
177 }
178
179 pub struct ModuleBuffer;
180
181 impl ModuleBufferMethods for ModuleBuffer {
182     fn data(&self) -> &[u8] {
183         unimplemented!();
184     }
185 }
186
187 pub struct ThinBuffer;
188
189 impl ThinBufferMethods for ThinBuffer {
190     fn data(&self) -> &[u8] {
191         unimplemented!();
192     }
193 }
194
195 pub struct GccContext {
196     context: Context<'static>,
197 }
198
199 unsafe impl Send for GccContext {}
200 // FIXME(antoyo): that shouldn't be Sync. Parallel compilation is currently disabled with "-Zno-parallel-llvm". Try to disable it here.
201 unsafe impl Sync for GccContext {}
202
203 impl WriteBackendMethods for GccCodegenBackend {
204     type Module = GccContext;
205     type TargetMachine = ();
206     type ModuleBuffer = ModuleBuffer;
207     type Context = ();
208     type ThinData = ();
209     type ThinBuffer = ThinBuffer;
210
211     fn run_fat_lto(_cgcx: &CodegenContext<Self>, mut modules: Vec<FatLTOInput<Self>>, _cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<LtoModuleCodegen<Self>, FatalError> {
212         // TODO(antoyo): implement LTO by sending -flto to libgccjit and adding the appropriate gcc linker plugins.
213         // NOTE: implemented elsewhere.
214         // TODO(antoyo): what is implemented elsewhere ^ ?
215         let module =
216             match modules.remove(0) {
217                 FatLTOInput::InMemory(module) => module,
218                 FatLTOInput::Serialized { .. } => {
219                     unimplemented!();
220                 }
221             };
222         Ok(LtoModuleCodegen::Fat { module, _serialized_bitcode: vec![] })
223     }
224
225     fn run_thin_lto(_cgcx: &CodegenContext<Self>, _modules: Vec<(String, Self::ThinBuffer)>, _cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> {
226         unimplemented!();
227     }
228
229     fn print_pass_timings(&self) {
230         unimplemented!();
231     }
232
233     unsafe fn optimize(_cgcx: &CodegenContext<Self>, _diag_handler: &Handler, module: &ModuleCodegen<Self::Module>, config: &ModuleConfig) -> Result<(), FatalError> {
234         module.module_llvm.context.set_optimization_level(to_gcc_opt_level(config.opt_level));
235         Ok(())
236     }
237
238     fn optimize_fat(_cgcx: &CodegenContext<Self>, _module: &mut ModuleCodegen<Self::Module>) -> Result<(), FatalError> {
239         // TODO(antoyo)
240         Ok(())
241     }
242
243     unsafe fn optimize_thin(_cgcx: &CodegenContext<Self>, _thin: ThinModule<Self>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
244         unimplemented!();
245     }
246
247     unsafe fn codegen(cgcx: &CodegenContext<Self>, diag_handler: &Handler, module: ModuleCodegen<Self::Module>, config: &ModuleConfig) -> Result<CompiledModule, FatalError> {
248         back::write::codegen(cgcx, diag_handler, module, config)
249     }
250
251     fn prepare_thin(_module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer) {
252         unimplemented!();
253     }
254
255     fn serialize_module(_module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
256         unimplemented!();
257     }
258
259     fn run_link(cgcx: &CodegenContext<Self>, diag_handler: &Handler, modules: Vec<ModuleCodegen<Self::Module>>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
260         back::write::link(cgcx, diag_handler, modules)
261     }
262 }
263
264 /// This is the entrypoint for a hot plugged rustc_codegen_gccjit
265 #[no_mangle]
266 pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
267     Box::new(GccCodegenBackend {
268         supports_128bit_integers: Arc::new(Mutex::new(false)),
269     })
270 }
271
272 fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
273     match optlevel {
274         None => OptimizationLevel::None,
275         Some(level) => {
276             match level {
277                 OptLevel::No => OptimizationLevel::None,
278                 OptLevel::Less => OptimizationLevel::Limited,
279                 OptLevel::Default => OptimizationLevel::Standard,
280                 OptLevel::Aggressive => OptimizationLevel::Aggressive,
281                 OptLevel::Size | OptLevel::SizeMin => OptimizationLevel::Limited,
282             }
283         },
284     }
285 }
286
287 fn handle_native(name: &str) -> &str {
288     if name != "native" {
289         return name;
290     }
291
292     unimplemented!();
293 }
294
295 pub fn target_cpu(sess: &Session) -> &str {
296     match sess.opts.cg.target_cpu {
297         Some(ref name) => handle_native(name),
298         None => handle_native(sess.target.cpu.as_ref()),
299     }
300 }
301
302 pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
303     supported_target_features(sess)
304         .iter()
305         .filter_map(
306             |&(feature, gate)| {
307                 if sess.is_nightly_build() || allow_unstable || gate.is_none() { Some(feature) } else { None }
308             },
309         )
310         .filter(|_feature| {
311             // TODO(antoyo): implement a way to get enabled feature in libgccjit.
312             // Probably using the equivalent of __builtin_cpu_supports.
313             #[cfg(feature="master")]
314             {
315                 _feature.contains("sse") || _feature.contains("avx")
316             }
317             #[cfg(not(feature="master"))]
318             {
319                 false
320             }
321             /*
322                adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512gfni,
323                avx512ifma, avx512pf, avx512vaes, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpclmulqdq,
324                avx512vpopcntdq, bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
325                sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, xsave, xsavec, xsaveopt, xsaves
326              */
327             //false
328         })
329         .map(|feature| Symbol::intern(feature))
330         .collect()
331 }