1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use back::archive::ArchiveRO;
use back::link;
use driver::session;
use driver::config;
use lib::llvm::{ModuleRef, TargetMachineRef, llvm, True, False};
use metadata::cstore;
use util::common::time;
use libc;
use flate;
pub fn run(sess: &session::Session, llmod: ModuleRef,
tm: TargetMachineRef, reachable: &[String]) {
if sess.opts.cg.prefer_dynamic {
sess.err("cannot prefer dynamic linking when performing LTO");
sess.note("only 'staticlib' and 'bin' outputs are supported with LTO");
sess.abort_if_errors();
}for crate_type in sess.crate_types.borrow().iter() {
match *crate_type {
config::CrateTypeExecutable | config::CrateTypeStaticlib => {}
_ => {
sess.fatal("lto can only be run for executables and \
static library outputs");
}
}
}let crates = sess.cstore.get_used_crates(cstore::RequireStatic);
for (cnum, path) in crates.move_iter() {
let name = sess.cstore.get_crate_data(cnum).name.clone();
let path = match path {
Some(p) => p,
None => {
sess.fatal(format!("could not find rlib for: `{}`",
name).as_slice());
}
};
let archive = ArchiveRO::open(&path).expect("wanted an rlib");
debug!("reading {}", name);
let bc = time(sess.time_passes(),
format!("read {}.bytecode.deflate", name).as_slice(),
(),
|_| {
archive.read(format!("{}.bytecode.deflate",
name).as_slice())
});
let bc = bc.expect("missing compressed bytecode in archive!");
let bc = time(sess.time_passes(),
format!("inflate {}.bc", name).as_slice(),
(),
|_| {
match flate::inflate_bytes(bc) {
Some(bc) => bc,
None => {
sess.fatal(format!("failed to decompress \
bc of `{}`",
name).as_slice())
}
}
});
let ptr = bc.as_slice().as_ptr();
debug!("linking {}", name);
time(sess.time_passes(),
format!("ll link {}", name).as_slice(),
(),
|()| unsafe {
if !llvm::LLVMRustLinkInExternalBitcode(llmod,
ptr as *libc::c_char,
bc.len() as libc::size_t) {
link::llvm_err(sess,
format!("failed to load bc of `{}`",
name.as_slice()));
}
});
}let cstrs: Vec<::std::c_str::CString> =
reachable.iter().map(|s| s.as_slice().to_c_str()).collect();
let arr: Vec<*i8> = cstrs.iter().map(|c| c.with_ref(|p| p)).collect();
let ptr = arr.as_ptr();
unsafe {
llvm::LLVMRustRunRestrictionPass(llmod, ptr as **libc::c_char,
arr.len() as libc::size_t);
}
if sess.no_landing_pads() {
unsafe {
llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
}
}debug!("running the pass manager");
unsafe {
let pm = llvm::LLVMCreatePassManager();
llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod);
"verify".with_c_str(|s| llvm::LLVMRustAddPass(pm, s));
let builder = llvm::LLVMPassManagerBuilderCreate();
llvm::LLVMPassManagerBuilderPopulateLTOPassManager(builder, pm,False,True);
llvm::LLVMPassManagerBuilderDispose(builder);
"verify".with_c_str(|s| llvm::LLVMRustAddPass(pm, s));
time(sess.time_passes(), "LTO pases", (), |()|
llvm::LLVMRunPassManager(pm, llmod));
llvm::LLVMDisposePassManager(pm);
}
debug!("lto done");
}