Skip to content

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

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

Open
scottmcm opened this issue Apr 8, 2025 · 2 comments
Open

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

scottmcm opened this issue Apr 8, 2025 · 2 comments

Comments

@scottmcm
Copy link

scottmcm commented Apr 8, 2025

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.)

@nikic
Copy link
Contributor

nikic commented Apr 8, 2025

See #88609. We currently do this because not emitting the and 1 causes regressions.

@scottmcm
Copy link
Author

scottmcm commented Apr 8, 2025

Ah :/

Shame it can't introduce, say, a range operand bundle there instead or something.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants