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

Forward the ABI of the non-zero sized fields of an union if they have the same ABI #55834

Merged
merged 2 commits into from
Nov 19, 2018
Merged

Conversation

ogoffart
Copy link
Contributor

@ogoffart ogoffart commented Nov 9, 2018

This is supposed to fix the performence regression of using MaybeUninit in
#54668

@rust-highfive
Copy link
Collaborator

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @varkor (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see the contribution instructions for more information.

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Nov 9, 2018
@varkor
Copy link
Member

varkor commented Nov 9, 2018

r? @eddyb

@rust-highfive rust-highfive assigned eddyb and unassigned varkor Nov 9, 2018
if abi == Abi::Uninhabited || size == Size::ZERO {
abi = field.abi.clone();
} else if field.size != Size::ZERO && abi != field.abi {
abi = Abi::Aggregate{ sized: true };
Copy link
Member

Choose a reason for hiding this comment

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

Missing space before {.

size = cmp::max(size, field.size);
}

// Use scalar_unit to reset the valid range to the maximal one
// since an union might not be initialised
Copy link
Member

Choose a reason for hiding this comment

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

Need to do this before comparing field.abi above with abi, so we never compare ranges.

@eddyb
Copy link
Member

eddyb commented Nov 10, 2018

cc @rkruppe @nagisa @RalfJung

@@ -697,6 +697,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
}

let mut size = Size::ZERO;
let mut abi = Abi::Uninhabited;
Copy link
Member

Choose a reason for hiding this comment

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

What is the meaining of this initial value?

Notice that a union should NOT be uninhabited even if all of its fields are! That would also be a form of "propagating ranges".

Copy link
Member

@RalfJung RalfJung Nov 10, 2018

Choose a reason for hiding this comment

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

Ah, you are using it as a sentinel value for "no non-ZST field found yet". This warrants a comment. However, we should also never use the Uninhabited layout on unions. So maybe better use an Option here, initialized to None?

Copy link
Member

Choose a reason for hiding this comment

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

I think I prefer Option too.

_ => field.abi.clone(),
};

if abi == Abi::Uninhabited || size == Size::ZERO {
Copy link
Member

@RalfJung RalfJung Nov 10, 2018

Choose a reason for hiding this comment

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

Why is this checking for the size of the entire thing? Or whatever else size is?

Copy link
Member

Choose a reason for hiding this comment

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

Ah, size seems to be the size of the largest field so far. That's worth a comment.
I also do not understand why we need two conditions here, shouldn't this simply be "if we have not set an abi yet"? So, shouldn't the Uninhabited test be enough?

Generally, all this new code needs a comment explaining its purpose.

Copy link
Member

Choose a reason for hiding this comment

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

The size check is for PhantomData. I think we can remove the Uninhabited test, since no fields means size is 0 anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we can remove the Uninhabited test, since no fields means size is 0 anyway.

Is (u32, UninhabitedEnum) Uninhabited? What's its size?

Copy link
Member

Choose a reason for hiding this comment

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

It is uninhabited at has size 4. Also see #49298.

scalar_unit(y.value),
)
}
_ => field.abi.clone(),
Copy link
Member

Choose a reason for hiding this comment

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

After this normalization, the ABI is sure to permit all bit patterns, right? There are no restrictions about what can be stored e.g. in a vector ABI type?

src/librustc/ty/layout.rs Outdated Show resolved Hide resolved
@ogoffart
Copy link
Contributor Author

@RalfJung thanks for your review. I fixed the uninhabited case, and added some comments.

src/librustc/ty/layout.rs Outdated Show resolved Hide resolved
src/librustc/ty/layout.rs Outdated Show resolved Hide resolved
@RalfJung
Copy link
Member

Looks good to me now, but I also have hardly any knowledge about layout computation.

@eddyb
Copy link
Member

eddyb commented Nov 10, 2018

LGTM but I'd like at least of @nagisa or @rkruppe to also sign off on it.

Copy link
Member

@RalfJung RalfJung left a comment

Choose a reason for hiding this comment

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

Fine for me, though I think using Option would be clearer.


pub union UnionI64x4I64{ a: i64x4, b: i64 }

// CHECK: define void @test_UnionI64x4I64(%UnionI64x4I64* {{.*}}, %UnionI64x4I64* {{.*}} %arg0)
Copy link
Contributor

Choose a reason for hiding this comment

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

Some of these CHECK lines seem to assume aggregates are passed as in the x86_64 SysV ABI, so if I'm not mistaken they'll fail on some other platforms. See the repr(transparent) codegen tests for what it takes to cover all/most of our targets.

Copy link
Member

Choose a reason for hiding this comment

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

Ironically, the Rust default "ABI" (i.e. fn instead of extern fn) would be more consistent, in that we always pass the inner scalars for Scalar / ScalarPair.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, I only tested on x86_64, because that's the only arch i have. (and the test is based of the repr-transparent.rs test.) I guess this check and the next one are architecture specific. What should i do? Just remove them? Or move them somewhere else?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I used the rust ABI and removed the return value for these tests.

Copy link
Contributor

Choose a reason for hiding this comment

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

What the repr(transparent) tests do is separate tests for each variation of how the C ABI encodes aggregates in LLVM signatures. But that's because for repr(transparent) it's important that it matches the C ABI. This PR, by contrast, is mostly about the Rust ABI and mostly about unions that shouldn't be passed as aggregates. So I don't think it needs as comprehensive coverage of extern "C" as the repr(transparent) tests, as long as we have tests somewhere that ensure that repr(C) unions are passed correctly in extern "C" calls. As long as that is true (@eddyb do you know?) I think it doesn't matter very much.

@eddyb
Copy link
Member

eddyb commented Nov 10, 2018

Hang on, are we checking whether the repr is C or not?
I don't think we can do this optimization for repr(C) unions.

@ogoffart
Copy link
Contributor Author

I just disabled the optimisation for repr(C) union. (but i don't know how i can test them: simd are not repr(c), what else would make a difference?)

@eddyb
Copy link
Member

eddyb commented Nov 10, 2018

An union with a large scalar (e.g. u128) should be passed as an u32 in the Rust ABI, but if you add #[repr(C)] to it, it should be passed by indirection.

@eddyb
Copy link
Member

eddyb commented Nov 11, 2018

@RalfJung There's a method about "are optimizations allowed" on AdtDef that we could check.

@ogoffart
Copy link
Contributor Author

I found ReprOptions::inhibit_enum_layout_opt and ReprOptions::inhibit_struct_field_reordering_opt . I could use inhibit_enum_layout_opt, since the second condition does not matter for unions, but that's not really a good name. Or I could add in impl ReprOptions

    pub fn inhibit_union_opt(&self) -> bool {
        self.c()
    }

if we want to have all the inhibit options at the same place. Should I do that?

@eddyb
Copy link
Member

eddyb commented Nov 11, 2018

@ogoffart I think that's good. Kind of surprised there's not a more general method in there.

All struct-related optimizations (including the newtype ABI ones!) appear to use:

let mut optimize = !repr.inhibit_struct_field_reordering_opt();

Maybe the name should be inhibit_field_abi_opt?

@bors
Copy link
Contributor

bors commented Nov 13, 2018

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

@ogoffart
Copy link
Contributor Author

Please resolve the merge conflicts

Should I rebase, or merge?

@nagisa
Copy link
Member

nagisa commented Nov 13, 2018 via email

@eddyb
Copy link
Member

eddyb commented Nov 15, 2018

@bors r+

@bors
Copy link
Contributor

bors commented Nov 15, 2018

📌 Commit c040a48 has been approved by eddyb

@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-review Status: Awaiting review from the assignee but also interested parties. labels Nov 15, 2018
pietroalbini added a commit to pietroalbini/rust that referenced this pull request Nov 15, 2018
Forward the ABI of the non-zero sized fields of an union if they have the same ABI

This is supposed to fix the performence regression of using MaybeUninit in
rust-lang#54668
kennytm added a commit to kennytm/rust that referenced this pull request Nov 17, 2018
Forward the ABI of the non-zero sized fields of an union if they have the same ABI

This is supposed to fix the performence regression of using MaybeUninit in
rust-lang#54668
@bors
Copy link
Contributor

bors commented Nov 18, 2018

⌛ Testing commit c040a48 with merge f5a924d58abe287646f5f02ae22c5dc8153548c2...

@bors
Copy link
Contributor

bors commented Nov 18, 2018

💔 Test failed - status-appveyor

@bors bors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Nov 18, 2018
@kennytm
Copy link
Member

kennytm commented Nov 18, 2018

@bors retry #56034

@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-review Status: Awaiting review from the assignee but also interested parties. labels Nov 18, 2018
pietroalbini added a commit to pietroalbini/rust that referenced this pull request Nov 18, 2018
Forward the ABI of the non-zero sized fields of an union if they have the same ABI

This is supposed to fix the performence regression of using MaybeUninit in
rust-lang#54668
bors added a commit that referenced this pull request Nov 19, 2018
Rollup of 25 pull requests

Successful merges:

 - #55562 (Add powerpc- and powerpc64-unknown-linux-musl targets)
 - #55564 (test/linkage-visibility: Ignore on musl targets)
 - #55827 (A few tweaks to iterations/collecting)
 - #55834 (Forward the ABI of the non-zero sized fields of an union if they have the same ABI)
 - #55857 (remove unused dependency)
 - #55862 (in which the E0618 "expected function" diagnostic gets a makeover)
 - #55867 (do not panic just because cargo failed)
 - #55894 (miri enum discriminant handling: Fix treatment of pointers, better error when it is undef)
 - #55916 (Make miri value visitor usfeful for mutation)
 - #55919 (core/tests/num: Simplify `test_int_from_str_overflow()` test code)
 - #55923 (reword #[test] attribute error on fn items)
 - #55935 (appveyor: Use VS2017 for all our images)
 - #55949 (ty: return impl Iterator from Predicate::walk_tys)
 - #55952 (Update to Clang 7 on CI.)
 - #55953 (#53488 Refactoring UpvarId)
 - #55962 (rustdoc: properly calculate spans for intra-doc link resolution errors)
 - #55963 (Stress test for MPSC)
 - #55968 (Clean up some non-mod-rs stuff.)
 - #55970 (Miri backtrace improvements)
 - #56007 (CTFE: dynamically make sure we do not call non-const-fn)
 - #56011 (Replace data.clone() by Arc::clone(&data) in mutex doc.)
 - #56012 (avoid shared ref in UnsafeCell::get)
 - #56016 (Add VecDeque::resize_with)
 - #56027 (docs: Add missing backtick in object_safety.rs docs)
 - #56043 (remove "approx env bounds" if we already know from trait)

Failed merges:

r? @ghost
bors added a commit that referenced this pull request Nov 19, 2018
Rollup of 25 pull requests

Successful merges:

 - #55562 (Add powerpc- and powerpc64-unknown-linux-musl targets)
 - #55564 (test/linkage-visibility: Ignore on musl targets)
 - #55827 (A few tweaks to iterations/collecting)
 - #55834 (Forward the ABI of the non-zero sized fields of an union if they have the same ABI)
 - #55857 (remove unused dependency)
 - #55862 (in which the E0618 "expected function" diagnostic gets a makeover)
 - #55867 (do not panic just because cargo failed)
 - #55894 (miri enum discriminant handling: Fix treatment of pointers, better error when it is undef)
 - #55916 (Make miri value visitor useful for mutation)
 - #55919 (core/tests/num: Simplify `test_int_from_str_overflow()` test code)
 - #55923 (reword #[test] attribute error on fn items)
 - #55949 (ty: return impl Iterator from Predicate::walk_tys)
 - #55952 (Update to Clang 7 on CI.)
 - #55953 (#53488 Refactoring UpvarId)
 - #55962 (rustdoc: properly calculate spans for intra-doc link resolution errors)
 - #55963 (Stress test for MPSC)
 - #55968 (Clean up some non-mod-rs stuff.)
 - #55970 (Miri backtrace improvements)
 - #56007 (CTFE: dynamically make sure we do not call non-const-fn)
 - #56011 (Replace data.clone() by Arc::clone(&data) in mutex doc.)
 - #56012 (avoid shared ref in UnsafeCell::get)
 - #56016 (Add VecDeque::resize_with)
 - #56027 (docs: Add missing backtick in object_safety.rs docs)
 - #56043 (remove "approx env bounds" if we already know from trait)
 - #56059 (Increase `Duration` approximate equal threshold to 1us)
@bors bors merged commit c040a48 into rust-lang:master Nov 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants