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