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

Passing enum by-value loses range metadata #13926

Open
huonw opened this Issue May 4, 2014 · 6 comments

Comments

Projects
None yet
7 participants
@huonw
Copy link
Member

huonw commented May 4, 2014

pub enum Foo {
    A, B, C, D
}

static X: [int, .. 4] = [10, 1, 4, 3];
pub fn foo(y: Foo) -> int {
    X[y as uint]
}

becomes

; Function Attrs: uwtable
define i64 @_ZN3foo20h19859df9e3d3b0bcsaa4v0.0E(i8) unnamed_addr #0 {
entry-block:
  %1 = zext i8 %0 to i64
  %2 = icmp ugt i8 %0, 3
  br i1 %2, label %cond, label %next, !prof !0

next:                                             ; preds = %entry-block
  %3 = getelementptr inbounds [4 x i64]* @_ZN1X20h61a81bb0de98e867iaa4v0.0E, i64 0, i64 %1
  %4 = load i64* %3, align 8
  ret i64 %4

cond:                                             ; preds = %entry-block
  tail call void @_ZN2rt6unwind17fail_bounds_check20h0f41a1608cc59c5e1199v0.11.preE(i8* getelementptr inbounds ([14 x i8]* @str879, i64 0, i64 0), i64 7, i64 %1, i64 4)
  unreachable
}

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 type u8 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.)

@huonw huonw added the I-slow label May 4, 2014

@huonw huonw changed the title Indexing fixed-length array be shorter enum doesn't eliminate bounds checks Indexing fixed-length array with shorter enum doesn't eliminate bounds checks May 4, 2014

@huonw

This comment has been minimized.

Copy link
Member Author

huonw commented May 4, 2014

Oh, actually: this is because there is no range metadata when Foo is passed by value: passing it by reference fn foo(x: &Foo) means a load with metadata is emitted and the bounds check is eliminated:

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".

@huonw huonw changed the title Indexing fixed-length array with shorter enum doesn't eliminate bounds checks Passing enum by-value loses range metadata May 4, 2014

@thestinger

This comment has been minimized.

Copy link
Contributor

thestinger commented May 4, 2014

Fixing this would likely require extending the feature in LLVM to be usable on parameters.

@ranma42

This comment has been minimized.

Copy link
Contributor

ranma42 commented Dec 29, 2014

I agree that the !range metadata annotation would be convenient also on values other than those coming from load/call/invoke, but wouldn't it be sufficient to use the llvm.assume intrinsic to specify the constraints on values (in this case, its range)?

@ranma42

This comment has been minimized.

Copy link
Contributor

ranma42 commented Aug 30, 2015

If the enumeration derives Copy and Clone, this seems to be a way to code the function so that the LLVM optimisations generate the desired code:

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.

@brson

This comment has been minimized.

Copy link
Contributor

brson commented Mar 9, 2017

Can this be reproed today?

@arielb1

This comment has been minimized.

Copy link
Contributor

arielb1 commented Mar 19, 2017

Sure. Same LLVM problem. I fixed the y as uint case in #36962. The underlying issue still exists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.