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