Skip to content

Missed optimization when known bits would permit transforming an and into subtruction #146087

Open
@WaffleLapkin

Description

@WaffleLapkin

Rust in which we spotted this originally: https://godbolt.org/z/8xM3P9xP5

Take this IR:

define noundef i8 @f(i8 noundef %0) unnamed_addr {
  ; check if two highest bits are set
  %2 = lshr i8 %0, 6
  %3 = icmp eq i8 %2, 3
  br i1 %3, label %4, label %7

4:                                                ; preds = %1
  ; if so, get the value of the lower 6 bits + 1
  %5 = and i8 %0, 63
  %6 = add i8 %5, 1
  br label %8

7:                                                ; preds = %1
  br label %8

8:                                                ; preds = %7, %4
  %9 = phi i8 [ %6, %4 ], [ -1, %7 ]
  ret i8 %9
}

Today --passes=instcombine turns it into

define noundef i8 @f(i8 noundef %0) unnamed_addr {
  %2 = icmp ugt i8 %0, -65
  br i1 %2, label %3, label %6

3:
  %4 = and i8 %0, 63 ; 😢
  %5 = add nuw nsw i8 %4, 1
  br label %7

6:
  br label %7

7:
  %8 = phi i8 [ %5, %3 ], [ -1, %6 ]
  ret i8 %8
}

However the and and add could be combined too -- they are used in the branch where %0 > -65 (two highest bits in %0 are set), which means that and i8 %0, 63 (& 0b111111) could be replaced with add i8, %0, -192 (- 0b11000000) and then trivially folded with the other add. That is, the resulting IR should look like this (https://alive2.llvm.org/ce/z/Go8nxD):

define noundef i8 @tgt(i8 noundef %0) unnamed_addr {
  %2 = icmp ugt i8 %0, -65
  br i1 %2, label %3, label %6

3:
  %5 = add nuw nsw i8 %0, -191 ; 🌸
  br label %7

6:
  br label %7

7:
  %8 = phi i8 [ %5, %3 ], [ -1, %6 ]
  ret i8 %8
}

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