]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_gcc/src/lib.rs
Rollup merge of #104672 - Voultapher:unify-sort-modules, r=thomcc
[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, alloc_error_handler_kind: AllocatorKind) -> Self::Module {
157         let mut mods = GccContext {
158             context: Context::default(),
159         };
160         unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); }
161         mods
162     }
163
164     fn compile_codegen_unit(&self, tcx: TyCtxt<'_>, 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
176 pub struct ModuleBuffer;
177
178 impl ModuleBufferMethods for ModuleBuffer {
179     fn data(&self) -> &[u8] {
180         unimplemented!();
181     }
182 }
183
184 pub struct ThinBuffer;
185
186 impl ThinBufferMethods for ThinBuffer {
187     fn data(&self) -> &[u8] {
188         unimplemented!();
189     }
190 }
191
192 pub struct GccContext {
193     context: Context<'static>,
194 }
195
196 unsafe impl Send for GccContext {}
197 // FIXME(antoyo): that shouldn't be Sync. Parallel compilation is currently disabled with "-Zno-parallel-llvm". Try to disable it here.
198 unsafe impl Sync for GccContext {}
199
200 impl WriteBackendMethods for GccCodegenBackend {
201     type Module = GccContext;
202     type TargetMachine = ();
203     type ModuleBuffer = ModuleBuffer;
204     type ThinData = ();
205     type ThinBuffer = ThinBuffer;
206
207     fn run_fat_lto(_cgcx: &CodegenContext<Self>, mut modules: Vec<FatLTOInput<Self>>, _cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<LtoModuleCodegen<Self>, FatalError> {
208         // TODO(antoyo): implement LTO by sending -flto to libgccjit and adding the appropriate gcc linker plugins.
209         // NOTE: implemented elsewhere.
210         // TODO(antoyo): what is implemented elsewhere ^ ?
211         let module =
212             match modules.remove(0) {
213                 FatLTOInput::InMemory(module) => module,
214                 FatLTOInput::Serialized { .. } => {
215                     unimplemented!();
216                 }
217             };
218         Ok(LtoModuleCodegen::Fat { module, _serialized_bitcode: vec![] })
219     }
220
221     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> {
222         unimplemented!();
223     }
224
225     fn print_pass_timings(&self) {
226         unimplemented!();
227     }
228
229     unsafe fn optimize(_cgcx: &CodegenContext<Self>, _diag_handler: &Handler, module: &ModuleCodegen<Self::Module>, config: &ModuleConfig) -> Result<(), FatalError> {
230         module.module_llvm.context.set_optimization_level(to_gcc_opt_level(config.opt_level));
231         Ok(())
232     }
233
234     fn optimize_fat(_cgcx: &CodegenContext<Self>, _module: &mut ModuleCodegen<Self::Module>) -> Result<(), FatalError> {
235         // TODO(antoyo)
236         Ok(())
237     }
238
239     unsafe fn optimize_thin(_cgcx: &CodegenContext<Self>, _thin: ThinModule<Self>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
240         unimplemented!();
241     }
242
243     unsafe fn codegen(cgcx: &CodegenContext<Self>, diag_handler: &Handler, module: ModuleCodegen<Self::Module>, config: &ModuleConfig) -> Result<CompiledModule, FatalError> {
244         back::write::codegen(cgcx, diag_handler, module, config)
245     }
246
247     fn prepare_thin(_module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer) {
248         unimplemented!();
249     }
250
251     fn serialize_module(_module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
252         unimplemented!();
253     }
254
255     fn run_link(cgcx: &CodegenContext<Self>, diag_handler: &Handler, modules: Vec<ModuleCodegen<Self::Module>>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
256         back::write::link(cgcx, diag_handler, modules)
257     }
258 }
259
260 /// This is the entrypoint for a hot plugged rustc_codegen_gccjit
261 #[no_mangle]
262 pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
263     Box::new(GccCodegenBackend {
264         supports_128bit_integers: Arc::new(Mutex::new(false)),
265     })
266 }
267
268 fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
269     match optlevel {
270         None => OptimizationLevel::None,
271         Some(level) => {
272             match level {
273                 OptLevel::No => OptimizationLevel::None,
274                 OptLevel::Less => OptimizationLevel::Limited,
275                 OptLevel::Default => OptimizationLevel::Standard,
276                 OptLevel::Aggressive => OptimizationLevel::Aggressive,
277                 OptLevel::Size | OptLevel::SizeMin => OptimizationLevel::Limited,
278             }
279         },
280     }
281 }
282
283 fn handle_native(name: &str) -> &str {
284     if name != "native" {
285         return name;
286     }
287
288     unimplemented!();
289 }
290
291 pub fn target_cpu(sess: &Session) -> &str {
292     match sess.opts.cg.target_cpu {
293         Some(ref name) => handle_native(name),
294         None => handle_native(sess.target.cpu.as_ref()),
295     }
296 }
297
298 pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
299     supported_target_features(sess)
300         .iter()
301         .filter_map(
302             |&(feature, gate)| {
303                 if sess.is_nightly_build() || allow_unstable || gate.is_none() { Some(feature) } else { None }
304             },
305         )
306         .filter(|_feature| {
307             // TODO(antoyo): implement a way to get enabled feature in libgccjit.
308             // Probably using the equivalent of __builtin_cpu_supports.
309             #[cfg(feature="master")]
310             {
311                 _feature.contains("sse") || _feature.contains("avx")
312             }
313             #[cfg(not(feature="master"))]
314             {
315                 false
316             }
317             /*
318                adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512ifma,
319                avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
320                bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
321                sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
322              */
323             //false
324         })
325         .map(|feature| Symbol::intern(feature))
326         .collect()
327 }