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

Improve nop-match simplification #68481

Closed
wants to merge 8 commits into from
Closed

Conversation

sinkuu
Copy link
Contributor

@sinkuu sinkuu commented Jan 23, 2020

  • The first commit fixes SimplifyArmIdentity not working in presence of temporaries and storage markes, which are not eliminated in mir-opt-level=1. This does not fix the issue of ? not being eliminated in mir-opt-level < 2.
  • The third commit adds SinkCommonCodeFromPredecessors pass. This allows optimizing identical matches on types that have destructors.

This code ...

// `String` has destructor
pub fn foo(x: Result<String, u32>) -> Result<String, u32> {
    match x {
        Ok(x) => Ok(x),
        Err(x) => Err(x),
    }
}

... gives you MIR with drop flag manipulation:

    bb2: {
        StorageLive(_3);
        _7 = const false;             // <--- This is drop flag for `String`
        _3 = move ((_1 as Ok).0: std::string::String);
        StorageLive(_4);
        _4 = move _3;
        ((_0 as Ok).0: std::string::String) = move _4;
        discriminant(_0) = 0;
        StorageDead(_4);
        StorageDead(_3);
        goto -> bb8;
    }
    bb3: {
        StorageLive(_5);
        _5 = ((_1 as Err).0: u32);
        StorageLive(_6);
        _6 = _5;
        ((_0 as Err).0: u32) = move _6;
        discriminant(_0) = 1;
        StorageDead(_6);
        StorageDead(_5);
        goto -> bb8;
    }

In this case SimplifyBranchSame does not work because bb2 and bb3 is still unequal after SimplifyArmIdentity pass. It seems that LLVM is able to optimize the match into memcpy from this state, though.

    bb2: {
        _7 = const false;             // <---
        _0 = move _1;
        goto -> bb8;
    }
    bb3: {
        _0 = move _1;
        goto -> bb8;
    }

SinkCommonCodeFromPredecessors is able to sink the common statement, _0 = move _1, to bb8.

I stole the idea from LLVM, but this PR implements only (1) in the comment there.

#66234

@rust-highfive
Copy link
Collaborator

r? @zackmdavis

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jan 23, 2020
@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-7 of your PR failed (pretty log, raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
2020-01-23T12:11:05.4177022Z ========================== Starting Command Output ===========================
2020-01-23T12:11:05.4180050Z [command]/bin/bash --noprofile --norc /home/vsts/work/_temp/68973766-2d6c-43ab-a99b-53511cdf5744.sh
2020-01-23T12:11:05.4180275Z 
2020-01-23T12:11:05.4184302Z ##[section]Finishing: Disable git automatic line ending conversion
2020-01-23T12:11:05.4191726Z ##[section]Starting: Checkout rust-lang/rust@refs/pull/68481/merge to s
2020-01-23T12:11:05.4193700Z Task         : Get sources
2020-01-23T12:11:05.4194223Z Description  : Get sources from a repository. Supports Git, TfsVC, and SVN repositories.
2020-01-23T12:11:05.4194264Z Version      : 1.0.0
2020-01-23T12:11:05.4194299Z Author       : Microsoft
---
2020-01-23T12:11:06.3000823Z ##[command]git remote add origin https://github.com/rust-lang/rust
2020-01-23T12:11:06.3081755Z ##[command]git config gc.auto 0
2020-01-23T12:11:06.3158199Z ##[command]git config --get-all http.https://github.com/rust-lang/rust.extraheader
2020-01-23T12:11:06.3223519Z ##[command]git config --get-all http.proxy
2020-01-23T12:11:06.3365252Z ##[command]git -c http.extraheader="AUTHORIZATION: basic ***" fetch --force --tags --prune --progress --no-recurse-submodules --depth=2 origin +refs/heads/*:refs/remotes/origin/* +refs/pull/68481/merge:refs/remotes/pull/68481/merge
---
2020-01-23T13:08:49.0643262Z .................................................................................................... 1700/9546
2020-01-23T13:08:55.5088912Z .................................................................................................... 1800/9546
2020-01-23T13:09:07.4780645Z .....................i.............................................................................. 1900/9546
2020-01-23T13:09:15.3610997Z .................................................................................................... 2000/9546
2020-01-23T13:09:30.8841428Z ...........iiiii.................................................................................... 2100/9546
2020-01-23T13:09:40.7842756Z .................................................................................................... 2300/9546
2020-01-23T13:09:43.3255910Z .................................................................................................... 2400/9546
2020-01-23T13:09:48.8907696Z .................................................................................................... 2500/9546
2020-01-23T13:10:10.4739284Z .....................................................F.............................................. 2600/9546
---
2020-01-23T13:12:56.0559014Z .......................................................i...............i............................ 4900/9546
2020-01-23T13:13:04.4610586Z .................................................................................................... 5000/9546
2020-01-23T13:13:12.5545927Z ..................................................................................................i. 5100/9546
2020-01-23T13:13:17.8365684Z .................................................................................................... 5200/9546
2020-01-23T13:13:29.0899962Z ......................................................................ii.ii...........i............. 5300/9546
2020-01-23T13:13:38.5349430Z .......i............................................................................................ 5500/9546
2020-01-23T13:13:48.8493800Z .................................................................................................... 5600/9546
2020-01-23T13:13:55.6850593Z ........................................................i........................................... 5700/9546
2020-01-23T13:14:02.9298483Z .................................................................................................... 5800/9546
2020-01-23T13:14:02.9298483Z .................................................................................................... 5800/9546
2020-01-23T13:14:13.0534466Z .................................................................................................... 5900/9546
2020-01-23T13:14:20.9672092Z ...............................................ii...i..ii...........i............................... 6000/9546
2020-01-23T13:14:43.6549053Z .................................................................................................... 6200/9546
2020-01-23T13:14:52.3068451Z .................................................................................................... 6300/9546
2020-01-23T13:14:52.3068451Z .................................................................................................... 6300/9546
2020-01-23T13:15:02.4850847Z ...........................................................................i..ii.................... 6400/9546
2020-01-23T13:15:33.5358527Z .................................................................................................... 6600/9546
2020-01-23T13:15:38.5779341Z ...................................................i................................................ 6700/9546
2020-01-23T13:15:40.8758897Z .................................................................................................... 6800/9546
2020-01-23T13:15:43.2429984Z ..................................................i................................................. 6900/9546
---
2020-01-23T13:17:28.9688779Z .................................................................................................... 7600/9546
2020-01-23T13:17:34.9339008Z .................................................................................................... 7700/9546
2020-01-23T13:17:41.8019644Z .................................................................................................... 7800/9546
2020-01-23T13:17:52.9323830Z .................................................................................................... 7900/9546
2020-01-23T13:17:59.1315893Z ......iiiiiii....................................................................................... 8000/9546
2020-01-23T13:18:14.4703409Z .................................................................................................... 8200/9546
2020-01-23T13:18:26.5843016Z .................................................................................................... 8300/9546
2020-01-23T13:18:39.6865961Z .................................................................................................... 8400/9546
2020-01-23T13:18:46.2130969Z ....................................F............................................................... 8500/9546
---
2020-01-23T13:20:46.3861416Z 
2020-01-23T13:20:46.3861562Z 
2020-01-23T13:20:46.3861999Z ---- [ui] ui/suggestions/as-ref.rs stdout ----
2020-01-23T13:20:46.3862179Z 
2020-01-23T13:20:46.3862587Z error: Error: expected failure status (Some(1)) but received status None.
2020-01-23T13:20:46.3862821Z status: signal: 6
2020-01-23T13:20:46.3863939Z command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/suggestions/as-ref.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/suggestions/as-ref" "-Crpath" "-O" "-Cdebuginfo=0" "-Zunstable-options" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/suggestions/as-ref/auxiliary" "-A" "unused"
2020-01-23T13:20:46.3864627Z ------------------------------------------
2020-01-23T13:20:46.3864795Z 
2020-01-23T13:20:46.3865211Z ------------------------------------------
2020-01-23T13:20:46.3865397Z stderr:
2020-01-23T13:20:46.3865397Z stderr:
2020-01-23T13:20:46.3865804Z ------------------------------------------
2020-01-23T13:20:46.3866018Z error[E0308]: mismatched types
2020-01-23T13:20:46.3866949Z   --> /checkout/src/test/ui/suggestions/as-ref.rs:6:27
2020-01-23T13:20:46.3867268Z    |
2020-01-23T13:20:46.3867457Z LL |   opt.map(|arg| takes_ref(arg));
2020-01-23T13:20:46.3867987Z    |       ---                 ^^^ expected `&Foo`, found struct `Foo`
2020-01-23T13:20:46.3868408Z    |       help: consider using `as_ref` instead: `mismatched t`
2020-01-23T13:20:46.3868559Z 
2020-01-23T13:20:46.3868725Z error[E0308]: mismatched types
2020-01-23T13:20:46.3869207Z   --> /checkout/src/test/ui/suggestions/as-ref.rs:8:37
2020-01-23T13:20:46.3869207Z   --> /checkout/src/test/ui/suggestions/as-ref.rs:8:37
2020-01-23T13:20:46.3869438Z    |
2020-01-23T13:20:46.3869608Z LL |   opt.and_then(|arg| Some(takes_ref(arg)));
2020-01-23T13:20:46.3870082Z    |       --------                      ^^^ expected `&Foo`, found struct `Foo`
2020-01-23T13:20:46.3870471Z    |       help: consider using `as_ref` instead: `mismatched typesn`
2020-01-23T13:20:46.3870653Z 
2020-01-23T13:20:46.3870839Z error[E0308]: mismatched types
2020-01-23T13:20:46.3871296Z   --> /checkout/src/test/ui/suggestions/as-ref.rs:11:27
2020-01-23T13:20:46.3871296Z   --> /checkout/src/test/ui/suggestions/as-ref.rs:11:27
2020-01-23T13:20:46.3871501Z    |
2020-01-23T13:20:46.3871665Z LL |   opt.map(|arg| takes_ref(arg));
2020-01-23T13:20:46.3872147Z    |       ---                 ^^^ expected `&Foo`, found struct `Foo`
2020-01-23T13:20:46.3872543Z    |       help: consider using `as_ref` instead: `mismatched t`
2020-01-23T13:20:46.3872685Z 
2020-01-23T13:20:46.3872849Z error[E0308]: mismatched types
2020-01-23T13:20:46.3873310Z   --> /checkout/src/test/ui/suggestions/as-ref.rs:13:35
2020-01-23T13:20:46.3873310Z   --> /checkout/src/test/ui/suggestions/as-ref.rs:13:35
2020-01-23T13:20:46.3873510Z    |
2020-01-23T13:20:46.3873674Z LL |   opt.and_then(|arg| Ok(takes_ref(arg)));
2020-01-23T13:20:46.3874143Z    |       --------                    ^^^ expected `&Foo`, found struct `Foo`
2020-01-23T13:20:46.3874581Z    |       help: consider using `as_ref` instead: `mismatched typesn`
2020-01-23T13:20:46.3874933Z 
2020-01-23T13:20:46.3875100Z error[E0308]: mismatched types
2020-01-23T13:20:46.3875586Z   --> /checkout/src/test/ui/suggestions/as-ref.rs:16:27
2020-01-23T13:20:46.3875586Z   --> /checkout/src/test/ui/suggestions/as-ref.rs:16:27
2020-01-23T13:20:46.3875821Z    |
2020-01-23T13:20:46.3876006Z LL |   let y: Option<&usize> = x;
2020-01-23T13:20:46.3877235Z    |          |                |
2020-01-23T13:20:46.3877433Z    |          |                expected enum `std::option::Option`, found reference
2020-01-23T13:20:46.3877433Z    |          |                expected enum `std::option::Option`, found reference
2020-01-23T13:20:46.3877610Z    |          |                help: you can convert from `&Option<T>` to `Option<&T>` using `.as_ref()`: `x.as_ref()`
2020-01-23T13:20:46.3877957Z    |
2020-01-23T13:20:46.3877957Z    |
2020-01-23T13:20:46.3878113Z    = note:   expected enum `std::option::Option<&usize>`
2020-01-23T13:20:46.3878292Z            found reference `&std::option::Option<usize>`
2020-01-23T13:20:46.3880164Z error[E0308]: mismatched types
2020-01-23T13:20:46.3880725Z   --> /checkout/src/test/ui/suggestions/as-ref.rs:19:35
2020-01-23T13:20:46.3880952Z    |
2020-01-23T13:20:46.3880952Z    |
2020-01-23T13:20:46.3881111Z LL |   let y: Result<&usize, &usize> = x;
2020-01-23T13:20:46.3881569Z    |          ----------------------   ^ expected enum `std::result::Result`, found reference
2020-01-23T13:20:46.3881957Z    |          expected due to this
2020-01-23T13:20:46.3882124Z    |
2020-01-23T13:20:46.3882124Z    |
2020-01-23T13:20:46.3882290Z    = note:   expected enum `std::result::Result<&usize, &usize>`
2020-01-23T13:20:46.3882457Z            found reference `&std::result::Result<usize, usize>`
2020-01-23T13:20:46.3882621Z help: you can convert from `&Result<T, E>` to `Result<&T, &E>` using `.as_ref()`
2020-01-23T13:20:46.3882776Z    |
2020-01-23T13:20:46.3882947Z LL |   let y: Result<&usize, &usize> = x.as_ref();
2020-01-23T13:20:46.3883272Z 
2020-01-23T13:20:46.3883442Z error[E0308]: mismatched types
2020-01-23T13:20:46.3883866Z   --> /checkout/src/test/ui/suggestions/as-ref.rs:23:34
2020-01-23T13:20:46.3884059Z    |
2020-01-23T13:20:46.3884059Z    |
2020-01-23T13:20:46.3884234Z LL |   let y: Result<&usize, usize> = x;
2020-01-23T13:20:46.3884698Z    |          ---------------------   ^ expected enum `std::result::Result`, found reference
2020-01-23T13:20:46.3885078Z    |          expected due to this
2020-01-23T13:20:46.3885229Z    |
2020-01-23T13:20:46.3885229Z    |
2020-01-23T13:20:46.3885402Z    = note:   expected enum `std::result::Result<&usize, usize>`
2020-01-23T13:20:46.3885566Z            found reference `&std::result::Result<usize, usize>`
2020-01-23T13:20:46.3885721Z 
2020-01-23T13:20:46.3885875Z free(): invalid pointer
2020-01-23T13:20:46.3886405Z ------------------------------------------
2020-01-23T13:20:46.3886902Z 
2020-01-23T13:20:46.3887045Z 
2020-01-23T13:20:46.3887519Z ---- [ui] ui/tcp-stress.rs stdout ----
---
2020-01-23T13:20:46.3893925Z test result: FAILED. 9493 passed; 3 failed; 50 ignored; 0 measured; 0 filtered out
2020-01-23T13:20:46.3894305Z 
2020-01-23T13:20:46.3897830Z 
2020-01-23T13:20:46.3899177Z 
2020-01-23T13:20:46.3901597Z command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-tools-bin/compiletest" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-tools-bin/compiletest" "--compile-lib-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib" "--run-lib-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/x86_64-unknown-linux-gnu/lib" "--rustc-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "--src-base" "/checkout/src/test/ui" "--build-base" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui" "--stage-id" "stage2-x86_64-unknown-linux-gnu" "--mode" "ui" "--target" "x86_64-unknown-linux-gnu" "--host" "x86_64-unknown-linux-gnu" "--llvm-filecheck" "/usr/lib/llvm-7/bin/FileCheck" "--host-rustcflags" "-Crpath -O -Cdebuginfo=0 -Zunstable-options  -Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "--target-rustcflags" "-Crpath -O -Cdebuginfo=0 -Zunstable-options  -Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "--docck-python" "/usr/bin/python2.7" "--lldb-python" "/usr/bin/python2.7" "--gdb" "/usr/bin/gdb" "--quiet" "--llvm-version" "7.0.0\n" "--system-llvm" "--cc" "" "--cxx" "" "--cflags" "" "--llvm-components" "" "--llvm-cxxflags" "" "--adb-path" "adb" "--adb-test-dir" "/data/tmp/work" "--android-cross-path" "" "--color" "always"
2020-01-23T13:20:46.3908137Z 
2020-01-23T13:20:46.3908543Z 
2020-01-23T13:20:46.3909334Z thread 'main' panicked at 'Some tests failed', src/tools/compiletest/src/main.rs:387:22
2020-01-23T13:20:46.3909586Z note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
2020-01-23T13:20:46.3909586Z note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
2020-01-23T13:20:46.3913154Z failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test
2020-01-23T13:20:46.3913503Z Build completed unsuccessfully in 1:03:52
2020-01-23T13:20:46.3966223Z == clock drift check ==
2020-01-23T13:20:46.3984113Z   local time: Thu Jan 23 13:20:46 UTC 2020
2020-01-23T13:20:46.6976277Z   network time: Thu, 23 Jan 2020 13:20:46 GMT
2020-01-23T13:20:46.6978515Z == end clock drift check ==
2020-01-23T13:20:47.1623147Z 
2020-01-23T13:20:47.1728478Z ##[error]Bash exited with code '1'.
2020-01-23T13:20:47.1752860Z ##[section]Finishing: Run build
2020-01-23T13:20:47.1774678Z ##[section]Starting: Checkout rust-lang/rust@refs/pull/68481/merge to s
2020-01-23T13:20:47.1776611Z Task         : Get sources
2020-01-23T13:20:47.1776669Z Description  : Get sources from a repository. Supports Git, TfsVC, and SVN repositories.
2020-01-23T13:20:47.1776711Z Version      : 1.0.0
2020-01-23T13:20:47.1776747Z Author       : Microsoft
2020-01-23T13:20:47.1776747Z Author       : Microsoft
2020-01-23T13:20:47.1776805Z Help         : [More Information](https://go.microsoft.com/fwlink/?LinkId=798199)
2020-01-23T13:20:47.1776863Z ==============================================================================
2020-01-23T13:20:47.6220161Z Cleaning any cached credential from repository: rust-lang/rust (GitHub)
2020-01-23T13:20:47.6263054Z ##[section]Finishing: Checkout rust-lang/rust@refs/pull/68481/merge to s
2020-01-23T13:20:47.6401045Z Cleaning up task key
2020-01-23T13:20:47.6401913Z Start cleaning up orphan processes.
2020-01-23T13:20:47.6541252Z Terminate orphan process: pid (4152) (python)
2020-01-23T13:20:47.6780332Z ##[section]Finishing: Finalize Job

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@sinkuu sinkuu closed this Jan 23, 2020
@sinkuu sinkuu reopened this Jan 24, 2020
@sinkuu
Copy link
Contributor Author

sinkuu commented Jan 24, 2020

Ready for review.

Copy link
Contributor

@oli-obk oli-obk left a comment

Choose a reason for hiding this comment

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

I haven't understood some parts, maybe you can clear up some of my confusion.

src/librustc_mir/transform/simplify_try.rs Outdated Show resolved Hide resolved
src/librustc_mir/transform/simplify_try.rs Outdated Show resolved Hide resolved
/// or
///
/// ```rust
/// StorageLive(_LOCAL_TMP);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you elaborate on why we should be doing this optimization in debug mode (and why we shouldn't instead run the storage and temporary elimination)? Will this make debug mode compile faster in all cases?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry for the late reply!

AFAIK mir-opt-level is always 1 unless explicitly specified, regardless of release or debug build. mir-opt-level is independent from optimization level, and cargo does not set it. (-Zmir-optlevel is an unstable flag and setting it to 2 or larger is prone to ICE/miscompile anyway.)
You can confirm this by building MIR of this playground in release / debug build. Temporaries are not eliminated even in release build, and SimplifyArmIdentity is not working.

That said, the purpose of this PR is to improve the codegen of identical match in relase build.

diff of cargo rustc --release -- --emit=llvm-ir, using the same code as the playground above, before/after this PR
--- old.ll	2020-01-27 07:04:08.034979599 +0900
+++ new.ll	2020-01-27 07:04:21.682132255 +0900
@@ -1,5 +1,5 @@
-; ModuleID = 'foo.1lzogcxs-cgu.0'
-source_filename = "foo.1lzogcxs-cgu.0"
+; ModuleID = 'foo.2my2volq-cgu.0'
+source_filename = "foo.2my2volq-cgu.0"
 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-unknown-linux-gnu"
 
@@ -9,80 +9,35 @@
 %"unwind::libunwind::_Unwind_Context" = type { [0 x i8] }
 
 ; foo::try_identity
-; Function Attrs: nofree norecurse nounwind nonlazybind uwtable
-define void @_ZN3foo12try_identity17hf7a3f301f9e3a548E(%"core::result::Result<u64, i32>"* noalias nocapture sret dereferenceable(16), %"core::result::Result<u64, i32>"* noalias nocapture readonly dereferenceable(16) %x) unnamed_addr #0 {
+; Function Attrs: nounwind nonlazybind uwtable
+define void @_ZN3foo12try_identity17h273ad7d1ef012f0eE(%"core::result::Result<u64, i32>"* noalias nocapture sret dereferenceable(16), %"core::result::Result<u64, i32>"* noalias nocapture readonly dereferenceable(16) %x) unnamed_addr #0 {
 start:
-  %1 = getelementptr inbounds %"core::result::Result<u64, i32>", %"core::result::Result<u64, i32>"* %x, i64 0, i32 0, i64 0
-  %2 = load i32, i32* %1, align 8, !range !2
-  %switch = icmp eq i32 %2, 1
-  br i1 %switch, label %bb3, label %bb2
-
-bb2:                                              ; preds = %start
-  %3 = getelementptr inbounds %"core::result::Result<u64, i32>", %"core::result::Result<u64, i32>"* %x, i64 0, i32 2, i64 1
-  %4 = bitcast i32* %3 to i64*
-  %x2 = load i64, i64* %4, align 8
-  %5 = getelementptr inbounds %"core::result::Result<u64, i32>", %"core::result::Result<u64, i32>"* %0, i64 0, i32 2, i64 1
-  %6 = bitcast i32* %5 to i64*
-  store i64 %x2, i64* %6, align 8
-  br label %bb4
-
-bb3:                                              ; preds = %start
-  %7 = getelementptr inbounds %"core::result::Result<u64, i32>", %"core::result::Result<u64, i32>"* %x, i64 0, i32 2, i64 0
-  %x1 = load i32, i32* %7, align 4
-  %8 = getelementptr inbounds %"core::result::Result<u64, i32>", %"core::result::Result<u64, i32>"* %0, i64 0, i32 2, i64 0
-  store i32 %x1, i32* %8, align 4
-  br label %bb4
-
-bb4:                                              ; preds = %bb2, %bb3
-  %.sink = phi i32 [ 0, %bb2 ], [ 1, %bb3 ]
-  %9 = getelementptr inbounds %"core::result::Result<u64, i32>", %"core::result::Result<u64, i32>"* %0, i64 0, i32 0, i64 0
-  store i32 %.sink, i32* %9, align 8
+  %1 = bitcast %"core::result::Result<u64, i32>"* %0 to i8*
+  %2 = bitcast %"core::result::Result<u64, i32>"* %x to i8*
+  tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* nonnull align 8 %1, i8* nonnull align 8 %2, i64 16, i1 false)
   ret void
 }
 
 ; foo::try_identity_drop
 ; Function Attrs: nounwind nonlazybind uwtable
-define void @_ZN3foo17try_identity_drop17h5d9ea5a8e7421c58E(%"core::result::Result<alloc::string::String, i32>"* noalias nocapture sret dereferenceable(32), %"core::result::Result<alloc::string::String, i32>"* noalias nocapture readonly dereferenceable(32) %x) unnamed_addr #1 personality i32 (i32, i32, i64, %"unwind::libunwind::_Unwind_Exception"*, %"unwind::libunwind::_Unwind_Context"*)* @rust_eh_personality {
+define void @_ZN3foo17try_identity_drop17h7d0574702d5fadd5E(%"core::result::Result<alloc::string::String, i32>"* noalias nocapture sret dereferenceable(32), %"core::result::Result<alloc::string::String, i32>"* noalias nocapture readonly dereferenceable(32) %x) unnamed_addr #0 personality i32 (i32, i32, i64, %"unwind::libunwind::_Unwind_Exception"*, %"unwind::libunwind::_Unwind_Context"*)* @rust_eh_personality {
 start:
-  %1 = getelementptr inbounds %"core::result::Result<alloc::string::String, i32>", %"core::result::Result<alloc::string::String, i32>"* %x, i64 0, i32 0, i64 0
-  %2 = load i32, i32* %1, align 8, !range !2
-  %switch = icmp eq i32 %2, 1
-  br i1 %switch, label %bb8, label %bb5
-
-bb4:                                              ; preds = %bb5, %bb8
-  %.sink = phi i32 [ 0, %bb5 ], [ 1, %bb8 ]
-  %3 = getelementptr inbounds %"core::result::Result<alloc::string::String, i32>", %"core::result::Result<alloc::string::String, i32>"* %0, i64 0, i32 0, i64 0
-  store i32 %.sink, i32* %3, align 8
+  %1 = bitcast %"core::result::Result<alloc::string::String, i32>"* %0 to i8*
+  %2 = bitcast %"core::result::Result<alloc::string::String, i32>"* %x to i8*
+  tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* nonnull align 8 %1, i8* nonnull align 8 %2, i64 32, i1 false)
   ret void
-
-bb5:                                              ; preds = %start
-  %x1.sroa.0.0..sroa_idx3 = getelementptr inbounds %"core::result::Result<alloc::string::String, i32>", %"core::result::Result<alloc::string::String, i32>"* %x, i64 0, i32 2, i64 1
-  %x1.sroa.0.0..sroa_cast = bitcast i32* %x1.sroa.0.0..sroa_idx3 to i8*
-  %_4.sroa.0.0..sroa_idx10 = getelementptr inbounds %"core::result::Result<alloc::string::String, i32>", %"core::result::Result<alloc::string::String, i32>"* %0, i64 0, i32 2, i64 1
-  %_4.sroa.0.0..sroa_cast = bitcast i32* %_4.sroa.0.0..sroa_idx10 to i8*
-  call void @llvm.memcpy.p0i8.p0i8.i64(i8* nonnull align 8 %_4.sroa.0.0..sroa_cast, i8* nonnull align 8 %x1.sroa.0.0..sroa_cast, i64 24, i1 false)
-  br label %bb4
-
-bb8:                                              ; preds = %start
-  %4 = getelementptr inbounds %"core::result::Result<alloc::string::String, i32>", %"core::result::Result<alloc::string::String, i32>"* %x, i64 0, i32 2, i64 0
-  %x2 = load i32, i32* %4, align 4
-  %5 = getelementptr inbounds %"core::result::Result<alloc::string::String, i32>", %"core::result::Result<alloc::string::String, i32>"* %0, i64 0, i32 2, i64 0
-  store i32 %x2, i32* %5, align 4
-  br label %bb4
 }
 
 ; Function Attrs: nounwind nonlazybind uwtable
-declare i32 @rust_eh_personality(i32, i32, i64, %"unwind::libunwind::_Unwind_Exception"*, %"unwind::libunwind::_Unwind_Context"*) unnamed_addr #1
+declare i32 @rust_eh_personality(i32, i32, i64, %"unwind::libunwind::_Unwind_Exception"*, %"unwind::libunwind::_Unwind_Context"*) unnamed_addr #0
 
 ; Function Attrs: argmemonly nounwind
-declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1 immarg) #2
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1 immarg) #1
 
-attributes #0 = { nofree norecurse nounwind nonlazybind uwtable "probe-stack"="__rust_probestack" "target-cpu"="x86-64" }
-attributes #1 = { nounwind nonlazybind uwtable "probe-stack"="__rust_probestack" "target-cpu"="x86-64" }
-attributes #2 = { argmemonly nounwind }
+attributes #0 = { nounwind nonlazybind uwtable "probe-stack"="__rust_probestack" "target-cpu"="x86-64" }
+attributes #1 = { argmemonly nounwind }
 
 !llvm.module.flags = !{!0, !1}
 
 !0 = !{i32 7, !"PIC Level", i32 2}
 !1 = !{i32 2, !"RtLibUseGOT", i32 1}
-!2 = !{i32 0, i32 2}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Regarding the compiler performance: I locally run rustc-perf, and it looks perf-neutral. The 2nd point in #66234 (comment) is still required for these optimizations to be useful in real cases.

Improved SimplifyArmIdentity

new1

Improved SimplifyArmIdentity + SinkCommonCodeFromPredecessors

new2

Copy link
Contributor

Choose a reason for hiding this comment

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

So there's two things I'm worried about here:

  1. we're slowly adding more optimizations to debug mode, which by it's very definition should be easy to debug with a debugger. Such optimizations can easily end up messing up the source. This one doesn't do it yet, but still.

  2. You essentially had to implement an optimization twice, once for mir-opt-level 1 and once for mir-opt-level 2. I feel like that needlessly complicates our optimizations.

Instead of implementing this optimization twice, how about moving the ICEing optimizations to mir-opt-level 3 and making mir-opt-level 2 the standard for --release?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

we're slowly adding more optimizations to debug mode, which by it's very definition should be easy to debug with a debugger. Such optimizations can easily end up messing up the source.

I realized this PR is already debuginfo-breaking. If the debugger was stepping on match, it would point to whichever arm the optimizer reduced all other arms into.

Instead of implementing this optimization twice, how about moving the ICEing optimizations to mir-opt-level 3 and making mir-opt-level 2 the standard for --release?

Your plan sounds right. Efforts should be concentrated on fixing/improving advanced MIR optimizations rather than adding ad-hoc optimization passes.

I'll close this PR. Thank you for your time, @oli-obk!

@@ -169,19 +194,23 @@ fn match_arm(stmts: &mut [Statement<'_>], local_decls: &mut IndexVec<Local, Loca
return;
}

if vf_1 != vf_0 // The field-and-variant information match up.
if drop_flag == Some(local_0)
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't get what these checks do. The type of local_0 is never bool as far as I can tell, so how can local_0 and drop_flag refer to the same local?

Copy link
Contributor Author

@sinkuu sinkuu Jan 26, 2020

Choose a reason for hiding this comment

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

Yes, this one is definitely unnecessary. I added it by mistake - sorry for confusion.

let mut matched_stmts = 0;
let basic_blocks = body.basic_blocks_mut();

loop {
Copy link
Contributor

Choose a reason for hiding this comment

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

So... this loop goes backwards in all preds statements and gives you the number of statements that are the same? Basically extracting a common postfix of statements from all previous basic blocks?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes.

|| drop_flag == Some(local_tmp_2)
|| local_decls[local_tmp_2].is_user_variable()
Copy link
Contributor

Choose a reason for hiding this comment

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

Since I still don't understand what the above code is doing, I can't tell if removing the == Some(local_0) is ok

Copy link
Contributor Author

Choose a reason for hiding this comment

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

== Some(local_0) surely didn't make sense as you pointed out. Regarding other checks... I'm not sure. I added checks to make sure the code being matched is exactly what I intended, but probably they can all be removed.

src/librustc_mir/transform/simplify_try.rs Outdated Show resolved Hide resolved
@sinkuu sinkuu closed this Jan 28, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants