[llvm] [llvm][InstCombine] Fold signum(x) into scmp(x, 0) (PR #143445)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 11 23:30:11 PDT 2025
================
@@ -0,0 +1,254 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -passes=instcombine -S < %s | FileCheck %s
+
+; Fold (x < y) ? -1 : zext(x != y) to scmp(x, y)
+define i32 @scmp_x_y_from_lt(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @scmp_x_y_from_lt(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT: ret i32 [[SEL]]
+;
+ %cmp1 = icmp ne i32 %x, %y
+ %zext = zext i1 %cmp1 to i32
+ %cmp2 = icmp slt i32 %x, %y
+ %sel = select i1 %cmp2, i32 -1, i32 %zext
+ ret i32 %sel
+}
+
+; Fold (x < y) ? -1 : zext(x > y) to scmp(x, y)
+define i32 @scmp_x_y_from_lt_gt(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @scmp_x_y_from_lt_gt(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT: ret i32 [[SEL]]
+;
+ %cmp1 = icmp sgt i32 %x, %y
+ %zext = zext i1 %cmp1 to i32
+ %cmp2 = icmp slt i32 %x, %y
+ %sel = select i1 %cmp2, i32 -1, i32 %zext
+ ret i32 %sel
+}
+
+; Fold (x > y) ? 1 : sext(x != y) to scmp(x, y)
+define i32 @scmp_x_y_from_gt_sext_ne(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @scmp_x_y_from_gt_sext_ne(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT: ret i32 [[SEL]]
+;
+ %cmp1 = icmp ne i32 %x, %y
+ %sext = sext i1 %cmp1 to i32
+ %cmp2 = icmp sgt i32 %x, %y
+ %sel = select i1 %cmp2, i32 1, i32 %sext
+ ret i32 %sel
+}
+
+; Fold (x > y) ? 1 : sext(x < y) to scmp(x, y)
+define i32 @scmp_x_y_from_gt_sext_lt(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @scmp_x_y_from_gt_sext_lt(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT: ret i32 [[SEL]]
+;
+ %cmp1 = icmp slt i32 %x, %y
+ %sext = sext i1 %cmp1 to i32
+ %cmp2 = icmp sgt i32 %x, %y
+ %sel = select i1 %cmp2, i32 1, i32 %sext
+ ret i32 %sel
+}
+
+; Fold (x <= y - 1) ? -1 : zext(x != y) to ucmp(x, y)
+define i32 @ucmp_x_y_from_le_sub_zext_ne(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @ucmp_x_y_from_le_sub_zext_ne(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.ucmp.i32.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT: ret i32 [[SEL]]
+;
+ %ym1 = sub i32 %y, 1
+ %cmp1 = icmp ule i32 %x, %ym1
+ %neq = icmp ne i32 %x, %y
+ %zext = zext i1 %neq to i32
+ %sel = select i1 %cmp1, i32 -1, i32 %zext
+ ret i32 %sel
+}
+
+; Fold (x <= y - 1) ? -1 : zext(x > y) to ucmp(x, y)
+define i32 @ucmp_x_y_from_le_sub_zext_gt(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @ucmp_x_y_from_le_sub_zext_gt(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.ucmp.i32.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT: ret i32 [[SEL]]
+;
+ %ym1 = sub i32 %y, 1
+ %cmp1 = icmp ule i32 %x, %ym1
+ %gt = icmp ugt i32 %x, %y
+ %zext = zext i1 %gt to i32
+ %sel = select i1 %cmp1, i32 -1, i32 %zext
+ ret i32 %sel
+}
+
+; Fold (x >= y + 1) ? 1 : sext(x != y) to ucmp(x, y)
+define i32 @ucmp_x_y_from_ge_add_sext_ne(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @ucmp_x_y_from_ge_add_sext_ne(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.ucmp.i32.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT: ret i32 [[SEL]]
+;
+ %yp1 = add i32 %y, 1
+ %cmp1 = icmp uge i32 %x, %yp1
+ %neq = icmp ne i32 %x, %y
+ %sext = sext i1 %neq to i32
+ %sel = select i1 %cmp1, i32 1, i32 %sext
+ ret i32 %sel
+}
+
+; Fold (x >= y + 1) ? 1 : sext(x < y) to ucmp(x, y)
+define i32 @ucmp_x_y_from_ge_add_sext_lt(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @ucmp_x_y_from_ge_add_sext_lt(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.ucmp.i32.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT: ret i32 [[SEL]]
+;
+ %yp1 = add i32 %y, 1
+ %cmp1 = icmp uge i32 %x, %yp1
+ %lt = icmp ult i32 %x, %y
+ %sext = sext i1 %lt to i32
+ %sel = select i1 %cmp1, i32 1, i32 %sext
+ ret i32 %sel
+}
+
+; Fold (x > y - 1) ? zext(x != y) : -1 to scmp(x, y)
+define i32 @scmp_x_y_from_gt_sub_zext_ne(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @scmp_x_y_from_gt_sub_zext_ne(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT: ret i32 [[SEL]]
+;
+ %ym1 = sub i32 %y, 1
+ %cmp1 = icmp sgt i32 %x, %ym1
+ %ne = icmp ne i32 %x, %y
+ %zext = zext i1 %ne to i32
+ %sel = select i1 %cmp1, i32 %zext, i32 -1
+ ret i32 %sel
+}
+
+; Fold (x > y - 1) ? zext(x > y) : -1 to ucmp(x, y)
+define i32 @ucmp_x_y_from_gt_sub_zext_gt(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @ucmp_x_y_from_gt_sub_zext_gt(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.ucmp.i32.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT: ret i32 [[SEL]]
+;
+ %ym1 = sub i32 %y, 1
+ %cmp1 = icmp ugt i32 %x, %ym1
+ %gt = icmp ugt i32 %x, %y
+ %zext = zext i1 %gt to i32
+ %sel = select i1 %cmp1, i32 %zext, i32 -1
+ ret i32 %sel
+}
+
+; Fold (x < y + 1) ? sext(x != y) : 1 to scmp(x, y)
+define i32 @scmp_x_y_from_lt_add_sext_ne(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @scmp_x_y_from_lt_add_sext_ne(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT: ret i32 [[SEL]]
+;
+ %yp1 = add i32 %y, 1
+ %cmp1 = icmp slt i32 %x, %yp1
+ %ne = icmp ne i32 %x, %y
+ %sext = sext i1 %ne to i32
+ %sel = select i1 %cmp1, i32 %sext, i32 1
+ ret i32 %sel
+}
+
+; Fold (x < y + 1) ? sext(x < y) : 1 to ucmp(x, y)
+define i32 @ucmp_x_y_from_lt_add_sext_lt(i32 %x, i32 %y) {
----------------
dtcxzyw wrote:
This is a miscompilation without nuw on `y+1`:
https://alive2.llvm.org/ce/z/-YEfDZ
If you set nuw on `y+1`, `x <u y +nuw 1` will be canonicalized into `x <=u y`. The canonical pattern has been handled by InstCombine: https://godbolt.org/z/jPx3seqTM
https://github.com/llvm/llvm-project/pull/143445
More information about the llvm-commits
mailing list