@@ -530,14 +530,24 @@ fn get_instr_profile_output_path(config: &ModuleConfig) -> Option<CString> {
530530 config. instrument_coverage . then ( || c"default_%m_%p.profraw" . to_owned ( ) )
531531}
532532
533+ // PreAD will run llvm opts but disable size increasing opts (vectorization, loop unrolling)
534+ // DuringAD is the same as above, but also runs the enzyme opt and autodiff passes.
535+ // PostAD will run all opts, including size increasing opts.
536+ #[ derive( Debug , Eq , PartialEq ) ]
537+ pub ( crate ) enum AutodiffStage {
538+ PreAD ,
539+ DuringAD ,
540+ PostAD ,
541+ }
542+
533543pub ( crate ) unsafe fn llvm_optimize (
534544 cgcx : & CodegenContext < LlvmCodegenBackend > ,
535545 dcx : DiagCtxtHandle < ' _ > ,
536546 module : & ModuleCodegen < ModuleLlvm > ,
537547 config : & ModuleConfig ,
538548 opt_level : config:: OptLevel ,
539549 opt_stage : llvm:: OptStage ,
540- skip_size_increasing_opts : bool ,
550+ autodiff_stage : AutodiffStage ,
541551) -> Result < ( ) , FatalError > {
542552 // Enzyme:
543553 // The whole point of compiler based AD is to differentiate optimized IR instead of unoptimized
@@ -550,7 +560,7 @@ pub(crate) unsafe fn llvm_optimize(
550560 let unroll_loops;
551561 let vectorize_slp;
552562 let vectorize_loop;
553- let run_enzyme;
563+ let run_enzyme = cfg ! ( llvm_enzyme ) && autodiff_stage == AutodiffStage :: DuringAD ;
554564
555565 // When we build rustc with enzyme/autodiff support, we want to postpone size-increasing
556566 // optimizations until after differentiation. Our pipeline is thus: (opt + enzyme), (full opt).
@@ -559,17 +569,15 @@ pub(crate) unsafe fn llvm_optimize(
559569 // FIXME(ZuseZ4): Before shipping on nightly,
560570 // we should make this more granular, or at least check that the user has at least one autodiff
561571 // call in their code, to justify altering the compilation pipeline.
562- if skip_size_increasing_opts && cfg ! ( llvm_enzyme) {
572+ if cfg ! ( llvm_enzyme) && autodiff_stage != AutodiffStage :: PostAD {
563573 unroll_loops = false ;
564574 vectorize_slp = false ;
565575 vectorize_loop = false ;
566- run_enzyme = true ;
567576 } else {
568577 unroll_loops =
569578 opt_level != config:: OptLevel :: Size && opt_level != config:: OptLevel :: SizeMin ;
570579 vectorize_slp = config. vectorize_slp ;
571580 vectorize_loop = config. vectorize_loop ;
572- run_enzyme = false ;
573581 }
574582 trace ! ( ?unroll_loops, ?vectorize_slp, ?vectorize_loop, ?run_enzyme) ;
575583 let using_thin_buffers = opt_stage == llvm:: OptStage :: PreLinkThinLTO || config. bitcode_needed ( ) ;
@@ -691,18 +699,14 @@ pub(crate) unsafe fn optimize(
691699 _ => llvm:: OptStage :: PreLinkNoLTO ,
692700 } ;
693701
694- // If we know that we will later run AD, then we disable vectorization and loop unrolling
695- let skip_size_increasing_opts = cfg ! ( llvm_enzyme) ;
702+ // If we know that we will later run AD, then we disable vectorization and loop unrolling.
703+ // Otherwise we pretend AD is already done and run the normal opt pipeline (=PostAD).
704+ // FIXME(ZuseZ4): Make this more granular, only set PreAD if we actually have autodiff
705+ // usages, not just if we build rustc with autodiff support.
706+ let autodiff_stage =
707+ if cfg ! ( llvm_enzyme) { AutodiffStage :: PreAD } else { AutodiffStage :: PostAD } ;
696708 return unsafe {
697- llvm_optimize (
698- cgcx,
699- dcx,
700- module,
701- config,
702- opt_level,
703- opt_stage,
704- skip_size_increasing_opts,
705- )
709+ llvm_optimize ( cgcx, dcx, module, config, opt_level, opt_stage, autodiff_stage)
706710 } ;
707711 }
708712 Ok ( ( ) )
0 commit comments