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