2018-05-08 13:10:16 +00:00
|
|
|
//! Codegen the completed AST to the LLVM IR.
|
2015-02-28 21:53:12 +00:00
|
|
|
//!
|
2018-05-08 13:10:16 +00:00
|
|
|
//! Some functions here, such as codegen_block and codegen_expr, return a value --
|
|
|
|
//! the result of the codegen to LLVM -- while others, such as codegen_fn
|
|
|
|
//! and mono_item, are called only for the side effect of adding a
|
2015-02-28 21:53:12 +00:00
|
|
|
//! particular definition to the LLVM IR output we're producing.
|
|
|
|
//!
|
2018-05-08 13:10:16 +00:00
|
|
|
//! Hopefully useful general knowledge about codegen:
|
2015-02-28 21:53:12 +00:00
|
|
|
//!
|
2018-07-10 10:28:39 +00:00
|
|
|
//! * There's no way to find out the Ty type of a Value. Doing so
|
2015-02-28 21:53:12 +00:00
|
|
|
//! would be "trying to get the eggs out of an omelette" (credit:
|
2018-07-02 14:52:53 +00:00
|
|
|
//! pcwalton). You can, instead, find out its llvm::Type by calling val_ty,
|
|
|
|
//! but one llvm::Type corresponds to many `Ty`s; for instance, tup(int, int,
|
|
|
|
//! int) and rec(x=int, y=int, z=int) will have the same llvm::Type.
|
2011-12-14 00:25:51 +00:00
|
|
|
|
2016-07-21 16:49:59 +00:00
|
|
|
use super::ModuleLlvm;
|
2018-10-03 14:56:24 +00:00
|
|
|
use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
|
|
|
|
use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
|
2018-09-26 15:00:01 +00:00
|
|
|
use super::LlvmCodegenBackend;
|
2014-11-27 12:21:26 +00:00
|
|
|
|
2018-09-24 13:26:39 +00:00
|
|
|
use llvm;
|
2017-04-26 21:22:45 +00:00
|
|
|
use metadata;
|
2019-01-20 04:44:02 +00:00
|
|
|
use rustc::dep_graph;
|
2018-10-03 14:56:24 +00:00
|
|
|
use rustc::mir::mono::{Linkage, Visibility, Stats};
|
2017-10-27 08:50:39 +00:00
|
|
|
use rustc::middle::cstore::{EncodedMetadata};
|
2018-10-03 14:56:24 +00:00
|
|
|
use rustc::ty::TyCtxt;
|
2018-03-05 16:41:11 +00:00
|
|
|
use rustc::middle::exported_symbols;
|
2018-10-03 14:56:24 +00:00
|
|
|
use rustc::session::config::{self, DebugInfo};
|
|
|
|
use builder::Builder;
|
2018-09-28 10:18:03 +00:00
|
|
|
use common;
|
2018-09-27 13:31:20 +00:00
|
|
|
use context::CodegenCx;
|
2018-10-03 14:56:24 +00:00
|
|
|
use monomorphize::partitioning::CodegenUnitExt;
|
|
|
|
use rustc_codegen_ssa::mono_item::MonoItemExt;
|
2018-08-07 14:04:34 +00:00
|
|
|
use rustc_data_structures::small_c_str::SmallCStr;
|
2013-06-16 10:52:44 +00:00
|
|
|
|
2018-11-16 11:45:28 +00:00
|
|
|
use rustc_codegen_ssa::traits::*;
|
2018-10-23 15:01:35 +00:00
|
|
|
use rustc_codegen_ssa::back::write::submit_codegened_module_to_llvm;
|
2018-08-07 15:14:40 +00:00
|
|
|
|
2017-10-17 20:08:13 +00:00
|
|
|
use std::ffi::CString;
|
2018-10-03 14:56:24 +00:00
|
|
|
use std::time::Instant;
|
2017-09-14 03:26:39 +00:00
|
|
|
use syntax_pos::symbol::InternedString;
|
2018-10-03 14:56:24 +00:00
|
|
|
use rustc::hir::CodegenFnAttrs;
|
2012-03-04 01:49:23 +00:00
|
|
|
|
2018-08-22 15:48:32 +00:00
|
|
|
use value::Value;
|
2018-07-10 10:28:39 +00:00
|
|
|
|
2018-06-16 14:46:03 +00:00
|
|
|
|
2018-10-23 15:01:35 +00:00
|
|
|
pub fn write_metadata<'a, 'gcx>(
|
2018-09-25 15:52:03 +00:00
|
|
|
tcx: TyCtxt<'a, 'gcx, 'gcx>,
|
|
|
|
llvm_module: &ModuleLlvm
|
|
|
|
) -> EncodedMetadata {
|
2017-06-08 21:10:36 +00:00
|
|
|
use std::io::Write;
|
|
|
|
use flate2::Compression;
|
2017-07-10 15:54:50 +00:00
|
|
|
use flate2::write::DeflateEncoder;
|
Store metadata separately in rlib files
Right now whenever an rlib file is linked against, all of the metadata from the
rlib is pulled in to the final staticlib or binary. The reason for this is that
the metadata is currently stored in a section of the object file. Note that this
is intentional for dynamic libraries in order to distribute metadata bundled
with static libraries.
This commit alters the situation for rlib libraries to instead store the
metadata in a separate file in the archive. In doing so, when the archive is
passed to the linker, none of the metadata will get pulled into the result
executable. Furthermore, the metadata file is skipped when assembling rlibs into
an archive.
The snag in this implementation comes with multiple output formats. When
generating a dylib, the metadata needs to be in the object file, but when
generating an rlib this needs to be separate. In order to accomplish this, the
metadata variable is inserted into an entirely separate LLVM Module which is
then codegen'd into a different location (foo.metadata.o). This is then linked
into dynamic libraries and silently ignored for rlib files.
While changing how metadata is inserted into archives, I have also stopped
compressing metadata when inserted into rlib files. We have wanted to stop
compressing metadata, but the sections it creates in object file sections are
apparently too large. Thankfully if it's just an arbitrary file it doesn't
matter how large it is.
I have seen massive reductions in executable sizes, as well as staticlib output
sizes (to confirm that this is all working).
2013-12-04 01:41:01 +00:00
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod());
|
2017-04-13 15:48:19 +00:00
|
|
|
|
2016-10-19 01:06:46 +00:00
|
|
|
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
|
|
|
enum MetadataKind {
|
|
|
|
None,
|
|
|
|
Uncompressed,
|
|
|
|
Compressed
|
|
|
|
}
|
|
|
|
|
2017-04-13 22:21:51 +00:00
|
|
|
let kind = tcx.sess.crate_types.borrow().iter().map(|ty| {
|
2016-10-19 01:06:46 +00:00
|
|
|
match *ty {
|
2018-07-26 17:13:11 +00:00
|
|
|
config::CrateType::Executable |
|
|
|
|
config::CrateType::Staticlib |
|
|
|
|
config::CrateType::Cdylib => MetadataKind::None,
|
2016-10-19 01:06:46 +00:00
|
|
|
|
2018-07-26 17:13:11 +00:00
|
|
|
config::CrateType::Rlib => MetadataKind::Uncompressed,
|
2016-10-19 01:06:46 +00:00
|
|
|
|
2018-07-26 17:13:11 +00:00
|
|
|
config::CrateType::Dylib |
|
|
|
|
config::CrateType::ProcMacro => MetadataKind::Compressed,
|
2016-10-19 01:06:46 +00:00
|
|
|
}
|
2018-05-24 15:05:16 +00:00
|
|
|
}).max().unwrap_or(MetadataKind::None);
|
2016-10-19 01:06:46 +00:00
|
|
|
|
|
|
|
if kind == MetadataKind::None {
|
2018-06-27 14:57:25 +00:00
|
|
|
return EncodedMetadata::new();
|
2013-12-22 22:40:03 +00:00
|
|
|
}
|
2013-06-13 07:19:50 +00:00
|
|
|
|
2018-08-18 10:08:06 +00:00
|
|
|
let metadata = tcx.encode_metadata();
|
2016-10-19 01:06:46 +00:00
|
|
|
if kind == MetadataKind::Uncompressed {
|
2018-06-27 14:57:25 +00:00
|
|
|
return metadata;
|
2016-10-19 01:06:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
assert!(kind == MetadataKind::Compressed);
|
2017-09-07 20:21:46 +00:00
|
|
|
let mut compressed = tcx.metadata_encoding_version();
|
2017-12-29 10:24:38 +00:00
|
|
|
DeflateEncoder::new(&mut compressed, Compression::fast())
|
2017-06-08 21:10:36 +00:00
|
|
|
.write_all(&metadata.raw_data).unwrap();
|
2015-11-20 23:08:09 +00:00
|
|
|
|
2018-09-06 21:44:51 +00:00
|
|
|
let llmeta = common::bytes_in_context(metadata_llcx, &compressed);
|
|
|
|
let llconst = common::struct_in_context(metadata_llcx, &[llmeta], false);
|
2018-03-05 16:41:11 +00:00
|
|
|
let name = exported_symbols::metadata_symbol_name(tcx);
|
2015-02-18 06:47:40 +00:00
|
|
|
let buf = CString::new(name).unwrap();
|
2014-11-25 21:28:35 +00:00
|
|
|
let llglobal = unsafe {
|
2018-09-06 21:44:51 +00:00
|
|
|
llvm::LLVMAddGlobal(metadata_llmod, common::val_ty(llconst), buf.as_ptr())
|
2014-11-25 21:28:35 +00:00
|
|
|
};
|
2013-01-11 05:23:07 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMSetInitializer(llglobal, llconst);
|
2017-04-26 21:22:45 +00:00
|
|
|
let section_name = metadata::metadata_section_name(&tcx.sess.target.target);
|
2018-08-07 14:04:34 +00:00
|
|
|
let name = SmallCStr::new(section_name);
|
2016-08-14 08:16:28 +00:00
|
|
|
llvm::LLVMSetSection(llglobal, name.as_ptr());
|
|
|
|
|
|
|
|
// Also generate a .section directive to force no
|
|
|
|
// flags, at least for ELF outputs, so that the
|
|
|
|
// metadata doesn't get loaded into memory.
|
|
|
|
let directive = format!(".section {}", section_name);
|
|
|
|
let directive = CString::new(directive).unwrap();
|
2017-04-13 15:48:19 +00:00
|
|
|
llvm::LLVMSetModuleInlineAsm(metadata_llmod, directive.as_ptr())
|
2013-01-11 05:23:07 +00:00
|
|
|
}
|
2018-06-27 14:57:25 +00:00
|
|
|
return metadata;
|
2011-06-27 23:09:28 +00:00
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub struct ValueIter<'ll> {
|
|
|
|
cur: Option<&'ll Value>,
|
|
|
|
step: unsafe extern "C" fn(&'ll Value) -> Option<&'ll Value>,
|
2015-08-21 07:41:07 +00:00
|
|
|
}
|
2014-08-01 17:29:44 +00:00
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
impl Iterator for ValueIter<'ll> {
|
|
|
|
type Item = &'ll Value;
|
2014-08-01 17:29:44 +00:00
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
fn next(&mut self) -> Option<&'ll Value> {
|
2015-08-21 07:41:07 +00:00
|
|
|
let old = self.cur;
|
2018-07-10 10:28:39 +00:00
|
|
|
if let Some(old) = old {
|
2015-10-18 00:15:26 +00:00
|
|
|
self.cur = unsafe { (self.step)(old) };
|
2015-08-21 07:41:07 +00:00
|
|
|
}
|
2018-07-10 10:28:39 +00:00
|
|
|
old
|
2014-08-01 17:29:44 +00:00
|
|
|
}
|
2015-08-21 07:41:07 +00:00
|
|
|
}
|
2014-08-01 17:29:44 +00:00
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn iter_globals(llmod: &'ll llvm::Module) -> ValueIter<'ll> {
|
2015-08-21 07:41:07 +00:00
|
|
|
unsafe {
|
|
|
|
ValueIter {
|
|
|
|
cur: llvm::LLVMGetFirstGlobal(llmod),
|
|
|
|
step: llvm::LLVMGetNextGlobal,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-01-02 04:54:03 +00:00
|
|
|
|
2018-10-27 12:29:06 +00:00
|
|
|
pub fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
2018-08-20 11:42:07 +00:00
|
|
|
cgu_name: InternedString)
|
|
|
|
-> Stats {
|
2017-09-14 03:26:39 +00:00
|
|
|
let start_time = Instant::now();
|
2018-08-20 11:42:07 +00:00
|
|
|
|
|
|
|
let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
|
|
|
|
let ((stats, module), _) = tcx.dep_graph.with_task(dep_node,
|
|
|
|
tcx,
|
|
|
|
cgu_name,
|
2019-01-20 04:44:02 +00:00
|
|
|
module_codegen,
|
|
|
|
dep_graph::hash_result);
|
2018-05-08 13:10:16 +00:00
|
|
|
let time_to_codegen = start_time.elapsed();
|
2017-09-14 03:26:39 +00:00
|
|
|
|
|
|
|
// We assume that the cost to run LLVM on a CGU is proportional to
|
2018-05-08 13:10:16 +00:00
|
|
|
// the time we needed for codegenning it.
|
|
|
|
let cost = time_to_codegen.as_secs() * 1_000_000_000 +
|
|
|
|
time_to_codegen.subsec_nanos() as u64;
|
2017-09-14 03:26:39 +00:00
|
|
|
|
2018-10-23 15:01:35 +00:00
|
|
|
submit_codegened_module_to_llvm(&LlvmCodegenBackend(()), tcx, module, cost);
|
2017-09-14 03:26:39 +00:00
|
|
|
return stats;
|
|
|
|
|
2018-09-26 15:00:01 +00:00
|
|
|
fn module_codegen<'ll, 'tcx>(
|
|
|
|
tcx: TyCtxt<'ll, 'tcx, 'tcx>,
|
2018-08-20 11:42:07 +00:00
|
|
|
cgu_name: InternedString)
|
2018-09-25 15:52:03 +00:00
|
|
|
-> (Stats, ModuleCodegen<ModuleLlvm>)
|
2017-09-14 03:26:39 +00:00
|
|
|
{
|
2018-09-26 15:00:01 +00:00
|
|
|
let backend = LlvmCodegenBackend(());
|
2018-08-20 11:42:07 +00:00
|
|
|
let cgu = tcx.codegen_unit(cgu_name);
|
2018-05-08 13:10:16 +00:00
|
|
|
// Instantiate monomorphizations without filling out definitions yet...
|
2018-10-27 12:29:06 +00:00
|
|
|
let llvm_module = backend.new_metadata(tcx, &cgu_name.as_str());
|
2018-06-27 14:57:25 +00:00
|
|
|
let stats = {
|
2018-09-27 13:31:20 +00:00
|
|
|
let cx = CodegenCx::new(tcx, cgu, &llvm_module);
|
2018-05-08 13:10:16 +00:00
|
|
|
let mono_items = cx.codegen_unit
|
2018-08-20 11:42:07 +00:00
|
|
|
.items_in_deterministic_order(cx.tcx);
|
2018-05-08 13:10:16 +00:00
|
|
|
for &(mono_item, (linkage, visibility)) in &mono_items {
|
2018-11-16 11:48:26 +00:00
|
|
|
mono_item.predefine::<Builder>(&cx, linkage, visibility);
|
2017-09-14 03:26:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ... and now that we have everything pre-defined, fill out those definitions.
|
2018-05-08 13:10:16 +00:00
|
|
|
for &(mono_item, _) in &mono_items {
|
2018-11-16 11:48:26 +00:00
|
|
|
mono_item.define::<Builder>(&cx);
|
2017-09-14 03:26:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// If this codegen unit contains the main function, also create the
|
|
|
|
// wrapper here
|
2018-11-16 11:48:26 +00:00
|
|
|
maybe_create_entry_wrapper::<Builder>(&cx);
|
2017-09-14 03:26:39 +00:00
|
|
|
|
|
|
|
// Run replace-all-uses-with for statics that need it
|
2018-09-26 15:00:01 +00:00
|
|
|
for &(old_g, new_g) in cx.statics_to_rauw().borrow().iter() {
|
2018-11-16 11:33:28 +00:00
|
|
|
unsafe {
|
2018-11-24 13:18:13 +00:00
|
|
|
let bitcast = llvm::LLVMConstPointerCast(new_g, cx.val_ty(old_g));
|
|
|
|
llvm::LLVMReplaceAllUsesWith(old_g, bitcast);
|
|
|
|
llvm::LLVMDeleteGlobal(old_g);
|
2018-11-16 11:33:28 +00:00
|
|
|
}
|
2017-09-14 03:26:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create the llvm.used variable
|
|
|
|
// This variable has type [N x i8*] and is stored in the llvm.metadata section
|
2018-09-26 15:00:01 +00:00
|
|
|
if !cx.used_statics().borrow().is_empty() {
|
|
|
|
cx.create_used_variable()
|
2017-09-14 03:26:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Finalize debuginfo
|
2018-07-26 17:41:10 +00:00
|
|
|
if cx.sess().opts.debuginfo != DebugInfo::None {
|
2018-09-26 15:00:01 +00:00
|
|
|
cx.debuginfo_finalize();
|
2017-09-14 03:26:39 +00:00
|
|
|
}
|
|
|
|
|
2018-09-26 15:00:01 +00:00
|
|
|
cx.consume_stats().into_inner()
|
2017-09-14 03:26:39 +00:00
|
|
|
};
|
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
(stats, ModuleCodegen {
|
2018-08-20 11:42:07 +00:00
|
|
|
name: cgu_name.to_string(),
|
2018-08-20 15:13:01 +00:00
|
|
|
module_llvm: llvm_module,
|
2018-06-27 14:57:25 +00:00
|
|
|
kind: ModuleKind::Regular,
|
|
|
|
})
|
2017-09-14 03:26:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-03 11:49:57 +00:00
|
|
|
pub fn set_link_section(llval: &Value, attrs: &CodegenFnAttrs) {
|
|
|
|
let sect = match attrs.link_section {
|
|
|
|
Some(name) => name,
|
|
|
|
None => return,
|
2018-02-10 22:28:17 +00:00
|
|
|
};
|
2018-10-03 11:49:57 +00:00
|
|
|
unsafe {
|
|
|
|
let buf = SmallCStr::new(§.as_str());
|
|
|
|
llvm::LLVMSetSection(llval, buf.as_ptr());
|
|
|
|
}
|
2017-09-13 22:24:13 +00:00
|
|
|
}
|
|
|
|
|
2017-09-12 18:04:46 +00:00
|
|
|
pub fn linkage_to_llvm(linkage: Linkage) -> llvm::Linkage {
|
|
|
|
match linkage {
|
|
|
|
Linkage::External => llvm::Linkage::ExternalLinkage,
|
|
|
|
Linkage::AvailableExternally => llvm::Linkage::AvailableExternallyLinkage,
|
|
|
|
Linkage::LinkOnceAny => llvm::Linkage::LinkOnceAnyLinkage,
|
|
|
|
Linkage::LinkOnceODR => llvm::Linkage::LinkOnceODRLinkage,
|
|
|
|
Linkage::WeakAny => llvm::Linkage::WeakAnyLinkage,
|
|
|
|
Linkage::WeakODR => llvm::Linkage::WeakODRLinkage,
|
|
|
|
Linkage::Appending => llvm::Linkage::AppendingLinkage,
|
|
|
|
Linkage::Internal => llvm::Linkage::InternalLinkage,
|
|
|
|
Linkage::Private => llvm::Linkage::PrivateLinkage,
|
|
|
|
Linkage::ExternalWeak => llvm::Linkage::ExternalWeakLinkage,
|
|
|
|
Linkage::Common => llvm::Linkage::CommonLinkage,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility {
|
|
|
|
match linkage {
|
|
|
|
Visibility::Default => llvm::Visibility::Default,
|
|
|
|
Visibility::Hidden => llvm::Visibility::Hidden,
|
|
|
|
Visibility::Protected => llvm::Visibility::Protected,
|
2017-09-18 10:14:52 +00:00
|
|
|
}
|
2017-09-07 14:11:58 +00:00
|
|
|
}
|