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