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