Skip to content

Commit 9900a6a

Browse files
committed
Auto merge of #67954 - nikic:new-pm, r=<try>
[WIP] Support new LLVM pass manager This is a prototype to add support for the new LLVM pass manager. For now this is only for the optimization phase. Closes #64289. r? @ghost
2 parents ef92009 + d2959c3 commit 9900a6a

File tree

13 files changed

+332
-46
lines changed

13 files changed

+332
-46
lines changed

src/librustc_codegen_llvm/back/write.rs

+66-24
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,18 @@ pub fn to_llvm_opt_settings(
111111
}
112112
}
113113

114+
pub fn to_pass_builder_opt_level(cfg: config::OptLevel) -> llvm::PassBuilderOptLevel {
115+
use config::OptLevel::*;
116+
match cfg {
117+
No => llvm::PassBuilderOptLevel::O0,
118+
Less => llvm::PassBuilderOptLevel::O1,
119+
Default => llvm::PassBuilderOptLevel::O2,
120+
Aggressive => llvm::PassBuilderOptLevel::O3,
121+
Size => llvm::PassBuilderOptLevel::Os,
122+
SizeMin => llvm::PassBuilderOptLevel::Oz,
123+
}
124+
}
125+
114126
// If find_features is true this won't access `sess.crate_types` by assuming
115127
// that `is_pie_binary` is false. When we discover LLVM target features
116128
// `sess.crate_types` is uninitialized so we cannot access it.
@@ -327,6 +339,58 @@ pub(crate) unsafe fn optimize(
327339
}
328340

329341
if let Some(opt_level) = config.opt_level {
342+
if config.new_llvm_pass_manager {
343+
let unroll_loops =
344+
opt_level != config::OptLevel::Size && opt_level != config::OptLevel::SizeMin;
345+
let prepare_for_thin_lto = cgcx.lto == Lto::Thin
346+
|| cgcx.lto == Lto::ThinLocal
347+
|| (cgcx.lto != Lto::Fat && cgcx.opts.cg.linker_plugin_lto.enabled());
348+
let using_thin_buffers = prepare_for_thin_lto || config.bitcode_needed();
349+
350+
let pgo_gen_path = match config.pgo_gen {
351+
SwitchWithOptPath::Enabled(ref opt_dir_path) => {
352+
let path = if let Some(dir_path) = opt_dir_path {
353+
dir_path.join("default_%m.profraw")
354+
} else {
355+
PathBuf::from("default_%m.profraw")
356+
};
357+
358+
Some(CString::new(format!("{}", path.display())).unwrap())
359+
}
360+
SwitchWithOptPath::Disabled => None,
361+
};
362+
let pgo_use_path = config
363+
.pgo_use
364+
.as_ref()
365+
.map(|path_buf| CString::new(path_buf.to_string_lossy().as_bytes()).unwrap());
366+
367+
// FIXME: NewPM doesn't seem to have a facility to provide custom InlineParams.
368+
// FIXME: Support extra passes.
369+
llvm::LLVMRustOptimizeWithNewPassManager(
370+
llmod,
371+
tm,
372+
to_pass_builder_opt_level(opt_level),
373+
config.no_prepopulate_passes,
374+
config.verify_llvm_ir,
375+
prepare_for_thin_lto,
376+
/* prepare_for_lto */ false, // FIXME: Actually differentiate this?
377+
using_thin_buffers,
378+
config.merge_functions,
379+
unroll_loops,
380+
config.vectorize_slp,
381+
config.vectorize_loop,
382+
config.no_builtins,
383+
Some(Sanitizer::Memory) == config.sanitizer,
384+
Some(Sanitizer::Thread) == config.sanitizer,
385+
Some(Sanitizer::Address) == config.sanitizer,
386+
config.sanitizer.as_ref().map_or(false, |s| config.sanitizer_recover.contains(s)),
387+
config.sanitizer_memory_track_origins as c_int,
388+
pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
389+
pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
390+
);
391+
return Ok(());
392+
}
393+
330394
// Create the two optimizing pass managers. These mirror what clang
331395
// does, and are by populated by LLVM's default PassManagerBuilder.
332396
// Each manager has a different set of passes, but they also share
@@ -346,8 +410,6 @@ pub(crate) unsafe fn optimize(
346410
}
347411

348412
let mut extra_passes = Vec::new();
349-
let mut have_name_anon_globals_pass = false;
350-
351413
for pass_name in &config.passes {
352414
if pass_name == "lint" {
353415
// Linting should also be performed early, directly on the generated IR.
@@ -360,10 +422,6 @@ pub(crate) unsafe fn optimize(
360422
} else {
361423
diag_handler.warn(&format!("unknown pass `{}`, ignoring", pass_name));
362424
}
363-
364-
if pass_name == "name-anon-globals" {
365-
have_name_anon_globals_pass = true;
366-
}
367425
}
368426

369427
add_sanitizer_passes(config, &mut extra_passes);
@@ -389,33 +447,17 @@ pub(crate) unsafe fn optimize(
389447
llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm);
390448
});
391449

392-
have_name_anon_globals_pass = have_name_anon_globals_pass || prepare_for_thin_lto;
393450
if using_thin_buffers && !prepare_for_thin_lto {
394451
llvm::LLVMRustAddPass(mpm, find_pass("name-anon-globals").unwrap());
395-
have_name_anon_globals_pass = true;
396452
}
397453
} else {
398454
// If we don't use the standard pipeline, directly populate the MPM
399455
// with the extra passes.
400456
for pass in extra_passes {
401457
llvm::LLVMRustAddPass(mpm, pass);
402458
}
403-
}
404-
405-
if using_thin_buffers && !have_name_anon_globals_pass {
406-
// As described above, this will probably cause an error in LLVM
407-
if config.no_prepopulate_passes {
408-
diag_handler.err(
409-
"The current compilation is going to use thin LTO buffers \
410-
without running LLVM's NameAnonGlobals pass. \
411-
This will likely cause errors in LLVM. Consider adding \
412-
-C passes=name-anon-globals to the compiler command line.",
413-
);
414-
} else {
415-
bug!(
416-
"We are using thin LTO buffers without running the NameAnonGlobals pass. \
417-
This will likely cause errors in LLVM and should never happen."
418-
);
459+
if using_thin_buffers {
460+
llvm::LLVMRustAddPass(mpm, find_pass("name-anon-globals").unwrap());
419461
}
420462
}
421463
}

src/librustc_codegen_llvm/builder.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -780,13 +780,18 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
780780
align: Align,
781781
flags: MemFlags,
782782
) {
783-
let ptr_width = &self.sess().target.target.target_pointer_width;
784-
let intrinsic_key = format!("llvm.memset.p0i8.i{}", ptr_width);
785-
let llintrinsicfn = self.get_intrinsic(&intrinsic_key);
783+
let is_volatile = flags.contains(MemFlags::VOLATILE);
786784
let ptr = self.pointercast(ptr, self.type_i8p());
787-
let align = self.const_u32(align.bytes() as u32);
788-
let volatile = self.const_bool(flags.contains(MemFlags::VOLATILE));
789-
self.call(llintrinsicfn, &[ptr, fill_byte, size, align, volatile], None);
785+
unsafe {
786+
llvm::LLVMRustBuildMemSet(
787+
self.llbuilder,
788+
ptr,
789+
align.bytes() as c_uint,
790+
fill_byte,
791+
size,
792+
is_volatile,
793+
);
794+
}
790795
}
791796

792797
fn select(
@@ -984,11 +989,11 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
984989
}
985990

986991
fn lifetime_start(&mut self, ptr: &'ll Value, size: Size) {
987-
self.call_lifetime_intrinsic("llvm.lifetime.start", ptr, size);
992+
self.call_lifetime_intrinsic("llvm.lifetime.start.p0i8", ptr, size);
988993
}
989994

990995
fn lifetime_end(&mut self, ptr: &'ll Value, size: Size) {
991-
self.call_lifetime_intrinsic("llvm.lifetime.end", ptr, size);
996+
self.call_lifetime_intrinsic("llvm.lifetime.end.p0i8", ptr, size);
992997
}
993998

994999
fn call(

src/librustc_codegen_llvm/context.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -543,10 +543,6 @@ impl CodegenCx<'b, 'tcx> {
543543
t_v8f64: t_f64, 8;
544544
}
545545

546-
ifn!("llvm.memset.p0i8.i16", fn(i8p, t_i8, t_i16, t_i32, i1) -> void);
547-
ifn!("llvm.memset.p0i8.i32", fn(i8p, t_i8, t_i32, t_i32, i1) -> void);
548-
ifn!("llvm.memset.p0i8.i64", fn(i8p, t_i8, t_i64, t_i32, i1) -> void);
549-
550546
ifn!("llvm.trap", fn() -> void);
551547
ifn!("llvm.debugtrap", fn() -> void);
552548
ifn!("llvm.frameaddress", fn(t_i32) -> i8p);
@@ -811,8 +807,8 @@ impl CodegenCx<'b, 'tcx> {
811807
ifn!("llvm.usub.sat.i64", fn(t_i64, t_i64) -> t_i64);
812808
ifn!("llvm.usub.sat.i128", fn(t_i128, t_i128) -> t_i128);
813809

814-
ifn!("llvm.lifetime.start", fn(t_i64, i8p) -> void);
815-
ifn!("llvm.lifetime.end", fn(t_i64, i8p) -> void);
810+
ifn!("llvm.lifetime.start.p0i8", fn(t_i64, i8p) -> void);
811+
ifn!("llvm.lifetime.end.p0i8", fn(t_i64, i8p) -> void);
816812

817813
ifn!("llvm.expect.i1", fn(i1, i1) -> i1);
818814
ifn!("llvm.eh.typeid.for", fn(i8p) -> t_i32);

src/librustc_codegen_llvm/llvm/ffi.rs

+41
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,17 @@ pub enum CodeGenOptLevel {
402402
Aggressive,
403403
}
404404

405+
/// LLVMPassBuilderOptLevel
406+
#[repr(C)]
407+
pub enum PassBuilderOptLevel {
408+
O0,
409+
O1,
410+
O2,
411+
O3,
412+
Os,
413+
Oz,
414+
}
415+
405416
/// LLVMRelocMode
406417
#[derive(Copy, Clone, PartialEq)]
407418
#[repr(C)]
@@ -1317,6 +1328,14 @@ extern "C" {
13171328
Size: &'a Value,
13181329
IsVolatile: bool,
13191330
) -> &'a Value;
1331+
pub fn LLVMRustBuildMemSet(
1332+
B: &Builder<'a>,
1333+
Dst: &'a Value,
1334+
DstAlign: c_uint,
1335+
Val: &'a Value,
1336+
Size: &'a Value,
1337+
IsVolatile: bool,
1338+
) -> &'a Value;
13201339
pub fn LLVMBuildSelect(
13211340
B: &Builder<'a>,
13221341
If: &'a Value,
@@ -1886,6 +1905,28 @@ extern "C" {
18861905
Output: *const c_char,
18871906
FileType: FileType,
18881907
) -> LLVMRustResult;
1908+
pub fn LLVMRustOptimizeWithNewPassManager(
1909+
M: &'a Module,
1910+
TM: &'a TargetMachine,
1911+
OptLevel: PassBuilderOptLevel,
1912+
NoPrepopulatePasses: bool,
1913+
VerifyIR: bool,
1914+
PrepareForThinLTO: bool,
1915+
PrepareForLTO: bool,
1916+
UseThinLTOBuffers: bool,
1917+
MergeFunctions: bool,
1918+
UnrollLoops: bool,
1919+
SLPVectorize: bool,
1920+
LoopVectorize: bool,
1921+
DisableSimplifyLibCalls: bool,
1922+
SanitizeMemory: bool,
1923+
SanitizeThread: bool,
1924+
SanitizeAddress: bool,
1925+
SanitizeRecover: bool,
1926+
SanitizeMemoryTrackOrigins: c_int,
1927+
PGOGenPath: *const c_char,
1928+
PGOUsePath: *const c_char,
1929+
);
18891930
pub fn LLVMRustPrintModule(
18901931
M: &'a Module,
18911932
Output: *const c_char,

src/librustc_codegen_ssa/back/write.rs

+3
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ pub struct ModuleConfig {
8585
pub vectorize_slp: bool,
8686
pub merge_functions: bool,
8787
pub inline_threshold: Option<usize>,
88+
pub new_llvm_pass_manager: bool,
8889
// Instead of creating an object file by doing LLVM codegen, just
8990
// make the object file bitcode. Provides easy compatibility with
9091
// emscripten's ecc compiler, when used as the linker.
@@ -129,6 +130,7 @@ impl ModuleConfig {
129130
vectorize_slp: false,
130131
merge_functions: false,
131132
inline_threshold: None,
133+
new_llvm_pass_manager: false,
132134
}
133135
}
134136

@@ -137,6 +139,7 @@ impl ModuleConfig {
137139
self.no_prepopulate_passes = sess.opts.cg.no_prepopulate_passes;
138140
self.no_builtins = no_builtins || sess.target.target.options.no_builtins;
139141
self.inline_threshold = sess.opts.cg.inline_threshold;
142+
self.new_llvm_pass_manager = sess.opts.debugging_opts.new_llvm_pass_manager;
140143
self.obj_is_bitcode =
141144
sess.target.target.options.obj_is_bitcode || sess.opts.cg.linker_plugin_lto.enabled();
142145
let embed_bitcode =

src/librustc_session/options.rs

+2
Original file line numberDiff line numberDiff line change
@@ -948,4 +948,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
948948
(such as entering an empty infinite loop) by inserting llvm.sideeffect"),
949949
deduplicate_diagnostics: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
950950
"deduplicate identical diagnostics"),
951+
new_llvm_pass_manager: bool = (true, parse_bool, [TRACKED],
952+
"use new LLVM pass manager"),
951953
}

0 commit comments

Comments
 (0)