]>
Commit | Line | Data |
---|---|---|
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 | ||
064997fb FG |
9 | #![feature( |
10 | rustc_private, | |
11 | decl_macro, | |
12 | associated_type_bounds, | |
13 | never_type, | |
14 | trusted_len, | |
15 | hash_raw_entry | |
16 | )] | |
c295e0f8 XL |
17 | #![allow(broken_intra_doc_links)] |
18 | #![recursion_limit="256"] | |
19 | #![warn(rust_2018_idioms)] | |
20 | #![warn(unused_lifetimes)] | |
21 | ||
f2b60f7d | 22 | extern crate rustc_apfloat; |
c295e0f8 XL |
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; | |
c295e0f8 | 32 | extern crate rustc_target; |
5e7ed085 | 33 | extern crate tempfile; |
c295e0f8 XL |
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; | |
5e7ed085 | 53 | mod int; |
c295e0f8 XL |
54 | mod intrinsic; |
55 | mod mono_item; | |
56 | mod type_; | |
57 | mod type_of; | |
58 | ||
59 | use std::any::Any; | |
5e7ed085 | 60 | use std::sync::{Arc, Mutex}; |
c295e0f8 | 61 | |
5e7ed085 | 62 | use gccjit::{Context, OptimizationLevel, CType}; |
c295e0f8 XL |
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; | |
5e7ed085 | 71 | use rustc_errors::{ErrorGuaranteed, Handler}; |
c295e0f8 XL |
72 | use rustc_metadata::EncodedMetadata; |
73 | use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; | |
74 | use rustc_middle::ty::TyCtxt; | |
5e7ed085 | 75 | use rustc_middle::ty::query::Providers; |
c295e0f8 XL |
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; | |
5e7ed085 | 80 | use tempfile::TempDir; |
c295e0f8 XL |
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)] | |
5e7ed085 FG |
93 | pub struct GccCodegenBackend { |
94 | supports_128bit_integers: Arc<Mutex<bool>>, | |
95 | } | |
c295e0f8 XL |
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 | } | |
5e7ed085 FG |
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![]; | |
c295e0f8 XL |
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 | ||
c295e0f8 XL |
122 | Box::new(res) |
123 | } | |
124 | ||
5e7ed085 | 125 | fn join_codegen(&self, ongoing_codegen: Box<dyn Any>, sess: &Session, _outputs: &OutputFilenames) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorGuaranteed> { |
c295e0f8 XL |
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 | ||
5e7ed085 | 134 | fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) -> Result<(), ErrorGuaranteed> { |
c295e0f8 XL |
135 | use rustc_codegen_ssa::back::link::link_binary; |
136 | ||
064997fb | 137 | link_binary( |
c295e0f8 | 138 | sess, |
064997fb | 139 | &crate::archive::ArArchiveBuilderBuilder, |
c295e0f8 XL |
140 | &codegen_results, |
141 | outputs, | |
142 | ) | |
143 | } | |
144 | ||
064997fb FG |
145 | fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> { |
146 | target_features(sess, allow_unstable) | |
c295e0f8 XL |
147 | } |
148 | } | |
149 | ||
150 | impl ExtraBackendMethods for GccCodegenBackend { | |
04454e1e FG |
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 { | |
c295e0f8 | 153 | context: Context::default(), |
04454e1e FG |
154 | }; |
155 | unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, has_alloc_error_handler); } | |
156 | mods | |
c295e0f8 XL |
157 | } |
158 | ||
159 | fn compile_codegen_unit<'tcx>(&self, tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (ModuleCodegen<Self::Module>, u64) { | |
5e7ed085 | 160 | base::compile_codegen_unit(tcx, cgu_name, *self.supports_128bit_integers.lock().expect("lock")) |
c295e0f8 XL |
161 | } |
162 | ||
5e7ed085 | 163 | fn target_machine_factory(&self, _sess: &Session, _opt_level: OptLevel, _features: &[String]) -> TargetMachineFactoryFn<Self> { |
c295e0f8 XL |
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. | |
923072b8 | 215 | // TODO(antoyo): what is implemented elsewhere ^ ? |
c295e0f8 XL |
216 | let module = |
217 | match modules.remove(0) { | |
218 | FatLTOInput::InMemory(module) => module, | |
219 | FatLTOInput::Serialized { .. } => { | |
220 | unimplemented!(); | |
221 | } | |
222 | }; | |
04454e1e | 223 | Ok(LtoModuleCodegen::Fat { module, _serialized_bitcode: vec![] }) |
c295e0f8 XL |
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 | ||
04454e1e FG |
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> { | |
c295e0f8 XL |
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 | ||
c295e0f8 XL |
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> { | |
5e7ed085 FG |
268 | Box::new(GccCodegenBackend { |
269 | supports_128bit_integers: Arc::new(Mutex::new(false)), | |
270 | }) | |
c295e0f8 XL |
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 { | |
5e7ed085 FG |
297 | match sess.opts.cg.target_cpu { |
298 | Some(ref name) => handle_native(name), | |
299 | None => handle_native(sess.target.cpu.as_ref()), | |
300 | } | |
c295e0f8 XL |
301 | } |
302 | ||
064997fb | 303 | pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> { |
c295e0f8 XL |
304 | supported_target_features(sess) |
305 | .iter() | |
306 | .filter_map( | |
307 | |&(feature, gate)| { | |
064997fb | 308 | if sess.is_nightly_build() || allow_unstable || gate.is_none() { Some(feature) } else { None } |
c295e0f8 XL |
309 | }, |
310 | ) | |
311 | .filter(|_feature| { | |
312 | // TODO(antoyo): implement a way to get enabled feature in libgccjit. | |
923072b8 FG |
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 | |
c295e0f8 XL |
329 | }) |
330 | .map(|feature| Symbol::intern(feature)) | |
331 | .collect() | |
332 | } |