Skip to content

InstCombine introduces unnecessary and 1 when folding trunc nuw+zext #134908

Open
@scottmcm

Description

@scottmcm

Rust in which we spotted this originally: https://rust.godbolt.org/z/Knr5jdEY5, cc rust-lang/rust#139098 (comment)

Take this input IR:

define noundef range(i8 0, 14) i8 @match0(i8 noundef range(i8 0, 3) %0) unnamed_addr {
start:
  %1 = icmp eq i8 %0, 2
  %_2 = select i1 %1, i64 1, i64 0
  %2 = trunc nuw i64 %_2 to i1
  br i1 %2, label %bb2, label %bb3

bb2:                                              ; preds = %start
  br label %bb4

bb3:                                              ; preds = %start
  %b = trunc nuw i8 %0 to i1
  %3 = zext i1 %b to i8
  br label %bb4

bb4:                                              ; preds = %bb2, %bb3
  %_0.sroa.0.0 = phi i8 [ 13, %bb2 ], [ %3, %bb3 ]
  ret i8 %_0.sroa.0.0
}

Today https://llvm.godbolt.org/z/vnfGGxfbr, --passes=instcombine transforms that to

source_filename = "/app/example.ll"

define noundef range(i8 0, 14) i8 @match0(i8 noundef range(i8 0, 3) %0) unnamed_addr {
  %1 = icmp eq i8 %0, 2
  br i1 %1, label %bb2, label %bb3

bb2:                                              ; preds = %start
  br label %bb4

bb3:                                              ; preds = %start
  %2 = and i8 %0, 1 ; 😢
  br label %bb4

bb4:                                              ; preds = %bb3, %bb2
  %_0.sroa.0.0 = phi i8 [ 13, %bb2 ], [ %2, %bb3 ]
  ret i8 %_0.sroa.0.0
}

However it should not be adding that and i8 %0, 1 -- the trunc nuw means it ought to know it doesn't need to do that.

It should instead be emitting https://alive2.llvm.org/ce/z/oN3dig

define noundef range(i8 0, 14) i8 @tgt(i8 noundef range(i8 0, 3) %0) unnamed_addr {
start:
  %1 = icmp eq i8 %0, 2
  br i1 %1, label %bb2, label %bb3

bb2:                                              ; preds = %start
  br label %bb4

bb3:                                              ; preds = %start
  br label %bb4

bb4:                                              ; preds = %bb3, %bb2
  %_0.sroa.0.0 = phi i8 [ 13, %bb2 ], [ %0, %bb3 ]
  ret i8 %_0.sroa.0.0
}

Note that the correctness for this doesn't depend on the range information; removing that from the parameter it still validates https://alive2.llvm.org/ce/z/_ed2Ch.

(If you run a full -O2 or -O3 then CVP will get rid of the and, but that's not run in -O1. And InstCombine has the information it needs to do it correctly anyway, AFAICT, so it just should.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    llvm:instcombineCovers the InstCombine, InstSimplify and AggressiveInstCombine passes

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions