Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions compiler/rustc_codegen_llvm/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,13 +335,13 @@ pub(crate) fn save_temp_bitcode(
&module.name,
cgcx.invocation_temp.as_deref(),
);
write_bitcode_to_file(module, &path)
write_bitcode_to_file(&module.module_llvm, &path)
}

fn write_bitcode_to_file(module: &ModuleCodegen<ModuleLlvm>, path: &Path) {
fn write_bitcode_to_file(module: &ModuleLlvm, path: &Path) {
unsafe {
let path = path_to_c_string(&path);
let llmod = module.module_llvm.llmod();
let llmod = module.llmod();
llvm::LLVMWriteBitcodeToFile(llmod, path.as_ptr());
}
}
Expand Down Expand Up @@ -905,13 +905,8 @@ pub(crate) fn optimize(
let _handlers =
DiagnosticHandlers::new(cgcx, shared_emitter, llcx, module, CodegenDiagnosticsStage::Opt);

if config.emit_no_opt_bc {
let out = cgcx.output_filenames.temp_path_ext_for_cgu(
"no-opt.bc",
&module.name,
cgcx.invocation_temp.as_deref(),
);
write_bitcode_to_file(module, &out)
if module.kind == ModuleKind::Regular {
save_temp_bitcode(cgcx, module, "no-opt");
}

// FIXME(ZuseZ4): support SanitizeHWAddress and prevent illegal/unsupported opts
Expand Down
32 changes: 7 additions & 25 deletions compiler/rustc_codegen_llvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,24 +79,18 @@ pub(crate) use macros::TryFromU32;
#[derive(Clone)]
pub struct LlvmCodegenBackend(());

struct TimeTraceProfiler {
enabled: bool,
}
struct TimeTraceProfiler {}

impl TimeTraceProfiler {
fn new(enabled: bool) -> Self {
if enabled {
unsafe { llvm::LLVMRustTimeTraceProfilerInitialize() }
}
TimeTraceProfiler { enabled }
fn new() -> Self {
unsafe { llvm::LLVMRustTimeTraceProfilerInitialize() }
TimeTraceProfiler {}
}
}

impl Drop for TimeTraceProfiler {
fn drop(&mut self) {
if self.enabled {
unsafe { llvm::LLVMRustTimeTraceProfilerFinishThread() }
}
unsafe { llvm::LLVMRustTimeTraceProfilerFinishThread() }
}
}

Expand Down Expand Up @@ -131,20 +125,8 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
back::write::target_machine_factory(sess, optlvl, target_features)
}

fn spawn_named_thread<F, T>(
time_trace: bool,
name: String,
f: F,
) -> std::io::Result<std::thread::JoinHandle<T>>
where
F: FnOnce() -> T,
F: Send + 'static,
T: Send + 'static,
{
std::thread::Builder::new().name(name).spawn(move || {
let _profiler = TimeTraceProfiler::new(time_trace);
f()
})
fn thread_profiler() -> Box<dyn Any> {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use Box<dyn Any>? I feel like it makes more sense to return TimeTraceProfiler, and then using Option<TimeTraceProfiler> at the call sites? Is there a reason that this needs to be on the heap?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TimeTraceProfiler is defined in cg_llvm, while thread_profiler is part of a trait defined in cg_ssa.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kk then it's fine as-is

Copy link
Copy Markdown
Member Author

@bjorn3 bjorn3 Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kk then it's fine as-is

Does that count as an r=jackh726?

Box::new(TimeTraceProfiler::new())
}
}

Expand Down
31 changes: 20 additions & 11 deletions compiler/rustc_codegen_ssa/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ pub struct ModuleConfig {

// Flags indicating which outputs to produce.
pub emit_pre_lto_bc: bool,
pub emit_no_opt_bc: bool,
pub emit_bc: bool,
pub emit_ir: bool,
pub emit_asm: bool,
Expand Down Expand Up @@ -195,7 +194,6 @@ impl ModuleConfig {
save_temps || need_pre_lto_bitcode_for_incr_comp(sess),
false
),
emit_no_opt_bc: if_regular!(save_temps, false),
emit_bc: if_regular!(
save_temps || sess.opts.output_types.contains_key(&OutputType::Bitcode),
save_temps
Expand Down Expand Up @@ -1472,7 +1470,9 @@ fn start_executing_work<B: ExtraBackendMethods>(
// Each LLVM module is automatically sent back to the coordinator for LTO if
// necessary. There's already optimizations in place to avoid sending work
// back to the coordinator if LTO isn't requested.
return B::spawn_named_thread(cgcx.time_trace, "coordinator".to_string(), move || {
let f = move || {
let _profiler = if cgcx.time_trace { B::thread_profiler() } else { Box::new(()) };

// This is where we collect codegen units that have gone all the way
// through codegen and LLVM.
let mut compiled_modules = vec![];
Expand Down Expand Up @@ -1813,8 +1813,11 @@ fn start_executing_work<B: ExtraBackendMethods>(
B::codegen(&cgcx, &prof, &shared_emitter, allocator_module, &allocator_config)
}),
}))
})
.expect("failed to spawn coordinator thread");
};
return std::thread::Builder::new()
.name("coordinator".to_owned())
.spawn(f)
.expect("failed to spawn coordinator thread");

// A heuristic that determines if we have enough LLVM WorkItems in the
// queue so that the main thread can do LLVM work instead of codegen
Expand Down Expand Up @@ -1893,7 +1896,10 @@ fn spawn_work<'a, B: ExtraBackendMethods>(
let cgcx = cgcx.clone();
let prof = prof.clone();

B::spawn_named_thread(cgcx.time_trace, work.short_description(), move || {
let name = work.short_description();
let f = move || {
let _profiler = if cgcx.time_trace { B::thread_profiler() } else { Box::new(()) };

let result = std::panic::catch_unwind(AssertUnwindSafe(|| match work {
WorkItem::Optimize(m) => execute_optimize_work_item(&cgcx, &prof, shared_emitter, m),
WorkItem::CopyPostLtoArtifacts(m) => WorkItemResult::Finished(
Expand All @@ -1914,8 +1920,8 @@ fn spawn_work<'a, B: ExtraBackendMethods>(
Err(_) => Message::WorkItem::<B> { result: Err(None) },
};
drop(coordinator_send.send(msg));
})
.expect("failed to spawn work thread");
};
std::thread::Builder::new().name(name).spawn(f).expect("failed to spawn work thread");
}

fn spawn_thin_lto_work<B: ExtraBackendMethods>(
Expand All @@ -1929,7 +1935,10 @@ fn spawn_thin_lto_work<B: ExtraBackendMethods>(
let cgcx = cgcx.clone();
let prof = prof.clone();

B::spawn_named_thread(cgcx.time_trace, work.short_description(), move || {
let name = work.short_description();
let f = move || {
let _profiler = if cgcx.time_trace { B::thread_profiler() } else { Box::new(()) };

let result = std::panic::catch_unwind(AssertUnwindSafe(|| match work {
ThinLtoWorkItem::CopyPostLtoArtifacts(m) => {
execute_copy_from_cache_work_item(&cgcx, &prof, shared_emitter, m)
Expand All @@ -1952,8 +1961,8 @@ fn spawn_thin_lto_work<B: ExtraBackendMethods>(
Err(_) => ThinLtoMessage::WorkItem { result: Err(None) },
};
drop(coordinator_send.send(msg));
})
.expect("failed to spawn work thread");
};
std::thread::Builder::new().name(name).spawn(f).expect("failed to spawn work thread");
}

enum SharedEmitterMessage {
Expand Down
13 changes: 2 additions & 11 deletions compiler/rustc_codegen_ssa/src/traits/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,17 +165,8 @@ pub trait ExtraBackendMethods:
target_features: &[String],
) -> TargetMachineFactoryFn<Self>;

fn spawn_named_thread<F, T>(
_time_trace: bool,
name: String,
f: F,
) -> std::io::Result<std::thread::JoinHandle<T>>
where
F: FnOnce() -> T,
F: Send + 'static,
T: Send + 'static,
{
std::thread::Builder::new().name(name).spawn(f)
fn thread_profiler() -> Box<dyn Any> {
Box::new(())
}

/// Returns `true` if this backend can be safely called from multiple threads.
Expand Down