[llvm] [InstCombine]: Replace overflow calculation with intrinsic (PR #168195)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 4 03:07:33 PST 2025


================
@@ -0,0 +1,103 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+; Fold
+;
+; int result = x - y;
+; return !(INT_MIN <= result && result <= INT_MAX);
+;
+; into
+;
+; __builtin_ssub_overflow(x, y)
+
+define i1 @idiomatic_check_sub_i16(i16 %x, i16 %y) {
+; CHECK-LABEL: @idiomatic_check_sub_i16(
+; CHECK-NEXT:    [[TMP1:%.*]] = call { i16, i1 } @llvm.ssub.with.overflow.i16(i16 [[X:%.*]], i16 [[Y:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = extractvalue { i16, i1 } [[TMP1]], 1
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %3 = sext i16 %x to i32
+  %4 = sext i16 %y to i32
+  %5 = add nsw i32 %3, -32768
+  %6 = sub nsw i32 %5, %4
+  %7 = icmp ult i32 %6, -65536
+  ret i1 %7
+}
+
+define i1 @idiomatic_check_sub_i16_no_flags(i16 %x, i16 %y) {
+; CHECK-LABEL: @idiomatic_check_sub_i16_no_flags(
+; CHECK-NEXT:    [[TMP1:%.*]] = call { i16, i1 } @llvm.ssub.with.overflow.i16(i16 [[X:%.*]], i16 [[Y:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = extractvalue { i16, i1 } [[TMP1]], 1
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %3 = sext i16 %x to i32
+  %4 = sext i16 %y to i32
+  %5 = add i32 %3, -32768
+  %6 = sub i32 %5, %4
+  %7 = icmp ult i32 %6, -65536
+  ret i1 %7
+}
+
+define i1 @idiomatic_check_sub_i32(i32 %x, i32 %y) {
+; CHECK-LABEL: @idiomatic_check_sub_i32(
+; CHECK-NEXT:    [[TMP1:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
+; CHECK-NEXT:    [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %3 = sext i32 %x to i64
+  %4 = sext i32 %y to i64
+  %5 = add nsw i64 %3, -2147483648
+  %6 = sub nsw i64 %5, %4
+  %7 = icmp ult i64 %6, -4294967296
+  ret i1 %7
+}
+
+define i1 @idiomatic_check_sub_i32_negative_test_1(i32 %x, i32 %y) {
+; CHECK-LABEL: @idiomatic_check_sub_i32_negative_test_1(
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i32 [[X:%.*]] to i64
+; CHECK-NEXT:    [[TMP2:%.*]] = sext i32 [[Y:%.*]] to i64
+; CHECK-NEXT:    [[TMP3:%.*]] = sub nsw i64 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ult i64 [[TMP3]], -4294967296
+; CHECK-NEXT:    ret i1 [[TMP4]]
+;
+  %3 = sext i32 %x to i64
+  %4 = sext i32 %y to i64
+  %5 = add nsw i64 %3, 0 ; Constant wrong
+  %6 = sub nsw i64 %5, %4
+  %7 = icmp ult i64 %6, -4294967296
+  ret i1 %7
+}
+
+define i1 @idiomatic_check_sub_i32_negative_test_2(i32 %x, i32 %y) {
+; CHECK-LABEL: @idiomatic_check_sub_i32_negative_test_2(
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i32 [[X:%.*]] to i64
+; CHECK-NEXT:    [[TMP2:%.*]] = sext i32 [[Y:%.*]] to i64
+; CHECK-NEXT:    [[TMP3:%.*]] = add nsw i64 [[TMP1]], -2147483648
+; CHECK-NEXT:    [[TMP4:%.*]] = sub nsw i64 [[TMP3]], [[TMP2]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp ult i64 [[TMP4]], -4294967295
+; CHECK-NEXT:    ret i1 [[TMP5]]
+;
+  %3 = sext i32 %x to i64
+  %4 = sext i32 %y to i64
+  %5 = add nsw i64 %3, -2147483648
+  %6 = sub nsw i64 %5, %4
+  %7 = icmp ult i64 %6, -4294967295 ; Constant wrong
+  ret i1 %7
+}
+
+define i1 @idiomatic_check_sub_i32_negative_test_3(i32 %x, i32 %y) {
+; CHECK-LABEL: @idiomatic_check_sub_i32_negative_test_3(
+; CHECK-NEXT:    [[TMP1:%.*]] = sext i32 [[X:%.*]] to i64
+; CHECK-NEXT:    [[TMP2:%.*]] = sext i32 [[Y:%.*]] to i64
+; CHECK-NEXT:    [[TMP3:%.*]] = add nsw i64 [[TMP1]], -2147483648
+; CHECK-NEXT:    [[TMP4:%.*]] = sub nsw i64 [[TMP3]], [[TMP2]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp slt i64 [[TMP4]], -4294967296
+; CHECK-NEXT:    ret i1 [[TMP5]]
+;
+  %3 = sext i32 %x to i64
+  %4 = sext i32 %y to i64
+  %5 = add nsw i64 %3, -2147483648
+  %6 = sub nsw i64 %5, %4
+  %7 = icmp slt i64 %6, -4294967296 ; wrong Condition
+  ret i1 %7
+}
----------------
nikic wrote:

Please add multi-use tests. We wouldn't want to transform if there are multiple uses.

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


More information about the llvm-commits mailing list