@@ -111,6 +111,18 @@ pub fn to_llvm_opt_settings(
111111 }
112112}
113113
114+ 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.
@@ -303,6 +315,88 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
303315 }
304316}
305317
318+ fn get_pgo_gen_path ( config : & ModuleConfig ) -> Option < CString > {
319+ match config. pgo_gen {
320+ SwitchWithOptPath :: Enabled ( ref opt_dir_path) => {
321+ let path = if let Some ( dir_path) = opt_dir_path {
322+ dir_path. join ( "default_%m.profraw" )
323+ } else {
324+ PathBuf :: from ( "default_%m.profraw" )
325+ } ;
326+
327+ Some ( CString :: new ( format ! ( "{}" , path. display( ) ) ) . unwrap ( ) )
328+ }
329+ SwitchWithOptPath :: Disabled => None ,
330+ }
331+ }
332+
333+ fn get_pgo_use_path ( config : & ModuleConfig ) -> Option < CString > {
334+ config
335+ . pgo_use
336+ . as_ref ( )
337+ . map ( |path_buf| CString :: new ( path_buf. to_string_lossy ( ) . as_bytes ( ) ) . unwrap ( ) )
338+ }
339+
340+ pub ( crate ) fn should_use_new_llvm_pass_manager ( config : & ModuleConfig ) -> bool {
341+ // We only support the new pass manager starting with LLVM 9.
342+ if llvm_util:: get_major_version ( ) < 9 {
343+ return false ;
344+ }
345+
346+ // The new pass manager is disabled by default.
347+ config. new_llvm_pass_manager . unwrap_or ( false )
348+ }
349+
350+ pub ( crate ) unsafe fn optimize_with_new_llvm_pass_manager (
351+ module : & ModuleCodegen < ModuleLlvm > ,
352+ config : & ModuleConfig ,
353+ opt_level : config:: OptLevel ,
354+ opt_stage : llvm:: OptStage ,
355+ ) {
356+ let unroll_loops =
357+ opt_level != config:: OptLevel :: Size && opt_level != config:: OptLevel :: SizeMin ;
358+ let using_thin_buffers = opt_stage == llvm:: OptStage :: PreLinkThinLTO || config. bitcode_needed ( ) ;
359+ let pgo_gen_path = get_pgo_gen_path ( config) ;
360+ let pgo_use_path = get_pgo_use_path ( config) ;
361+ let is_lto = opt_stage == llvm:: OptStage :: ThinLTO || opt_stage == llvm:: OptStage :: FatLTO ;
362+ // Sanitizer instrumentation is only inserted during the pre-link optimization stage.
363+ let sanitizer_options = if !is_lto {
364+ config. sanitizer . as_ref ( ) . map ( |s| llvm:: SanitizerOptions {
365+ sanitize_memory : * s == Sanitizer :: Memory ,
366+ sanitize_thread : * s == Sanitizer :: Thread ,
367+ sanitize_address : * s == Sanitizer :: Address ,
368+ sanitize_recover : config. sanitizer_recover . contains ( s) ,
369+ sanitize_memory_track_origins : config. sanitizer_memory_track_origins as c_int ,
370+ } )
371+ } else {
372+ None
373+ } ;
374+
375+ // FIXME: NewPM doesn't provide a facility to pass custom InlineParams.
376+ // We would have to add upstream support for this first, before we can support
377+ // config.inline_threshold and our more aggressive default thresholds.
378+ // FIXME: NewPM uses an different and more explicit way to textually represent
379+ // pass pipelines. It would probably make sense to expose this, but it would
380+ // require a different format than the current -C passes.
381+ llvm:: LLVMRustOptimizeWithNewPassManager (
382+ module. module_llvm . llmod ( ) ,
383+ & * module. module_llvm . tm ,
384+ to_pass_builder_opt_level ( opt_level) ,
385+ opt_stage,
386+ config. no_prepopulate_passes ,
387+ config. verify_llvm_ir ,
388+ using_thin_buffers,
389+ config. merge_functions ,
390+ unroll_loops,
391+ config. vectorize_slp ,
392+ config. vectorize_loop ,
393+ config. no_builtins ,
394+ sanitizer_options. as_ref ( ) ,
395+ pgo_gen_path. as_ref ( ) . map_or ( std:: ptr:: null ( ) , |s| s. as_ptr ( ) ) ,
396+ pgo_use_path. as_ref ( ) . map_or ( std:: ptr:: null ( ) , |s| s. as_ptr ( ) ) ,
397+ ) ;
398+ }
399+
306400// Unsafe due to LLVM calls.
307401pub ( crate ) unsafe fn optimize (
308402 cgcx : & CodegenContext < LlvmCodegenBackend > ,
@@ -327,6 +421,17 @@ pub(crate) unsafe fn optimize(
327421 }
328422
329423 if let Some ( opt_level) = config. opt_level {
424+ if should_use_new_llvm_pass_manager ( config) {
425+ let opt_stage = match cgcx. lto {
426+ Lto :: Fat => llvm:: OptStage :: PreLinkFatLTO ,
427+ Lto :: Thin | Lto :: ThinLocal => llvm:: OptStage :: PreLinkThinLTO ,
428+ _ if cgcx. opts . cg . linker_plugin_lto . enabled ( ) => llvm:: OptStage :: PreLinkThinLTO ,
429+ _ => llvm:: OptStage :: PreLinkNoLTO ,
430+ } ;
431+ optimize_with_new_llvm_pass_manager ( module, config, opt_level, opt_stage) ;
432+ return Ok ( ( ) ) ;
433+ }
434+
330435 // Create the two optimizing pass managers. These mirror what clang
331436 // does, and are by populated by LLVM's default PassManagerBuilder.
332437 // Each manager has a different set of passes, but they also share
@@ -757,24 +862,8 @@ pub unsafe fn with_llvm_pmb(
757862 let opt_size =
758863 config. opt_size . map ( |x| to_llvm_opt_settings ( x) . 1 ) . unwrap_or ( llvm:: CodeGenOptSizeNone ) ;
759864 let inline_threshold = config. inline_threshold ;
760-
761- let pgo_gen_path = match config. pgo_gen {
762- SwitchWithOptPath :: Enabled ( ref opt_dir_path) => {
763- let path = if let Some ( dir_path) = opt_dir_path {
764- dir_path. join ( "default_%m.profraw" )
765- } else {
766- PathBuf :: from ( "default_%m.profraw" )
767- } ;
768-
769- Some ( CString :: new ( format ! ( "{}" , path. display( ) ) ) . unwrap ( ) )
770- }
771- SwitchWithOptPath :: Disabled => None ,
772- } ;
773-
774- let pgo_use_path = config
775- . pgo_use
776- . as_ref ( )
777- . map ( |path_buf| CString :: new ( path_buf. to_string_lossy ( ) . as_bytes ( ) ) . unwrap ( ) ) ;
865+ let pgo_gen_path = get_pgo_gen_path ( config) ;
866+ let pgo_use_path = get_pgo_use_path ( config) ;
778867
779868 llvm:: LLVMRustConfigurePassManagerBuilder (
780869 builder,
0 commit comments