-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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
Passing enum by-value loses range metadata #13926
Comments
Oh, actually: this is because there is no range metadata when define i64 @_ZN3foo20h043091a9d9208cb0saa4v0.0E(i8* nocapture readonly) unnamed_addr #0 {
entry-block:
%1 = load i8* %0, align 1, !range !0
%2 = zext i8 %1 to i64
%3 = getelementptr inbounds [4 x i64]* @_ZN1X20hcca41332b11ffec7iaa4v0.0E, i64 0, i64 %2
%4 = load i64* %3, align 8
ret i64 %4
}
!0 = metadata !{i8 0, i8 4} Updated title from "indexing fixed-length array doesn't eliminated bounds checks". |
Fixing this would likely require extending the feature in LLVM to be usable on parameters. |
I agree that the |
If the enumeration derives pub fn foo(y: Foo) -> isize {
let closure = |z: &Foo| { X[(*z) as usize] };
closure(&y)
} ; Function Attrs: nounwind readnone uwtable
define i64 @_ZN3foo20h8ac558f51be88dd53aaE(i8) unnamed_addr #1 {
entry-block:
%1 = zext i8 %0 to i64
%2 = getelementptr inbounds [4 x i64], [4 x i64]* @_ZN1X20h5e497aaeb62c0700UaaE, i64 0, i64 %1
%3 = load i64, i64* %2, align 8, !noalias !1
ret i64 %3
} This might be fragile as it probably relies on the order in which the LLVM optimiser performs the bound-check optimisation and the closure inlining. |
Can this be reproed today? |
|
Here's the generated LLVM IR as of Rust 1.41: @_ZN10playground1X17h7a5538bb38d6a168E = internal unnamed_addr constant <{ [32 x i8] }> <{ [32 x i8] c"\0A\00\00\00\00\00\00\00\01\00\00\00\00\00\00\00\04\00\00\00\00\00\00\00\03\00\00\00\00\00\00\00" }>, align 8
; playground::foo
; Function Attrs: nounwind nonlazybind uwtable
define i64 @_ZN10playground3foo17hc0370d8e3b68fd0eE(i8 %y) unnamed_addr #0 {
start:
%0 = icmp ult i8 %y, 4
tail call void @llvm.assume(i1 %0)
%_3 = zext i8 %y to i64
%1 = getelementptr inbounds [4 x i64], [4 x i64]* bitcast (<{ [32 x i8] }>* @_ZN10playground1X17h7a5538bb38d6a168E to [4 x i64]*), i64 0, i64 %_3
%2 = load i64, i64* %1, align 8
ret i64 %2
}
; Function Attrs: nounwind
declare void @llvm.assume(i1) #1
attributes #0 = { nounwind nonlazybind uwtable "probe-stack"="__rust_probestack" "target-cpu"="x86-64" }
attributes #1 = { nounwind }
!llvm.module.flags = !{!0, !1}
!0 = !{i32 7, !"PIC Level", i32 2}
!1 = !{i32 2, !"RtLibUseGOT", i32 1} I'm no expert, but I note that the branch is in fact now gone, however we're still doing a comparison against the input parameter and passing the result of the comparison to |
That will never hit codegen, it's just an optimization hint for LLVM. This issue does still reproduce with this code though: #[repr(u8)]
pub enum Exception {
Low = 5,
High = 10,
}
pub fn access(array: &[usize; 12], exc: Exception) -> usize {
array[(exc as u8 - 4) as usize]
} LLVM IR:
(this originally showed up in rust-embedded/cortex-m#202) |
#36962 actually fixed the I've attempted to add the assumption but it failed to achieve the desired results. I've opened #75525 which I believe is related. See this example: https://godbolt.org/z/YhK1rT When any of the assumptions is an inclusive relation check instead of an exclusive one, the assumption is useless. |
Eliminate some other bound checks when index comes from an enum rust-lang#36962 introduced an assumption for the upper limit of the enum's value. This PR adds an assumption to the lower value as well. I've modified the original codegen test to show that derived (in that case, adding 1) values also don't generate bounds checks. However, this test is actually carefully crafted to not hit a bug: if the enum's variants are modified to 1 and 2 instead of 2 and 3, the test fails by adding a bounds check. I suppose this is an LLVM issue and rust-lang#75525, while not exactly in this context should be tracking it. I'm not at all confident if this patch can be accepted, or even if it _should_ be accepted in this state. But I'm curious about what others think :) ~Improves~ Should improve rust-lang#13926 but does not close it because it's not exactly predictable, where bounds checks may pop up against the assumptions.
@jonas-schievink's test case was added in #75529: see https://github.com/rust-lang/rust/pull/75529/files#diff-d8b41e5a819724c9afcfc0f1ab152c25 This can probably be closed, unless anyone has another example that doesn't get optimized. |
This now compiles without bounds check. @huonw Maybe you should close the issue. |
[RFC](https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#lint-audit-and-categories) has more groups so add them changelog: none
Test case update for Rust 1.0:
Original report below:
becomes
even though it's impossible for a
Foo
to be larger than 3, so the bounds checking can never fail. (Doing a similar thing with e.g.[int, .. 256]
and a value of typeu8
does eliminate the bounds checks.)(I guess this is an LLVM bug, but filing it here just in case we're emiting range info incorrectly, or some-such.)
The text was updated successfully, but these errors were encountered: