Skip to content

Implementing <= via 3-way comparison doesn't optimize down #59666

Closed
@scottmcm

Description

@scottmcm

I ended up here from code doing essentially a spaceship operator, then comparing against zero: ((a > b) - (a < b)) <= 0.

That could optimize away: https://alive2.llvm.org/ce/z/_jFfvV

define i1 @src(i16 %0, i16 %1) noundef {
%start:
  %_8.i.i.i = icmp ult i16 %0, %1
  %_7.neg.i.i.i = sext i1 %_8.i.i.i to i8
  %_12.i.i.i = icmp ugt i16 %0, %1
  %_11.i.i.i = zext i1 %_12.i.i.i to i8
  %2 = add nsw i8 %_7.neg.i.i.i, %_11.i.i.i
  %3 = icmp slt i8 %2, 1
  ret i1 %3
}
=>
define i1 @tgt(i16 %0, i16 %1) noundef {
%start:
  %x = icmp ule i16 %0, %1
  ret i1 %x
}
Transformation seems to be correct!

But today it doesn't: https://llvm.godbolt.org/z/WerxaczEc


Original Rust repro: https://rust.godbolt.org/z/n6b5KWWhG

pub fn spaceship(x: i16, y: i16) -> i8 {
    (x > y) as i8 - (x < y) as i8
}

pub fn check_lt(x: i16, y: i16) -> bool {
    spaceship(x, y) < 0
}
pub fn check_le(x: i16, y: i16) -> bool {
    spaceship(x, y) <= 0
}
pub fn check_gt(x: i16, y: i16) -> bool {
    spaceship(x, y) > 0
}
pub fn check_ge(x: i16, y: i16) -> bool {
    spaceship(x, y) >= 0
}

Interestingly, check_lt and check_ge both optimize down to a single icmp, exactly as hoped. But neither check_le nor check_gt does.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions