1

Transforms match into an assignment statement by DianQK · Pull Request #120614 ·...

 4 weeks ago
source link: https://github.com/rust-lang/rust/pull/120614
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Transforms match into an assignment statement #120614

Conversation

Member

Fixes #106459.

We should be able to do some similar transformations, like enum to enum.

r? mir-opt

rustbot

added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

labels

Feb 3, 2024

This comment has been minimized.

Member

DianQK reacted with heart emoji

This comment has been minimized.

Contributor

⌛ Trying commit 7a47635 with merge eea65f2...

Contributor

☀️ Try build successful - checks-actions
Build commit: eea65f2 (eea65f2f4affd04b3b0fd5127c7e0951a2747136)

This comment has been minimized.

Collaborator

Finished benchmarking commit (eea65f2): comparison URL.

Overall result: no relevant changes - no action needed

Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR may lead to changes in compiler perf.

@bors rollup=never
@rustbot label: -S-waiting-on-perf -perf-regression

Instruction count

This benchmark run did not return any relevant results for this metric.

Max RSS (memory usage)

Results

Cycles

Results

Binary size

Results

Bootstrap: 659.957s -> 661.541s (0.24%)
Artifact size: 308.08 MiB -> 308.11 MiB (0.01%)

rustbot

removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label

Feb 4, 2024

DianQK

marked this pull request as ready for review

February 6, 2024 14:45

Collaborator

Some changes occurred to MIR optimizations

cc @rust-lang/wg-mir-opt

}

trait SimplifyMatch<'tcx> {

fn simplify(

Contributor

Could you comment what this function does?

Member

Author

Done.

let def_id = body.source.def_id();

let param_env = tcx.param_env_reveal_all_normalized(def_id);

let bbs = body.basic_blocks.as_mut();

Contributor

Calling as_mut() clears the CFG caches unconditionally. Is there a way to delay this invalidation?

Member

Author

I submitted a separate commit. I invalidate the cache only after modifying the CFG. If the cache is used later in a loop, we need to invalidate it after each modification.

Member

Author

With MirPatch we don't need to worry about this.

/// goto -> bb5;

/// }

/// ```

impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {

Contributor

IIUC, this transform is a strict superset of SimplifyToIf, isn't it? Can we only keep this one?

Member

Author

Most of their code can't be shared, and if they were put together, I'd be worried that it would be difficult to maintain later. A major difference is that the otherwise target of SimplifyToIf is reachable, while SimplifyToExp is unreachable.

Contributor

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

cjgillot

added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author.

and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.

labels

Feb 18, 2024

oli-obk

removed their assignment

Feb 20, 2024

Member

Author

Sorry for my late reply.
@rustbot ready

Contributor

⌛ Testing commit 755d9e5 with merge ff94dee...

This comment has been minimized.

Contributor

💔 Test failed - checks-actions

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

Apr 7, 2024

This comment has been minimized.

Member

Author

Rebased. :>

Member

@bors r=cjgillot

DianQK reacted with heart emoji

Contributor

📌 Commit f440737 has been approved by cjgillot

It is now in the queue for this repository.

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

Apr 8, 2024

Contributor

⌛ Testing commit f440737 with merge 211518e...

Contributor

☀️ Test successful - checks-actions
Approved by: cjgillot
Pushing 211518e to master...

bors

added the merged-by-bors This PR was explicitly merged by bors. label

Apr 8, 2024

bors

merged commit 211518e into

rust-lang:master

Apr 8, 2024

12 checks passed

rustbot

added this to the 1.79.0 milestone

Apr 8, 2024

DianQK

deleted the simplify-switch-int branch

April 8, 2024 20:51

Collaborator

Finished benchmarking commit (211518e): comparison URL.

Overall result: ❌ regressions - no action needed

@rustbot label: -perf-regression

Instruction count

This is a highly reliable metric that was used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
0.3% [0.3%, 0.3%] 1
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 0.3% [0.3%, 0.3%] 1

Max RSS (memory usage)

Results

Cycles

This benchmark run did not return any relevant results for this metric.

Binary size

Results

Bootstrap: 669.664s -> 668.886s (-0.12%)
Artifact size: 318.23 MiB -> 318.49 MiB (0.08%)

let (from, first, second) = bbs.pick3_mut(bb_idx, first, second);

fn int_equal(l: ScalarInt, r: impl Into<u128>, size: Size) -> bool {

l.try_to_int(l.size()).unwrap()

== ScalarInt::try_from_uint(r, size).unwrap().try_to_int(size).unwrap()

Member

What is the point of doing the comparison in such a complicated way? Why turn r into a ScalarInt and then back into a i128?

Member

Author

Because SwitchTargets only saves the value of the corresponding bit value by u128, it lacks information on bit-width and sign.

Member

It doesn't need the sign, as I said: == is sign-independent, so we can figure out the switch target without knowing the sign. And it has the width, it is determined by the type of the match operand.

Member

Author

Ah, you're right. This code is used to compare signed integers of different widths, such as i8 and i16. We must add additional conversions for this scenario.
Hmm, it's been just a month, and I have to carefully review the code to respond correctly. It seems I indeed wrote some hard-to-understand code. :>
I'll add some comments. I should also move the unsigned comparison to the front, as I expect this might make the code a bit faster.

&& int_equal(s, second_val, discr_size))

|| (Some(f) == ScalarInt::try_from_uint(first_val, f.size())

&& Some(s)

== ScalarInt::try_from_uint(second_val, s.size())) =>

This is very strange. == is sign-independent, so I don't understand why both cases need to be considered here. Furthermore, if the sign mattered, then surely it makes no sense to check they_are_equal_signed || they_are_equal_unsigned; instead you have to check if they_are_signed { they_are_equal_signed } else { they_are_equal_unsigned }. Finally, f_c.const_.ty().is_signed() || discr_ty.is_signed() sounds like you are mixing signed and unsigned values (as in, LHS and RHS can have different sign), which should never happen.

What is going on here?

Member

Author

This is used to handle conversions such as from enum(u32) to i32 or from enum(i32) to u32:

.

Aha... I have no idea what this means. ;)

But it makes no sense to compare things twice here. == is entirely based on being equal bitwise, so the sign doesn't matter.

Member

Author

Same as above (different width), corresponding test case:

But you are comparing both signed and unsigned representation completely disregarding whether the value is actually signed or unsigned. It sounds like you want two cases

  • value is signed; then convert everything to i128 (with sign extension, e.g. via try_to_int) and compare there
  • value is unsigned; the convert everything to u128 and compare there

But currently you're interpreting the number both ways and then checking if either comparison succeeds. It seems to me that can sometimes lead to blatantly wrong results, e.g. when two numbers are equal unsigned but different after sign extension, and they are actually signed -- you code will treat them as equal, I think?

Member

Author

Ah, I'm fixing it right now.

Member

Author

Fixed in #124122, thanks for pointing it out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

RalfJung

RalfJung left review comments

cjgillot

cjgillot left review comments
Assignees

cjgillot

Labels
merged-by-bors This PR was explicitly merged by bors. 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

Milestone

1.79.0

Development

Successfully merging this pull request may close these issues.

Missed optimization with match on repr(i8) enum

10 participants

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK