Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

don't allow ZST in ScalarInt #98957

Merged
merged 4 commits into from
Jul 9, 2022
Merged

Conversation

RalfJung
Copy link
Member

@RalfJung RalfJung commented Jul 5, 2022

There are several indications that we should not ZST as a ScalarInt:

  • We had two ways to have ZST valtrees, either an empty Branch or a Leaf with a ZST in it.
    ValTree::zst() used the former, but the latter could possibly arise as well.
  • Likewise, the interpreter had Immediate::Uninit and Immediate::Scalar(Scalar::ZST).
  • LLVM codegen already had to special-case ZST ScalarInt.

So I propose we stop using ScalarInt to represent ZST (which are clearly not integers). Instead, we can add new ZST variants to those types that did not have other variants which could be used for this purpose.

Based on #98831. Only the commits starting from "don't allow ZST in ScalarInt" are new.

r? @oli-obk

@rustbot rustbot added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Jul 5, 2022
@rustbot
Copy link
Collaborator

rustbot commented Jul 5, 2022

Some changes occurred to MIR optimizations

cc @rust-lang/wg-mir-opt

Some changes occurred to the CTFE / Miri engine

cc @rust-lang/miri

Some changes occurred in const_evaluatable.rs

cc @lcnr

Some changes occurred to the CTFE / Miri engine

cc @rust-lang/miri

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jul 5, 2022
@rust-log-analyzer

This comment has been minimized.

compiler/rustc_middle/src/mir/interpret/value.rs Outdated Show resolved Hide resolved
@@ -449,6 +449,7 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
}

let fmt_val = |val: &ConstValue<'tcx>| match val {
ConstValue::ZST => format!("ZST"),
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: the value isn't really a zero sized type 😁 idk what else I would want to print here though

probably <ZST> which is what we've done for zero sized scalars before?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, it's a ZSV, a zero-sized value. But we have called the value a ZST for a while now... (there's some red diff in this PR removing a <ZST> elsewhere; I think this will have to cause some test failure somewhere)

Copy link
Member

Choose a reason for hiding this comment

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

If they're not too long, ConstValue::ZeroSized or ConstValue::UnitLike both seem fine to me.

compiler/rustc_middle/src/thir.rs Outdated Show resolved Hide resolved
@RalfJung
Copy link
Member Author

RalfJung commented Jul 5, 2022

What's up with CI? I checked this locally...
... oh, it's in cranelift.

@rustbot
Copy link
Collaborator

rustbot commented Jul 5, 2022

Some changes occurred in compiler/rustc_codegen_cranelift

cc @bjorn3

Some changes occurred in compiler/rustc_codegen_gcc

cc @antoyo

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@@ -167,6 +167,7 @@ pub(crate) fn codegen_const_value<'tcx>(
}

match const_val {
ConstValue::ZST => unreachable!(), // we already handles ZST above
Copy link
Member

Choose a reason for hiding this comment

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

Does layout.is_zst() always imply ConstValue::ZST? If so moving CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout) into this branch will be a tiny bit faster at runtime and reduce compile time of cg_clif itself a bit too.

Copy link
Member Author

Choose a reason for hiding this comment

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

Does layout.is_zst() always imply ConstValue::ZST?

I don't know. There might be by-ref ZST ConstValues.

@RalfJung RalfJung added S-blocked Status: Blocked on something else such as an RFC or other implementation work. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 6, 2022
scope 2 (inlined std::mem::size_of::<()>) { // at $DIR/lower_intrinsics.rs:45:8: 45:32
}
}

bb0: {
StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:34:16: 34:18
StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17
_2 = f_zst::<()>(const ()) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17
StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:46:15: 46:16
_2 = f_zst::<()>(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17
Copy link
Member Author

Choose a reason for hiding this comment

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

No idea why this is not const-propped any more.

Copy link
Contributor

Choose a reason for hiding this comment

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

no idea either, but this could have happened with more complex logic before, too, so it's fine to regress and we'll just have to fix const prop

@bors
Copy link
Contributor

bors commented Jul 6, 2022

☔ The latest upstream changes (presumably #98970) made this pull request unmergeable. Please resolve the merge conflicts.

@RalfJung
Copy link
Member Author

RalfJung commented Jul 7, 2022

Conflicts resolved and all ready. @oli-obk is that const-prop change a problem or expected and fine? If it even is a const-prop change, the pass name says "lower-intrinsics", so maybe const-prop will fix this up again later?

@oli-obk
Copy link
Contributor

oli-obk commented Jul 7, 2022

@bors r=lcnr,oli-obk

@bors
Copy link
Contributor

bors commented Jul 7, 2022

📌 Commit d1dd4879125325c6730f7f40f75e0b28851e9649 has been approved by lcnr,oli-obk

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-blocked Status: Blocked on something else such as an RFC or other implementation work. labels Jul 7, 2022
@RalfJung
Copy link
Member Author

RalfJung commented Jul 9, 2022

Oh, that test is needs-profiler-support. I don't think I can bless this one. I guess I have to do it by hand?

@RalfJung
Copy link
Member Author

RalfJung commented Jul 9, 2022

@bors r=lcnr,oli-obk rollup=never

@bors
Copy link
Contributor

bors commented Jul 9, 2022

📌 Commit 4e7aaf1 has been approved by lcnr,oli-obk

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jul 9, 2022
@bors
Copy link
Contributor

bors commented Jul 9, 2022

⌛ Testing commit 4e7aaf1 with merge f893495...

@bors
Copy link
Contributor

bors commented Jul 9, 2022

☀️ Test successful - checks-actions
Approved by: lcnr,oli-obk
Pushing f893495 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Jul 9, 2022
@bors bors merged commit f893495 into rust-lang:master Jul 9, 2022
@rustbot rustbot added this to the 1.64.0 milestone Jul 9, 2022
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (f893495): comparison url.

Instruction count

  • Primary benchmarks: no relevant changes found
  • Secondary benchmarks: mixed results
mean1 max count2
Regressions 😿
(primary)
N/A N/A 0
Regressions 😿
(secondary)
4.4% 4.4% 2
Improvements 🎉
(primary)
N/A N/A 0
Improvements 🎉
(secondary)
-0.4% -0.4% 2
All 😿🎉 (primary) N/A N/A 0

Max RSS (memory usage)

Results
  • Primary benchmarks: no relevant changes found
  • Secondary benchmarks: 🎉 relevant improvement found
mean1 max count2
Regressions 😿
(primary)
N/A N/A 0
Regressions 😿
(secondary)
N/A N/A 0
Improvements 🎉
(primary)
N/A N/A 0
Improvements 🎉
(secondary)
-5.1% -5.1% 1
All 😿🎉 (primary) N/A N/A 0

Cycles

Results
  • Primary benchmarks: no relevant changes found
  • Secondary benchmarks: mixed results
mean1 max count2
Regressions 😿
(primary)
N/A N/A 0
Regressions 😿
(secondary)
7.4% 11.2% 7
Improvements 🎉
(primary)
N/A N/A 0
Improvements 🎉
(secondary)
-4.0% -5.4% 5
All 😿🎉 (primary) N/A N/A 0

If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf.

Next Steps: If you can justify the regressions found in this perf run, please indicate this with @rustbot label: +perf-regression-triaged along with sufficient written justification. If you cannot justify the regressions please open an issue or create a new PR that fixes the regressions, add a comment linking to the newly created issue or PR, and then add the perf-regression-triaged label to this PR.

@rustbot label: +perf-regression

Footnotes

  1. the arithmetic mean of the percent change 2 3

  2. number of relevant changes 2 3

@rustbot rustbot added the perf-regression Performance regression. label Jul 9, 2022
@RalfJung RalfJung deleted the zst-are-different branch July 9, 2022 22:39
@RalfJung
Copy link
Member Author

RalfJung commented Jul 9, 2022

Oh, that's pretty surprising. It's "only" a secondary benchmark so maybe it's okay...? We get some nice RSS reductions in secondary benchmarks in exchange, it seems. ;)

@RalfJung
Copy link
Member Author

RalfJung commented Jul 11, 2022

FWIW that benchmark has a "large amount of extern functions". I am not quite sure where our Scalar types even come to bear here, but it's probably values of FnDef type, which are now a ConstValue::ZeroSized rather than a scalar integer. I don't see any reason why that would be slower though... and indeed for "full" builds it is slightly faster, but for "incr-full" builds it is slower.

Supposedly, previously there were some NonHirLiteral involved, which used ty::ValTree::from_scalar_int, creating a valtree leaf. Now instead they use ty::ValTree::zst creating a valtree branch with 0 children. This is strictly more correct, we don't want to have two different ways of representing the same thing as a valtree (that would be unsound, probably). But looking at those functions there is really no reason why ty::ValTree::zst should be any slower... maybe it just needs an inline(always)?

I'll wait for the regular perf triage to come visit this PR and tell me whether this is okay or whether we should dig a bit deeper into what is going on.

@oli-obk
Copy link
Contributor

oli-obk commented Jul 12, 2022

  252,778,417  ???:<rustc_middle::dep_graph::dep_node::DepKind as rustc_query_system::dep_graph::DepKind>::read_deps::<<rustc_query_system::dep_graph::graph::DepGraph<rustc_middle::dep_graph::dep_node::DepKind>>::read_index::{closure
 -171,114,000  ???:<rustc_metadata::rmeta::decoder::cstore_impl::provide::{closure
      725,369  ???:<rustc_query_system::dep_graph::graph::DepGraph<rustc_middle::dep_graph::dep_node::DepKind>>::dep_node_exists
     -425,283  ???:<rustc_query_system::dep_graph::graph::DepGraph<rustc_middle::dep_graph::dep_node::DepKind>>::with_task::<rustc_middle::ty::context::TyCtxt, rustc_span::def_id::DefId, bool>
     -246,123  ???:<rustc_middle::hir::provide::{closure
     -107,395  ???:<rustc_query_system::dep_graph::graph::CurrentDepGraph<rustc_middle::dep_graph::dep_node::DepKind>>::intern_node
      -90,051  ???:<alloc::raw_vec::RawVec<rustc_parse::parser::TokenCursorFrame>>::reserve_for_push

looks like inliner noise to me

fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) -> &'ll Value {
let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
match cv {
Scalar::Int(ScalarInt::ZST) => {
assert_eq!(0, layout.size(self).bytes());
Copy link
Member

Choose a reason for hiding this comment

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

So I'm looking at this (in the context of Rust-GPU updating the nightly version of Rust we use).

How could this ever pass? abi::Scalar just can't encode sizes other than 1, 2, 4, 8, 16:

pub enum Integer {
I8,
I16,
I32,
I64,
I128,
}

pub enum Primitive {
/// The `bool` is the signedness of the `Integer` type.
///
/// One would think we would not care about such details this low down,
/// but some ABIs are described in terms of C types and ISAs where the
/// integer arithmetic is done on {sign,zero}-extended registers, e.g.
/// a negative integer passed by zero-extension will appear positive in
/// the callee, and most operations on it will produce the wrong values.
Int(Integer, bool),
F32,
F64,
Pointer,
}

pub enum Scalar {
Initialized {
value: Primitive,
// FIXME(eddyb) always use the shortest range, e.g., by finding
// the largest space between two consecutive valid values and
// taking everything else as the (shortest) valid range.
valid_range: WrappingRange,
},
Union {
/// Even for unions, we need to use the correct registers for the kind of
/// values inside the union, so we keep the `Primitive` type around. We
/// also use it to compute the size of the scalar.
/// However, unions never have niches and even allow undef,
/// so there is no `valid_range`.
value: Primitive,
},
}

Copy link
Member

Choose a reason for hiding this comment

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

This is the const eval Scalar, not abi Scalar.

Copy link
Member Author

Choose a reason for hiding this comment

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

layout is abi::Scalar though.

If you scroll up through this PR there is a comment of mine somewhere saying that this must have been dead code.

@@ -223,13 +222,13 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
})
}

fn zst_to_backend(&self, _llty: &'ll Type) -> &'ll Value {
self.const_undef(self.type_ix(0))
Copy link
Member

Choose a reason for hiding this comment

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

I don't think i0 is a legal LLVM type? At least not according to https://llvm.org/docs/LangRef.html#integer-type

Copy link
Member Author

Choose a reason for hiding this comment

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

I copied this from elsewhere... 🤷

Comment on lines +87 to +90
ConstValue::ZeroSized => {
let llval = bx.zst_to_backend(bx.immediate_backend_type(layout));
OperandValue::Immediate(llval)
}
Copy link
Member

@eddyb eddyb Sep 6, 2022

Choose a reason for hiding this comment

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

If you expand the diff there's a if layout.is_zst() { above, that early-returns, so this should've been unreachable!() without the illegal zst_to_backend implementations existing, looks like.
(and this is the only callsite of zst_to_backend AFAICT)

Copy link
Member

Choose a reason for hiding this comment

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

Though I think I see how this happened, scalar_to_backend had a nonsense Scalar::Int(ScalarInt::ZST) => { case from many years ago (at least 4? I wasn't able to easily go far back enough in git blame).

And this PR just refactored it into a more obvious spot.

JohnTitor added a commit to JohnTitor/rust that referenced this pull request Sep 6, 2022
Remove dead broken code from const zst handling in backends

cc `@RalfJung`

found by `@eddyb` in rust-lang#98957 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. perf-regression Performance regression. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.