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

Rust cannot move some of loop invariants out from loop at opt-level=2 #46542

Closed
upsuper opened this issue Dec 6, 2017 · 3 comments
Closed

Rust cannot move some of loop invariants out from loop at opt-level=2 #46542

upsuper opened this issue Dec 6, 2017 · 3 comments
Labels
A-MIR Area: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.html C-enhancement Category: An issue proposing an enhancement or a PR with one.

Comments

@upsuper
Copy link
Contributor

upsuper commented Dec 6, 2017

For example the following test code:

extern "C" {
fn random_bool() -> bool;
fn random_usize() -> usize;
fn output(_: usize);
}

#[no_mangle]
pub fn test() {
    let condition = unsafe { random_bool() };
    let num = unsafe { random_usize() };
    for i in 0..num {
        if !condition {
            break;
        }
        unsafe { output(i) };
    }
}

In assembly generated by rustc, it can be seen that the check of condition is inside the loop, while it should be considered a loop invariant, and be pulled out from the loop.

Note that Clang is able to do this optimization with an equivalent C++ code:

#include <cstddef>

bool random_bool();
size_t random_size();
void output(size_t n);

void test() {
    auto condition = random_bool();
    auto count = random_size();
    for (size_t i = 0; i < count; i++) {
        if (!condition) {
            break;
        }
        output(i);
    }
}

so it seems either this is something should be done in compiler frontend, or we are missing some optimization from LLVM.

@upsuper upsuper changed the title Rust cannot move some of loop invariants out from loop Rust cannot move some of loop invariants out from loop at opt-level=2 Dec 6, 2017
@upsuper
Copy link
Contributor Author

upsuper commented Dec 6, 2017

OK I was wrong that Rust cannot do this optimization. It can, with opt-level=3, but not with opt-level=2, while Clang does this with -O2.

Given that Firefox uses opt-level 2, it wouldn't get this useful optimization somehow :/

@Gankra
Copy link
Contributor

Gankra commented Dec 7, 2017

The webrender folks are looking at pushing for opt-level=3 for firefox, since it's also very important for our codegen. cc @jrmuizel

@pietroalbini pietroalbini added C-enhancement Category: An issue proposing an enhancement or a PR with one. A-MIR Area: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.html labels Jan 23, 2018
@bjorn3
Copy link
Member

bjorn3 commented May 16, 2022

This now result in the following llvm ir with -Copt-level=2:

; ModuleID = 'rust_out.b1180397-cgu.0'
source_filename = "rust_out.b1180397-cgu.0"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

%"unwind::libunwind::_Unwind_Exception" = type { i64, void (i32, %"unwind::libunwind::_Unwind_Exception"*)*, [6 x i64] }
%"unwind::libunwind::_Unwind_Context" = type { [0 x i8] }

; Function Attrs: nonlazybind uwtable
define void @test() unnamed_addr #0 personality i32 (i32, i32, i64, %"unwind::libunwind::_Unwind_Exception"*, %"unwind::libunwind::_Unwind_Context"*)* @rust_eh_personality {
start:
  %condition = tail call noundef zeroext i1 @random_bool()
  %num = tail call i64 @random_usize()
  %.not17 = icmp ne i64 %num, 0
  %0 = and i1 %condition, %.not17
  br i1 %0, label %bb9, label %bb11

bb11:                                             ; preds = %bb9, %start
  ret void

bb9:                                              ; preds = %start, %bb9
  %iter.sroa.0.016 = phi i64 [ %1, %bb9 ], [ 0, %start ]
  %1 = add nuw i64 %iter.sroa.0.016, 1
  tail call void @output(i64 %iter.sroa.0.016)
  %2 = icmp ult i64 %1, %num
  br i1 %2, label %bb9, label %bb11
}

; Function Attrs: nonlazybind uwtable
declare noundef zeroext i1 @random_bool() unnamed_addr #0

; Function Attrs: nonlazybind uwtable
declare i64 @random_usize() unnamed_addr #0

; Function Attrs: nonlazybind uwtable
declare void @output(i64) unnamed_addr #0

; Function Attrs: nonlazybind uwtable
declare i32 @rust_eh_personality(i32, i32, i64, %"unwind::libunwind::_Unwind_Exception"*, %"unwind::libunwind::_Unwind_Context"*) unnamed_addr #0

attributes #0 = { nonlazybind uwtable "probe-stack"="__rust_probestack" "target-cpu"="x86-64" }

!llvm.module.flags = !{!0, !1}

!0 = !{i32 7, !"PIC Level", i32 2}
!1 = !{i32 2, !"RtLibUseGOT", i32 1}

@bjorn3 bjorn3 closed this as completed May 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-MIR Area: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.html C-enhancement Category: An issue proposing an enhancement or a PR with one.
Projects
None yet
Development

No branches or pull requests

4 participants