Repository navigation
add core::arch::{x86, x86_64}::x87_f80 - #163992
folkertdev wants to merge 5 commits into
Conversation
This comment has been minimized.
This comment has been minimized.
b4fafc4 to
16b2882
Compare
This comment has been minimized.
This comment has been minimized.
16b2882 to
617db2d
Compare
617db2d to
d582ca8
Compare
|
Some changes occurred in compiler/rustc_attr_ir cc @jdonszelmann, @JonathanBrouwer
cc @bjorn3 Some changes occurred to the CTFE / Miri interpreter cc @rust-lang/miri Some changes occurred to the CTFE machinery This PR changes rustc_public cc @oli-obk, @celinval, @ouz-a, @makai410
|
|
@bors try jobs=test-various,test-i686-* |
This comment has been minimized.
This comment has been minimized.
add `core::arch::{x86, x86_64}::x87_f80`
try-job: test-various
try-job: test-i686-*
d582ca8 to
a9a37a4
Compare
"f80" is 128 bits large on 64-bit targets...?!?? How does that make any sense?
I'd be surprised if we didn't. That's been pretty much part of the definition of being a scalar -- if a type has padding, it is not a scalar type. The interpreter was built around that assumption. It does not sound to me like this type can be a scalar, then. |
| // For `x87_f80` the primitive is 80 bits, but the field (after rounding up to | ||
| // the alignment) is 12 bytes (on 32-bit systems) or 16 bytes (64-bit). | ||
| // So we can't assert equality of size and layout.size. | ||
| assert_eq!( | ||
| size.align_to(s.default_align(self).abi), | ||
| mplace.layout.size, | ||
| "abi::Scalar is larger than its layout" | ||
| ); |
There was a problem hiding this comment.
The entire logic for dealing with scalars throughout the interpreter assumes that they have no padding. Changing this assertion is not enough, it just means the rest of the interpreter is now more or less silently wrong. Pretty much all codepaths that deal with scalars need to be audited. Same for every other MIR consumer.
I would strongly prefer if we didn't break the fundamental concept of a "scalar".
There was a problem hiding this comment.
To give just one example, here's one place we make that assumption:
rust/compiler/rustc_const_eval/src/interpret/place.rs
Lines 792 to 794 in 6aaabbb
You can't even see it. But if you look at the ScalarPair path you can see that we have to ensure that padding gets reset to uninit, and in the Scalar path we don't have to worry about that.
Also, the basic APIs for reading/writing stuff in an Allocation are read_scalar/write_scalar. This again uses the term "scalar" to refer to something that has no padding. Same for the type Scalar. And so on.
|
It would probably be possible, with a lot of effort, to fix all the places where we assume scalars have no padding. But I think that's a bad idea. It makes life harder for every MIR consumer. (Most likely it'll mean many MIR consumers will stay buggy as nobody will expect something as outlandish as this weird type.) This new type is the weird one here, we should not shape everything around a legacy type that hardly anyone needs and that has no justification to exist in the first place other than "it has always been here". |
|
I think it might make sense to introduce something like |
|
For Rust's purposes could we just pretend it's a |
458a970 to
96a7143
Compare
| // ALIGN4: %"minicore::arch::x86::x87_f80" = type { [10 x i8], [2 x i8] } | ||
| // ALIGN4: %WrappedStruct = type { %"minicore::arch::x86::x87_f80", i8, [3 x i8] } | ||
| // | ||
| // ALIGN16: %"minicore::arch::{{x86|x86_64}}::x87_f80" = type { [10 x i8], [6 x i8] } | ||
| // ALIGN16: %WrappedStruct = type { %"minicore::arch::{{x86|x86_64}}::x87_f80", i8, [15 x i8] } |
There was a problem hiding this comment.
Not the most intuitive, but I guess it works.
| cx.type_padding_filler(element_ty.size * count, Align::ONE) | ||
| } else { | ||
| cx.type_array(element_ty.llvm_type(cx), count) | ||
| } |
There was a problem hiding this comment.
This is a bit ugly. We could have element_ty.is_x87_f80_raw I guess, is that worth it?
96a7143 to
1f53623
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
| // ALIGN4: @WRAPPED = external global [12 x i8] | ||
| // ALIGN4: @WRAPPED_ARRAY = external global [36 x i8] | ||
| // ALIGN4: @WRAPPED_STRUCT = external global [16 x i8] | ||
| // | ||
| // ALIGN16: @WRAPPED = external global [16 x i8] | ||
| // ALIGN16: @WRAPPED_ARRAY = external global [48 x i8] | ||
| // ALIGN16: @WRAPPED_STRUCT = external global [32 x i8] |
There was a problem hiding this comment.
I've updated these now that #165371 has been merged
|
Just noting that we should probably have @RalfJung's ack on the current approach |
|
Absolutely. I think at this point the |
There was a problem hiding this comment.
Could you add the assertion in CastTarget::llvm_type that I mentioned in #163992 (comment).
There was a problem hiding this comment.
This should be if cls.contains(&Some(Class::X87)) { [...] } else { [...] }, as the if cls.contains(&Some(Class::X87)) changes cls_or_mem to Err(Memory).
|
The doc comments above |
|
Also could you update the PR description to reflect the current state of the PR. I think the bit about breaking invariants no longer applies? |
1f53623 to
5b52d2c
Compare
| /// For sized types, this is the in-memory type that is used for stores and loads. | ||
| /// The type used for immediates may be different, see [`Self::immediate_llvm_type`]. |
There was a problem hiding this comment.
We can workshop this some more. I did just remove the line about the pointer type, it's blatantly wrong and didn't really fit in the reformatted text.
| /// The backend type used for a rust type when it is being loaded from or | ||
| /// stored to memory. | ||
| /// | ||
| /// Note that this type may be different from the type used for allocas. | ||
| /// For instance for x87_f80 the store size and allocation size is different, | ||
| /// so different types are used to represent it in memory versus on the stack. |
There was a problem hiding this comment.
We basically never use a typed alloca any more (only for scalable vectors from what I can find), so really the point here is more the size than the exact type.
But intuitively talking about allocas concretely makes more sense to me than "stack allocation".
| @@ -209,4 +215,4 @@ | |||
| if rest_count == 1 && !self.rest.is_consecutive { | |||
| return rest_ll_unit; | |||
| } | |||
|
|
|||
| @@ -217,6 +223,11 @@ | |||
| let prefix_args = self.prefix.iter().map(|reg| reg.llvm_type(cx)); | |||
| let rest_args = (0..rest_count).map(|_| rest_ll_unit); | |||
| let args: Vec<_> = prefix_args.chain(rest_args).collect(); | |||
|
|
|||
| // The x87_f80 type has a store size of 10 bytes, but an allocation size of 12 or 16 bytes. | |||
| // Ensure we don't cast to it, because that could have unintened behavior. | |||
| assert!(args.iter().all(|a| *a != cx.type_x87_f80())); | |||
|
|
|||
There was a problem hiding this comment.
is this what you had in mind for the assert!s?
This comment has been minimized.
This comment has been minimized.
|
|
||
| // The x87_f80 type has a store size of 10 bytes, but an allocation size of 12 or 16 bytes. | ||
| // Ensure we don't cast to it, because that could have unintened behavior. | ||
| assert!(rest_ll_unit != cx.type_x87_f80()); |
There was a problem hiding this comment.
Is it worth introducing a more central predicate like equal_store_and_alloc_size or so?
There was a problem hiding this comment.
Ideally I don't think anywhere in the compiler should be relying on the alloc size of what is returned from llvm_type, so I don't think we should add a method that encourages people to rely on it (the compiler has been moving towards using [size x i8] when an LLVM type is needed for its allocation size) - the only reason the assert is needed now is that load_cast/store_cast directly load/store the LLVM aggregate to/from the scratch space (loading/storing LLVM aggregates is generally something that should be avoided). I plan to fix load_cast/store_cast to not do that, at which point this assertion can be removed, but didn't want to block this PR on it.
Is the interpreter exercised with the new type (e.g. via Miri)? |
| if rest_count == 1 && !self.rest.is_consecutive { | ||
| return rest_ll_unit; | ||
| } | ||
|
|
There was a problem hiding this comment.
The assert!(rest_ll_unit != cx.type_x87_f80()); needs to be here - the allocation size is only a problem at the moment when it's in an LLVM struct or array (as we currently just tell LLVM to load the LLVM struct/array itself unless CastTarget::offset_pair is used).
| pub trait LayoutTypeCodegenMethods<'tcx>: BackendTypes { | ||
| /// The backend type used for a rust type when it's in memory, | ||
| /// such as when it's stack-allocated or when it's being loaded or stored. | ||
| /// The backend type used for a rust type when it is being loaded from or |
There was a problem hiding this comment.
| /// The backend type used for a rust type when it is being loaded from or | |
| /// The backend type used for a Rust type when it is being loaded from or |
5b52d2c to
18ceb9e
Compare
View all comments
tracking issue: #163982
cc #161787
Add
x87_f80in the same way asf16bandppcf128.It's unclear what to do with this type on softfloat targets. Clang and GCC reject the type when the x87 registers are not available. We should do the same, probably just with a
cfg?I don't think we have a good
cfgfor this though?x87is still set on softfloat targets, whilesoft-floatdoesn't get set (that does not give a warning even, it probably should?). We also don't setcfg_abi.future work
Complex<x87_f80>has not yet been implementedx87_f80does not yet implementVaArgSafe