]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_gcc/src/lib.rs
Add fine-grained LLVM CFI support to the Rust compiler
[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(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
15 extern crate rustc_ast;
16 extern crate rustc_codegen_ssa;
17 extern crate rustc_data_structures;
18 extern crate rustc_errors;
19 extern crate rustc_hir;
20 extern crate rustc_metadata;
21 extern crate rustc_middle;
22 extern crate rustc_session;
23 extern crate rustc_span;
24 extern crate rustc_target;
25 extern crate tempfile;
26
27 // This prevents duplicating functions and statics that are already part of the host rustc process.
28 #[allow(unused_extern_crates)]
29 extern crate rustc_driver;
30
31 mod abi;
32 mod allocator;
33 mod archive;
34 mod asm;
35 mod back;
36 mod base;
37 mod builder;
38 mod callee;
39 mod common;
40 mod consts;
41 mod context;
42 mod coverageinfo;
43 mod debuginfo;
44 mod declare;
45 mod int;
46 mod intrinsic;
47 mod mono_item;
48 mod type_;
49 mod type_of;
50
51 use std::any::Any;
52 use std::sync::{Arc, Mutex};
53
54 use gccjit::{Context, OptimizationLevel, CType};
55 use rustc_ast::expand::allocator::AllocatorKind;
56 use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
57 use rustc_codegen_ssa::base::codegen_crate;
58 use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryFn};
59 use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
60 use rustc_codegen_ssa::target_features::supported_target_features;
61 use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};
62 use rustc_data_structures::fx::FxHashMap;
63 use rustc_errors::{ErrorGuaranteed, Handler};
64 use rustc_metadata::EncodedMetadata;
65 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
66 use rustc_middle::ty::TyCtxt;
67 use rustc_middle::ty::query::Providers;
68 use rustc_session::config::{Lto, OptLevel, OutputFilenames};
69 use rustc_session::Session;
70 use rustc_span::Symbol;
71 use rustc_span::fatal_error::FatalError;
72 use tempfile::TempDir;
73
74 pub struct PrintOnPanic<F: Fn() -> String>(pub F);
75
76 impl<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)]
85 pub struct GccCodegenBackend {
86     supports_128bit_integers: Arc<Mutex<bool>>,
87 }
88
89 impl 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         }
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![];
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
114         Box::new(res)
115     }
116
117     fn join_codegen(&self, ongoing_codegen: Box<dyn Any>, sess: &Session, _outputs: &OutputFilenames) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorGuaranteed> {
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
126     fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) -> Result<(), ErrorGuaranteed> {
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
141 impl ExtraBackendMethods for GccCodegenBackend {
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 {
144             context: Context::default(),
145         };
146         unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, has_alloc_error_handler); }
147         mods
148     }
149
150     fn compile_codegen_unit<'tcx>(&self, tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (ModuleCodegen<Self::Module>, u64) {
151         base::compile_codegen_unit(tcx, cgu_name, *self.supports_128bit_integers.lock().expect("lock"))
152     }
153
154     fn target_machine_factory(&self, _sess: &Session, _opt_level: OptLevel, _features: &[String]) -> TargetMachineFactoryFn<Self> {
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
171 pub struct ModuleBuffer;
172
173 impl ModuleBufferMethods for ModuleBuffer {
174     fn data(&self) -> &[u8] {
175         unimplemented!();
176     }
177 }
178
179 pub struct ThinBuffer;
180
181 impl ThinBufferMethods for ThinBuffer {
182     fn data(&self) -> &[u8] {
183         unimplemented!();
184     }
185 }
186
187 pub struct GccContext {
188     context: Context<'static>,
189 }
190
191 unsafe 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.
193 unsafe impl Sync for GccContext {}
194
195 impl 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.
206         // TODO(antoyo): what is implemented elsewhere ^ ?
207         let module =
208             match modules.remove(0) {
209                 FatLTOInput::InMemory(module) => module,
210                 FatLTOInput::Serialized { .. } => {
211                     unimplemented!();
212                 }
213             };
214         Ok(LtoModuleCodegen::Fat { module, _serialized_bitcode: vec![] })
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
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> {
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
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]
258 pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
259     Box::new(GccCodegenBackend {
260         supports_128bit_integers: Arc::new(Mutex::new(false)),
261     })
262 }
263
264 fn 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
279 fn handle_native(name: &str) -> &str {
280     if name != "native" {
281         return name;
282     }
283
284     unimplemented!();
285 }
286
287 pub fn target_cpu(sess: &Session) -> &str {
288     match sess.opts.cg.target_cpu {
289         Some(ref name) => handle_native(name),
290         None => handle_native(sess.target.cpu.as_ref()),
291     }
292 }
293
294 pub 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.
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
320         })
321         .map(|feature| Symbol::intern(feature))
322         .collect()
323 }