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

if and match produce different assembly #85260

Open
In-line opened this issue May 13, 2021 · 1 comment
Open

if and match produce different assembly #85260

In-line opened this issue May 13, 2021 · 1 comment
Labels
C-enhancement Category: An issue proposing an enhancement or a PR with one.

Comments

@In-line
Copy link
Contributor

In-line commented May 13, 2021

https://rust.godbolt.org/z/zKEfaPKdn

inspired from https://stackoverflow.com/questions/67412863/match-compiles-into-suboptimal-asm-compared-to-if-else

@shampoofactory
Copy link
Contributor

shampoofactory commented May 13, 2021

Hi. Unless I'm mistaken, the two methods produce different outputs as the b < key results have been flipped.

If we account for this anomaly and introduce a third method that more directly compares the if and match equivalents, both using cmp and Ordering, we see the output is identical.

The difference appears to be due to the use of cmp and Ordering rather than if and match. In the final assembly, if_else makes use of a conditional move which is likely going to be faster.

https://rust.godbolt.org/z/vnfM4cY45

use std::cmp::Ordering;

pub fn if_else(out: &mut i64, key: i64, b: i64, c: i64) -> bool {
    if key == b {
        return true;
    }
    if key < b {
        *out = b;
    } else {
        *out = c;
    }
    false
}

pub fn contains_match_(out: &mut i64, key: i64, b: i64, c: i64) -> bool {
    match key.cmp(&b) {
        Ordering::Equal => return true,
        Ordering::Less => {
            *out = b;
        },
        Ordering::Greater => {
            *out = c;
        },
    }
    false
}

pub fn if_else_cmp(out: &mut i64, key: i64, b: i64, c: i64) -> bool {
    let ordering = key.cmp(&b);
    if ordering == Ordering::Equal {
        return true;
    }
    if ordering == Ordering::Less {
        *out = b;
    } else {
        *out = c;
    }
    false
}
example::if_else:
        cmp     rsi, rdx
        je      .LBB0_2
        cmovl   rcx, rdx
        mov     qword ptr [rdi], rcx
.LBB0_2:
        cmp     rsi, rdx
        sete    al
        ret

example::contains_match_:
        cmp     rsi, rdx
        jl      .LBB1_2
        mov     al, 1
        mov     rdx, rcx
        je      .LBB1_3
.LBB1_2:
        mov     qword ptr [rdi], rdx
        xor     eax, eax
.LBB1_3:
        ret

example::if_else_cmp:
        cmp     rsi, rdx
        jl      .LBB2_2
        mov     al, 1
        mov     rdx, rcx
        je      .LBB2_3
.LBB2_2:
        mov     qword ptr [rdi], rdx
        xor     eax, eax
.LBB2_3:
        ret

@Dylan-DPC Dylan-DPC added the C-enhancement Category: An issue proposing an enhancement or a PR with one. label Feb 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-enhancement Category: An issue proposing an enhancement or a PR with one.
Projects
None yet
Development

No branches or pull requests

3 participants