Skip to content
Closed
5 changes: 5 additions & 0 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ fn mir_borrowck(
def: LocalDefId,
) -> Result<&FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'_>>, ErrorGuaranteed> {
assert!(!tcx.is_typeck_child(def.to_def_id()));
if tcx.is_trivial_const(def) {
debug!("Skipping borrowck because of trivial const");
let opaque_types = Default::default();
return Ok(tcx.arena.alloc(opaque_types));
}
let (input_body, _) = tcx.mir_promoted(def);
debug!("run query mir_borrowck: {}", tcx.def_path_str(def));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ index 1e336bf..35e6f54 100644
+++ b/coretests/tests/lib.rs
@@ -2,4 +2,3 @@
// tidy-alphabetical-start
#![cfg_attr(not(panic = "abort"), feature(reentrant_lock))]
-#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
#![feature(array_ptr_get)]
#![feature(array_try_from_fn)]
Expand All @@ -36,4 +37,3 @@ index b735957..ea728b6 100644
#[cfg(target_has_atomic = "ptr")]
--
2.26.2.7.g19db9cfb68

4 changes: 2 additions & 2 deletions compiler/rustc_codegen_ssa/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -780,14 +780,14 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
// This likely is a temporary measure. Once we don't have to support the
// non-parallel compiler anymore, we can compile CGUs end-to-end in
// parallel and get rid of the complicated scheduling logic.
let mut pre_compiled_cgus = if tcx.sess.threads() > 1 {
let mut pre_compiled_cgus = if let Some(threads) = tcx.sess.threads() {
tcx.sess.time("compile_first_CGU_batch", || {
// Try to find one CGU to compile per thread.
let cgus: Vec<_> = cgu_reuse
.iter()
.enumerate()
.filter(|&(_, reuse)| reuse == &CguReuse::No)
.take(tcx.sess.threads())
.take(threads)
.collect();

// Compile the found CGUs in parallel.
Expand Down
110 changes: 110 additions & 0 deletions compiler/rustc_index/src/bit_set/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,116 @@ fn chunked_bitset() {
);
}

/// Additional helper methods for testing.
impl ChunkedBitSet<usize> {
/// Creates a new `ChunkedBitSet` containing all `i` for which `fill_fn(i)` is true.
fn fill_with(domain_size: usize, fill_fn: impl Fn(usize) -> bool) -> Self {
let mut this = ChunkedBitSet::new_empty(domain_size);
for i in 0..domain_size {
if fill_fn(i) {
this.insert(i);
}
}
this
}

/// Asserts that for each `i` in `0..self.domain_size()`, `self.contains(i) == expected_fn(i)`.
#[track_caller]
fn assert_filled_with(&self, expected_fn: impl Fn(usize) -> bool) {
for i in 0..self.domain_size() {
let expected = expected_fn(i);
assert_eq!(self.contains(i), expected, "i = {i}");
}
}
}

#[test]
fn chunked_bulk_ops() {
struct ChunkedBulkOp {
name: &'static str,
op_fn: fn(&mut ChunkedBitSet<usize>, &ChunkedBitSet<usize>) -> bool,
spec_fn: fn(fn(usize) -> bool, fn(usize) -> bool, usize) -> bool,
}
let ops = &[
ChunkedBulkOp {
name: "union",
op_fn: ChunkedBitSet::union,
spec_fn: |fizz, buzz, i| fizz(i) || buzz(i),
},
ChunkedBulkOp {
name: "subtract",
op_fn: ChunkedBitSet::subtract,
spec_fn: |fizz, buzz, i| fizz(i) && !buzz(i),
},
ChunkedBulkOp {
name: "intersect",
op_fn: ChunkedBitSet::intersect,
spec_fn: |fizz, buzz, i| fizz(i) && buzz(i),
},
];

let domain_sizes = [
CHUNK_BITS / 7, // Smaller than a full chunk.
CHUNK_BITS,
(CHUNK_BITS + CHUNK_BITS / 7), // Larger than a full chunk.
];

for ChunkedBulkOp { name, op_fn, spec_fn } in ops {
for domain_size in domain_sizes {
// If false, use different values for LHS and RHS, to test "fizz op buzz".
// If true, use identical values, to test "fizz op fizz".
for identical in [false, true] {
// If false, make a clone of LHS before doing the op.
// This covers optimizations that depend on whether chunk words are shared or not.
for unique in [false, true] {
// Print the current test case, so that we can see which one failed.
println!(
"Testing op={name}, domain_size={domain_size}, identical={identical}, unique={unique} ..."
);

let fizz_fn = |i| i % 3 == 0;
let buzz_fn = if identical { fizz_fn } else { |i| i % 5 == 0 };

// Check that `fizz op buzz` gives the expected results.
chunked_bulk_ops_test_inner(
domain_size,
unique,
fizz_fn,
buzz_fn,
op_fn,
|i| spec_fn(fizz_fn, buzz_fn, i),
);
}
}
}
}
}

fn chunked_bulk_ops_test_inner(
domain_size: usize,
unique: bool,
fizz_fn: impl Fn(usize) -> bool + Copy,
buzz_fn: impl Fn(usize) -> bool + Copy,
op_fn: impl Fn(&mut ChunkedBitSet<usize>, &ChunkedBitSet<usize>) -> bool,
expected_fn: impl Fn(usize) -> bool + Copy,
) {
// Create two bitsets, "fizz" (LHS) and "buzz" (RHS).
let mut fizz = ChunkedBitSet::fill_with(domain_size, fizz_fn);
let buzz = ChunkedBitSet::fill_with(domain_size, buzz_fn);

// If requested, clone `fizz` so that its word Rcs are not uniquely-owned.
let _cloned = (!unique).then(|| fizz.clone());

// Perform the op (e.g. union/subtract/intersect), and verify that the
// mutated LHS contains exactly the expected values.
let changed = op_fn(&mut fizz, &buzz);
fizz.assert_filled_with(expected_fn);

// Verify that the "changed" return value is correct.
let should_change = (0..domain_size).any(|i| fizz_fn(i) != expected_fn(i));
assert_eq!(changed, should_change);
}

fn with_elements_chunked(elements: &[usize], domain_size: usize) -> ChunkedBitSet<usize> {
let mut s = ChunkedBitSet::new_empty(domain_size);
for &e in elements {
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_interface/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,9 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
trace!("run_compiler");

// Set parallel mode before thread pool creation, which will create `Lock`s.
rustc_data_structures::sync::set_dyn_thread_safe_mode(config.opts.unstable_opts.threads > 1);
rustc_data_structures::sync::set_dyn_thread_safe_mode(
config.opts.unstable_opts.threads.is_some(),
);

// Check jobserver before run_in_thread_pool_with_globals, which call jobserver::acquire_thread
let early_dcx = EarlyDiagCtxt::new(config.opts.error_format);
Expand All @@ -407,7 +409,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
util::run_in_thread_pool_with_globals(
&early_dcx,
config.opts.edition,
config.opts.unstable_opts.threads,
config.opts.unstable_opts.threads.unwrap_or(1),
&config.extra_symbols,
SourceMapInputs { file_loader, path_mapping, hash_kind, checksum_hash_kind },
|current_gcx, jobserver_proxy| {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,7 @@ fn test_unstable_options_tracking_hash() {
untracked!(span_debug, true);
untracked!(span_free_formats, true);
untracked!(temps_dir, Some(String::from("abc")));
untracked!(threads, 99);
untracked!(threads, Some(99));
untracked!(time_llvm_passes, true);
untracked!(time_passes, true);
untracked!(time_passes_format, TimePassesFormat::Json);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2465,7 +2465,7 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path, ref_path: Option<&Path>) {
return;
};

if tcx.sess.threads() != 1 {
if tcx.sess.threads().is_some() {
// Prefetch some queries used by metadata encoding.
// This is not necessary for correctness, but is only done for performance reasons.
// It can be removed if it turns out to cause trouble or be detrimental to performance.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/dep_graph/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ impl DepGraphData {
let ok = match color {
DepNodeColor::Unknown => true,
DepNodeColor::Red => false,
DepNodeColor::Green(..) => sess.threads() > 1, // Other threads may mark this green
DepNodeColor::Green(..) => sess.threads().is_some(), // Other threads may mark this green
};
if !ok {
panic!("{}", msg())
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/trivial_const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ where
return None;
}

if !tcx.opaque_types_defined_by(def).is_empty() {
return None;
}

let body = body_provider();

if body.has_opaque_types() {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_query_impl/src/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ fn try_execute_query<'tcx, C: QueryCache, const INCR: bool>(
// re-executing the query since `try_start` only checks that the query is not currently
// executing, but another thread may have already completed the query and stores it result
// in the query cache.
if tcx.sess.threads() > 1 {
if tcx.sess.threads().is_some() {
if let Some((value, index)) = query.cache.lookup(&key) {
tcx.prof.query_cache_hit(index.into());
return (value, Some(index));
Expand Down
6 changes: 1 addition & 5 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2494,11 +2494,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
cg.codegen_units,
);

if unstable_opts.threads == 0 {
early_dcx.early_fatal("value for threads must be a positive non-zero integer");
}

if unstable_opts.threads == parse::MAX_THREADS_CAP {
if unstable_opts.threads == Some(parse::MAX_THREADS_CAP) {
early_dcx.early_warn(format!("number of threads was capped at {}", parse::MAX_THREADS_CAP));
}

Expand Down
33 changes: 17 additions & 16 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,7 @@ mod desc {
pub(crate) const parse_number: &str = "a number";
pub(crate) const parse_opt_number: &str = parse_number;
pub(crate) const parse_frame_pointer: &str = "one of `true`/`yes`/`on`, `false`/`no`/`off`, or (with -Zunstable-options) `non-leaf` or `always`";
pub(crate) const parse_threads: &str = parse_number;
pub(crate) const parse_threads: &str = "a number or `sync`";
pub(crate) const parse_time_passes_format: &str = "`text` (default) or `json`";
pub(crate) const parse_passes: &str = "a space-separated list of passes, or `all`";
pub(crate) const parse_panic_strategy: &str = "either `unwind`, `abort`, or `immediate-abort`";
Expand Down Expand Up @@ -1067,22 +1067,23 @@ pub mod parse {
}
}

pub(crate) fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
let ret = match v.and_then(|s| s.parse().ok()) {
Some(0) => {
*slot = std::thread::available_parallelism().map_or(1, NonZero::<usize>::get);
true
}
Some(i) => {
*slot = i;
true
}
None => false,
pub(crate) fn parse_threads(slot: &mut Option<usize>, v: Option<&str>) -> bool {
let Some(s) = v else { return false };
if s == "sync" {
// Enable synchronization despite only using one thread.
*slot = Some(1);
return true;
}
let n = match s.parse().ok() {
Some(0) => std::thread::available_parallelism().map_or(1, NonZero::<usize>::get),
Some(i) => i,
None => return false,
};
// We want to cap the number of threads here to avoid large numbers like 999999 and compiler panics.
// This solution was suggested here https://github.com/rust-lang/rust/issues/117638#issuecomment-1800925067
*slot = slot.clone().min(MAX_THREADS_CAP);
ret
let n = n.min(MAX_THREADS_CAP);
*slot = (n > 1).then_some(n); // Enable synchronization if we're using more than one thread.
true
}

/// Use this for any numeric option that has a static default.
Expand Down Expand Up @@ -2672,12 +2673,12 @@ written to standard error output)"),
#[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")]
thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
"enable ThinLTO when possible"),
/// We default to 1 here since we want to behave like
/// We default to None here since we want to behave like
/// a sequential compiler for now. This'll likely be adjusted
/// in the future. Note that -Zthreads=0 is the way to get
/// the num_cpus behavior.
#[rustc_lint_opt_deny_field_access("use `Session::threads` instead of this field")]
threads: usize = (1, parse_threads, [UNTRACKED],
threads: Option<usize> = (None, parse_threads, [UNTRACKED],
"use a thread pool with N threads"),
time_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
"measure time of each LLVM pass (default: no)"),
Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -813,10 +813,12 @@ impl Session {
.unwrap_or(self.panic_strategy().unwinds() || self.target.default_uwtable)
}

/// Returns the number of query threads that should be used for this
/// compilation
/// Returns the number of threads used for the thread pool.
///
/// `None` means thread pool is not used and synchronization is disabled.
/// `Some(n)` means synchronization is enabled with `n` worker threads.
#[inline]
pub fn threads(&self) -> usize {
pub fn threads(&self) -> Option<usize> {
self.opts.unstable_opts.threads
}

Expand Down
Loading
Loading