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

Store bools as i8 in scalar pairs #51566

Closed
wants to merge 1 commit into from

Conversation

cuviper
Copy link
Member

@cuviper cuviper commented Jun 15, 2018

Rust bool mostly uses the LLVM i1 type for immediate values, and
i8 for memory storage, including most aggregates. Scalar pairs were
an exception, also using i1, but this can cause problems when it is
accessed through a pointer to the pair. This patch changes to use the
memory type for scalar pairs too.

Function argument pairs (PassMode::Pair) pass their pieces like
distinct direct arguments, so for this case we explicitly convert bool
to an immediate i1 type again. This way the function can still
optimize knowing the valid 0..2 range of bool values.

Previously, bool-like enum tags were excluded from scalar pairs,
because the i1 didn't optimize well. Now that we're using i8,
optimization seems fine with this, at least for the repeat-trusted-len
test that was reportedly problematic before.

Fixes #50516.
r? @eddyb

Rust `bool` mostly uses the LLVM `i1` type for immediate values, and
`i8` for memory storage, including most aggregates.  Scalar pairs were
an exception, also using `i1`, but this can cause problems when it is
accessed through a pointer to the pair.  This patch changes to use the
memory type for scalar pairs too.

Function argument pairs (`PassMode::Pair`) pass their pieces like
distinct direct arguments, so for this case we explicitly convert `bool`
to an immediate `i1` type again.  This way the function can still
optimize knowing the valid `0..2` range of `bool` values.

Previously, `bool`-like enum tags were excluded from scalar pairs,
because the `i1` didn't optimize well.  Now that we're using `i8`,
optimization seems fine with this, at least for the repeat-trusted-len
test that was reportedly problematic before.
@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jun 15, 2018
@cuviper
Copy link
Member Author

cuviper commented Jun 15, 2018

cc @nox - this is taking a different direction than you had in #50277.

@eddyb
Copy link
Member

eddyb commented Jun 15, 2018

So this already is more complicated than what I did, but if LLVM is still bad at it... might as well.

However, this is still not enough: OperandValue::ScalarPair should contain i1 because it's in "immediate" mode, and only zext/trunct when packing/unpacking into/from the LLVM aggregate type.
One of the original purposes of ScalarPair was to generate optimal IR for checked arithmetic, so handling bools as immediates is essential.
(also, there are some intrinsics that should maybe be simplified a bit)

This should thankfully be easier nowadays, I believe part of why I didn't do it was the pre-miri LLVM constant creation.

@nox
Copy link
Contributor

nox commented Jun 15, 2018

I wonder how hard it would be to teach SROA about i1 instead.

@cuviper
Copy link
Member Author

cuviper commented Jun 15, 2018

@eddyb - Can you be more specific about what changes you'd like to see here? I'm not sure how to represent the difference you state between the sort-of "immediate" mode and the LLVM aggregate type.

@nox Sure, upstream LLVM improvements would be great, but for a while at least we have to worry about some older LLVM too. (It might be about time to consider raising from 3.9 though -- maybe 5?)

FWIW, that particular aarch64 GlobalIsel bug in #50516 was filed as LLVM bug 37393 and appears to be fixed in trunk, but I'm told that this would not be straightforward to backport.

@eddyb
Copy link
Member

eddyb commented Jun 15, 2018

@cuviper OperandValue::ScalarPair should contain two "immediates" (more specifically, only scalars), with the same rules followed for the value inside OperandValue::Immediate.
immediate_or_packed_pair should zext, while from_immediate_or_packed_pair should trunc, each component of the scalar pair, e.g. converting between ScalarPair(i1 0, i1 1) and { i8 0, i8 1}.

@cuviper
Copy link
Member Author

cuviper commented Jun 15, 2018

OK, thanks, I'll see if I can figure that out.

@pietroalbini pietroalbini 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 Jun 25, 2018
@pietroalbini
Copy link
Member

Marked as blocked on #51583.

@TimNN TimNN added A-allocators Area: Custom and system allocators and removed A-allocators Area: Custom and system allocators labels Jul 3, 2018
bors added a commit that referenced this pull request Jul 10, 2018
Store scalar pair bools as i8 in memory

We represent `bool` as `i1` in a `ScalarPair`, unlike other aggregates,
to optimize IR for checked operators and the like.  With this patch, we
still do so when the pair is an immediate value, but we use the `i8`
memory type when the value is loaded or stored as an LLVM aggregate.

So `(bool, bool)` looks like an `{ i1, i1 }` immediate, but `{ i8, i8 }`
in memory.  When a pair is a direct function argument, `PassMode::Pair`,
it is still passed using the immediate `i1` type, but as a return value
it will use the `i8` memory type.  Also, `bool`-like` enum tags will now
use scalar pairs when possible, where they were previously excluded due
to optimization issues.

Fixes #51516.
Closes #51566.

r? @eddyb
cc @nox
@bors bors closed this in #51583 Jul 10, 2018
@cuviper cuviper deleted the pair-i8-bool branch May 17, 2019 21:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-blocked Status: Blocked on something else such as an RFC or other implementation work.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants