]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_gcc/src/base.rs
Merge commit 'e228f0c16ea8c34794a6285bf57aab627c26b147' into libgccjit-codegen
[rust.git] / compiler / rustc_codegen_gcc / src / base.rs
1 use std::env;
2 use std::sync::Once;
3 use std::time::Instant;
4
5 use gccjit::{
6     Context,
7     FunctionType,
8     GlobalKind,
9 };
10 use rustc_hir::def_id::LOCAL_CRATE;
11 use rustc_middle::dep_graph;
12 use rustc_middle::middle::cstore::EncodedMetadata;
13 use rustc_middle::middle::exported_symbols;
14 use rustc_middle::ty::TyCtxt;
15 use rustc_middle::mir::mono::Linkage;
16 use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
17 use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
18 use rustc_codegen_ssa::mono_item::MonoItemExt;
19 use rustc_codegen_ssa::traits::DebugInfoMethods;
20 use rustc_session::config::DebugInfo;
21 use rustc_span::Symbol;
22
23 use crate::{GccContext, create_function_calling_initializers};
24 use crate::builder::Builder;
25 use crate::context::CodegenCx;
26
27 pub fn global_linkage_to_gcc(linkage: Linkage) -> GlobalKind {
28     match linkage {
29         Linkage::External => GlobalKind::Imported,
30         Linkage::AvailableExternally => GlobalKind::Imported,
31         Linkage::LinkOnceAny => unimplemented!(),
32         Linkage::LinkOnceODR => unimplemented!(),
33         Linkage::WeakAny => unimplemented!(),
34         Linkage::WeakODR => unimplemented!(),
35         Linkage::Appending => unimplemented!(),
36         Linkage::Internal => GlobalKind::Internal,
37         Linkage::Private => GlobalKind::Internal,
38         Linkage::ExternalWeak => GlobalKind::Imported, // TODO(antoyo): should be weak linkage.
39         Linkage::Common => unimplemented!(),
40     }
41 }
42
43 pub fn linkage_to_gcc(linkage: Linkage) -> FunctionType {
44     match linkage {
45         Linkage::External => FunctionType::Exported,
46         Linkage::AvailableExternally => FunctionType::Extern,
47         Linkage::LinkOnceAny => unimplemented!(),
48         Linkage::LinkOnceODR => unimplemented!(),
49         Linkage::WeakAny => FunctionType::Exported, // FIXME(antoyo): should be similar to linkonce.
50         Linkage::WeakODR => unimplemented!(),
51         Linkage::Appending => unimplemented!(),
52         Linkage::Internal => FunctionType::Internal,
53         Linkage::Private => FunctionType::Internal,
54         Linkage::ExternalWeak => unimplemented!(),
55         Linkage::Common => unimplemented!(),
56     }
57 }
58
59 pub fn compile_codegen_unit<'tcx>(tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (ModuleCodegen<GccContext>, u64) {
60     let prof_timer = tcx.prof.generic_activity("codegen_module");
61     let start_time = Instant::now();
62
63     let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
64     let (module, _) = tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result);
65     let time_to_codegen = start_time.elapsed();
66     drop(prof_timer);
67
68     // We assume that the cost to run GCC on a CGU is proportional to
69     // the time we needed for codegenning it.
70     let cost = time_to_codegen.as_secs() * 1_000_000_000 + time_to_codegen.subsec_nanos() as u64;
71
72     fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen<GccContext> {
73         let cgu = tcx.codegen_unit(cgu_name);
74         // Instantiate monomorphizations without filling out definitions yet...
75         //let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str());
76         let context = Context::default();
77         // TODO(antoyo): only set on x86 platforms.
78         context.add_command_line_option("-masm=intel");
79         for arg in &tcx.sess.opts.cg.llvm_args {
80             context.add_command_line_option(arg);
81         }
82         context.add_command_line_option("-fno-semantic-interposition");
83         if env::var("CG_GCCJIT_DUMP_CODE").as_deref() == Ok("1") {
84             context.set_dump_code_on_compile(true);
85         }
86         if env::var("CG_GCCJIT_DUMP_GIMPLE").as_deref() == Ok("1") {
87             context.set_dump_initial_gimple(true);
88         }
89         context.set_debug_info(true);
90         if env::var("CG_GCCJIT_DUMP_EVERYTHING").as_deref() == Ok("1") {
91             context.set_dump_everything(true);
92         }
93         if env::var("CG_GCCJIT_KEEP_INTERMEDIATES").as_deref() == Ok("1") {
94             context.set_keep_intermediates(true);
95         }
96
97         {
98             let cx = CodegenCx::new(&context, cgu, tcx);
99
100             static START: Once = Once::new();
101             START.call_once(|| {
102                 let initializer_name = format!("__gccGlobalCrateInit{}", tcx.crate_name(LOCAL_CRATE));
103                 let func = context.new_function(None, FunctionType::Exported, context.new_type::<()>(), &[], initializer_name, false);
104                 let block = func.new_block("initial");
105                 create_function_calling_initializers(tcx, &context, block);
106                 block.end_with_void_return(None);
107             });
108
109             let mono_items = cgu.items_in_deterministic_order(tcx);
110             for &(mono_item, (linkage, visibility)) in &mono_items {
111                 mono_item.predefine::<Builder<'_, '_, '_>>(&cx, linkage, visibility);
112             }
113
114             // ... and now that we have everything pre-defined, fill out those definitions.
115             for &(mono_item, _) in &mono_items {
116                 mono_item.define::<Builder<'_, '_, '_>>(&cx);
117             }
118
119             // If this codegen unit contains the main function, also create the
120             // wrapper here
121             maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx);
122
123             // Finalize debuginfo
124             if cx.sess().opts.debuginfo != DebugInfo::None {
125                 cx.debuginfo_finalize();
126             }
127
128             cx.global_init_block.end_with_void_return(None);
129         }
130
131         ModuleCodegen {
132             name: cgu_name.to_string(),
133             module_llvm: GccContext {
134                 context
135             },
136             kind: ModuleKind::Regular,
137         }
138     }
139
140     (module, cost)
141 }
142
143 pub fn write_compressed_metadata<'tcx>(tcx: TyCtxt<'tcx>, metadata: &EncodedMetadata, gcc_module: &mut GccContext) {
144     use snap::write::FrameEncoder;
145     use std::io::Write;
146
147     // Historical note:
148     //
149     // When using link.exe it was seen that the section name `.note.rustc`
150     // was getting shortened to `.note.ru`, and according to the PE and COFF
151     // specification:
152     //
153     // > Executable images do not use a string table and do not support
154     // > section names longer than 8 characters
155     //
156     // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
157     //
158     // As a result, we choose a slightly shorter name! As to why
159     // `.note.rustc` works on MinGW, see
160     // https://github.com/llvm/llvm-project/blob/llvmorg-12.0.0/lld/COFF/Writer.cpp#L1190-L1197
161     let section_name = if tcx.sess.target.is_like_osx { "__DATA,.rustc" } else { ".rustc" };
162
163     let context = &gcc_module.context;
164     let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
165     FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap();
166
167     let name = exported_symbols::metadata_symbol_name(tcx);
168     let typ = context.new_array_type(None, context.new_type::<u8>(), compressed.len() as i32);
169     let global = context.new_global(None, GlobalKind::Exported, typ, name);
170     global.global_set_initializer(&compressed);
171     global.set_link_section(section_name);
172
173     // Also generate a .section directive to force no
174     // flags, at least for ELF outputs, so that the
175     // metadata doesn't get loaded into memory.
176     let directive = format!(".section {}", section_name);
177     context.add_top_level_asm(None, &directive);
178 }