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

[MIR] simd_shuffle codegen uses self.instance as const_eval_promoted source #67557

Closed
bjorn3 opened this issue Dec 23, 2019 · 11 comments · Fixed by #67598
Closed

[MIR] simd_shuffle codegen uses self.instance as const_eval_promoted source #67557

bjorn3 opened this issue Dec 23, 2019 · 11 comments · Fixed by #67598
Assignees
Labels
A-MIR Area: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.html C-bug Category: This is a bug. E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. requires-nightly This issue requires a nightly compiler in some way. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@bjorn3
Copy link
Member

bjorn3 commented Dec 23, 2019

let c = bx.tcx().const_eval_promoted(self.instance, promoted);

It should use Instance::new(def_is, self.monomorphize(substs). (substs is the second field of StaticKind::Promoted.) While both instances are normally equal, they can differ after running the mir inliner. In that case the promoted will refer to the inlined function.

@rustbot modify labels: +A-mir +C-bug +requires-nightly

This issue has been assigned to @jumbatm via this comment.

@rustbot rustbot added A-MIR Area: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.html C-bug Category: This is a bug. requires-nightly This issue requires a nightly compiler in some way. labels Dec 23, 2019
@jonas-schievink jonas-schievink added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Dec 23, 2019
@Centril
Copy link
Contributor

Centril commented Dec 23, 2019

cc @oli-obk

@oli-obk oli-obk added the E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. label Dec 23, 2019
@jumbatm
Copy link
Contributor

jumbatm commented Dec 23, 2019

Can I give this a go?

@rustbot claim

@rustbot rustbot self-assigned this Dec 23, 2019
@jumbatm
Copy link
Contributor

jumbatm commented Dec 23, 2019

Do you have any specific tests in mind I should add to check for the correct behaviour?

@rustbot rustbot assigned rustbot and unassigned rustbot Dec 23, 2019
@bjorn3
Copy link
Member Author

bjorn3 commented Dec 23, 2019

// compile-flags:-Zmir-opt-level=3

#[inline(never)]
fn assert_1234(x: &[u8]) {
    assert_eq!(x, &[1, 2, 3, 4]);
}

#[inline(always)]
fn ret_slice() -> &'static [u8] {
    &[1, 2, 3, 4]
}

fn main() {
    let promoted: &'static [u8] = &[0, 0, 0, 0];
    let slice: &'static [u8] = ret_slice();
    assert_1234(slice);
}

should be a test if the mir inliner would to inline ret_slice. Somehow it doesn't though.

@wesleywiser
Copy link
Member

@bjorn3 You might be running into this unfortunate check

&& self_node_id.as_u32() < callee_node_id.as_u32()

Try moving ret_slice below main.

@jumbatm
Copy link
Contributor

jumbatm commented Dec 24, 2019

Wow, that's hilarious. With just the changes @bjorn3 suggested, the inlining still doesn't work properly, but doesn't seem to break any existing stuff. But I've just tried this and yeah, putting ret_slice below main has made the MIR inliner work.

@bjorn3
Copy link
Member Author

bjorn3 commented Dec 24, 2019

// compile-flags:-Zmir-opt-level=3

fn main() {
    let promoted: &'static [u8] = &[0, 0, 0, 0];
    let slice: &'static [u8] = ret_slice();
    assert_1234(slice); assert_0000(promoted);
}

#[inline(never)]
fn assert_1234(x: &[u8]) {
    assert_eq!(x, &[1, 2, 3, 4]);
}

#[inline(never)]
fn assert_0000(x: &[u8]) {
    assert_eq!(x, &[0, 0, 0, 0]);
}

#[inline(always)]
fn ret_slice() -> &'static [u8] {
    &[1, 2, 3, 4]
}

This does inline, but somehow no assertion fires with current rustc. The printed MIR doesn't seem to show the the def_id from which the promoted originates, so I don't know what the problem is.

[...]
    bb0: {
        _2 = &(promoted[0]: [u8; 4]);
        _1 = move _2 as &[u8] (Pointer(Unsize));
        _6 = &(promoted[0]: [u8; 4]);
        _3 = move _6 as &[u8] (Pointer(Unsize));
        StorageLive(_4);
        _4 = const assert_1234(move _3) -> bb1;
    }

    bb1: {
        StorageDead(_4);
        StorageLive(_5);
        _5 = const assert_0000(move _1) -> bb2;
    }
[...]

@jumbatm
Copy link
Contributor

jumbatm commented Dec 24, 2019

Unless I'm misunderstanding something, isn't this the correct behaviour? Both of those assertions are true, and swapping slice and promoted around in the assertions correctly triggers an assertion failure.

@bjorn3
Copy link
Member Author

bjorn3 commented Dec 24, 2019

I forgot that this problem was only with simd_shuffle.

@bjorn3
Copy link
Member Author

bjorn3 commented Dec 24, 2019

I got a working test:

#![feature(platform_intrinsics, repr_simd)]

extern "platform-intrinsic" {
    fn simd_shuffle2<T, U>(x: T, y: T, idx: [u32; 2]) -> U;
}

#[repr(simd)]
#[derive(Debug, PartialEq)]
struct Simd2(u8, u8);

fn main() {
    unsafe {
        let p_res: Simd2 = simd_shuffle2(Simd2(10, 11), Simd2(12, 13), [0, 1]);
        let a_res: Simd2 = inline_me();

        assert_10_11(p_res);
        assert_10_13(a_res);
    }
}

#[inline(never)]
fn assert_10_11(x: Simd2) {
    assert_eq!(x, Simd2(10, 11));
}

#[inline(never)]
fn assert_10_13(x: Simd2) {
    assert_eq!(x, Simd2(10, 13));
}


#[inline(always)]
unsafe fn inline_me() -> Simd2 {
    simd_shuffle2(Simd2(10, 11), Simd2(12, 13), [0, 3])
}
$ rustc ./simd_shuffle_promotion_problem.rs && ./simd_shuffle_promotion_problem
$ rustc -Zmir-opt-level=2 ./simd_shuffle_promotion_problem.rs && ./simd_shuffle_promotion_problem
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `Simd2(10, 11)`,
 right: `Simd2(10, 13)`', ./simd_shuffle_promotion_problem.rs:28:5

@jumbatm
Copy link
Contributor

jumbatm commented Dec 25, 2019

Ah, that's a good test case. Yeah, that's definitely not the expected behaviour.

While messing about with your example, I also managed to come across an ICE with this slightly shorter version:

#![feature(platform_intrinsics, repr_simd)]

extern "platform-intrinsic" {
    fn simd_shuffle2<T, U>(x: T, y: T, idx: [u32; 2]) -> U;
}

#[repr(simd)]
#[derive(Debug, PartialEq)]
struct Simd2(u8, u8);

fn main() {
    unsafe {
        let _: Simd2 = inline_me(); 
    }
}

#[inline(always)]
unsafe fn inline_me() -> Simd2 {
    simd_shuffle2(Simd2(10, 11), Simd2(12, 13), [0, 1])
}

causes an ICE currently due to an internal index out of range.

The good news is that the changes you suggested fixes both of these test cases. Good spot :) I'm putting up the PR now.

JohnTitor added a commit to JohnTitor/rust that referenced this issue Dec 26, 2019
…oli-obk

Fix ICE / miscompilation when inlining simd shuffle intrinsic in MIR.

Closes rust-lang#67557.

r? @oli-obk
JohnTitor added a commit to JohnTitor/rust that referenced this issue Dec 26, 2019
…oli-obk

Fix ICE / miscompilation when inlining simd shuffle intrinsic in MIR.

Closes rust-lang#67557.

r? @oli-obk
Mark-Simulacrum added a commit to Mark-Simulacrum/rust that referenced this issue Dec 26, 2019
…oli-obk

Fix ICE / miscompilation when inlining simd shuffle intrinsic in MIR.

Closes rust-lang#67557.

r? @oli-obk
@bors bors closed this as completed in 8b4d22c Dec 28, 2019
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-bug Category: This is a bug. E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. requires-nightly This issue requires a nightly compiler in some way. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants