[llvm] [InstCombine] Fold trunc(umin/umax(zext(x), y & mask)) to narrower umin/umax (PR #173221)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Sat Dec 27 02:24:45 PST 2025


================
@@ -0,0 +1,76 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define i16 @umin(i32 %arg1, i32 %arg2, ptr %arg0) {
+; CHECK-LABEL: define i16 @umin(
+; CHECK-SAME: i32 [[ARG1:%.*]], i32 [[ARG2:%.*]], ptr [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = udiv i32 [[ARG2]], [[ARG1]]
+; CHECK-NEXT:    [[V1:%.*]] = load i16, ptr [[ARG0]], align 2
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[V0]] to i16
+; CHECK-NEXT:    [[V4:%.*]] = call i16 @llvm.umin.i16(i16 [[TMP1]], i16 [[V1]])
+; CHECK-NEXT:    ret i16 [[V4]]
+;
+  %v0 = udiv i32 %arg2, %arg1
+  %v1 = load i16, ptr %arg0, align 2
+  %v2 = and i32 %v0, 65535
+  %v3 = zext i16 %v1 to i32
+  %v4 = call i32 @llvm.umin.i32(i32 %v2, i32 %v3)
+  %v5 = trunc nuw i32 %v4 to i16
+  ret i16 %v5
+}
+
+define i16 @umin1(i32 %arg1, i32 %arg2, ptr %arg0) {
+; CHECK-LABEL: define i16 @umin1(
+; CHECK-SAME: i32 [[ARG1:%.*]], i32 [[ARG2:%.*]], ptr [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = udiv i32 [[ARG2]], [[ARG1]]
+; CHECK-NEXT:    [[V1:%.*]] = load i16, ptr [[ARG0]], align 2
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[V0]] to i16
+; CHECK-NEXT:    [[TMP2:%.*]] = and i16 [[TMP1]], -6
+; CHECK-NEXT:    [[V4:%.*]] = call i16 @llvm.umin.i16(i16 [[TMP2]], i16 [[V1]])
+; CHECK-NEXT:    ret i16 [[V4]]
+;
+  %v0 = udiv i32 %arg2, %arg1
+  %v1 = load i16, ptr %arg0, align 2
+  %v2 = and i32 %v0, 65530
+  %v3 = zext i16 %v1 to i32
+  %v4 = call i32 @llvm.umin.i32(i32 %v2, i32 %v3)
+  %v5 = trunc nuw i32 %v4 to i16
+  ret i16 %v5
+}
+
+define i16 @umax(i32 %arg1, i32 %arg2, ptr %arg0) {
+; CHECK-LABEL: define i16 @umax(
+; CHECK-SAME: i32 [[ARG1:%.*]], i32 [[ARG2:%.*]], ptr [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = udiv i32 [[ARG2]], [[ARG1]]
+; CHECK-NEXT:    [[V1:%.*]] = load i16, ptr [[ARG0]], align 2
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[V0]] to i16
+; CHECK-NEXT:    [[V4:%.*]] = call i16 @llvm.umax.i16(i16 [[TMP1]], i16 [[V1]])
+; CHECK-NEXT:    ret i16 [[V4]]
+;
+  %v0 = udiv i32 %arg2, %arg1
+  %v1 = load i16, ptr %arg0, align 2
+  %v2 = and i32 %v0, 65535
+  %v3 = zext i16 %v1 to i32
+  %v4 = call i32 @llvm.umax.i32(i32 %v2, i32 %v3)
+  %v5 = trunc nuw i32 %v4 to i16
+  ret i16 %v5
+}
+
+define i16 @umax1(i32 %arg1, i32 %arg2, ptr %arg0) {
+; CHECK-LABEL: define i16 @umax1(
+; CHECK-SAME: i32 [[ARG1:%.*]], i32 [[ARG2:%.*]], ptr [[ARG0:%.*]]) {
+; CHECK-NEXT:    [[V0:%.*]] = udiv i32 [[ARG2]], [[ARG1]]
+; CHECK-NEXT:    [[V1:%.*]] = load i16, ptr [[ARG0]], align 2
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[V0]] to i16
+; CHECK-NEXT:    [[TMP2:%.*]] = and i16 [[TMP1]], -6
+; CHECK-NEXT:    [[V4:%.*]] = call i16 @llvm.umax.i16(i16 [[TMP2]], i16 [[V1]])
+; CHECK-NEXT:    ret i16 [[V4]]
+;
+  %v0 = udiv i32 %arg2, %arg1
+  %v1 = load i16, ptr %arg0, align 2
+  %v2 = and i32 %v0, 65530
+  %v3 = zext i16 %v1 to i32
+  %v4 = call i32 @llvm.umax.i32(i32 %v2, i32 %v3)
+  %v5 = trunc nuw i32 %v4 to i16
+  ret i16 %v5
+}
----------------
nikic wrote:

Missing negative tests where the transform is invalid because the mask checks fail.

https://github.com/llvm/llvm-project/pull/173221


More information about the llvm-commits mailing list