[llvm] [InstCombine] Recognize X - 1 as nonnegative when X is positive (PR #223168)
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Sun Sep 13 02:39:05 PDT 2026
================
@@ -903,3 +903,106 @@ end: ; preds = %unreachable, %entry
%3 = extractelement <2 x i16> %2, i64 0
ret i16 %3
}
+
+; Issue #221943: X - 1 should be nonnegative when X > 0.
+; The assume that %magx > 0 should allow InstCombine to recognize that
+; %mag = %magx - 1 is nonnegative, enabling the copysign idiom fold.
+define float @copysign_idiom_sub1_positive(float %x, i32 %magx) {
+; CHECK-LABEL: @copysign_idiom_sub1_positive(
+; CHECK-NEXT: [[MAG:%.*]] = add nsw i32 [[MAGX:%.*]], -1
+; CHECK-NEXT: [[POSITIVE:%.*]] = icmp sgt i32 [[MAGX]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[POSITIVE]])
+; CHECK-NEXT: [[TMP1:%.*]] = bitcast i32 [[MAG]] to float
+; CHECK-NEXT: [[Y:%.*]] = call float @llvm.copysign.f32(float [[TMP1]], float [[X:%.*]])
+; CHECK-NEXT: ret float [[Y]]
+;
+ %mag = add i32 %magx, -1
+ %positive = icmp sgt i32 %magx, 0
+ call void @llvm.assume(i1 %positive)
+ %bits = bitcast float %x to i32
+ %sign = and i32 %bits, -2147483648
+ %res = or i32 %mag, %sign
+ %y = bitcast i32 %res to float
+ ret float %y
+}
+
+; Test with sub instruction instead of add with -1.
+define float @copysign_idiom_sub1_positive_sub(float %x, i32 %magx) {
+; CHECK-LABEL: @copysign_idiom_sub1_positive_sub(
+; CHECK-NEXT: [[MAG:%.*]] = add nsw i32 [[MAGX:%.*]], -1
+; CHECK-NEXT: [[POSITIVE:%.*]] = icmp sgt i32 [[MAGX]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[POSITIVE]])
+; CHECK-NEXT: [[TMP1:%.*]] = bitcast i32 [[MAG]] to float
+; CHECK-NEXT: [[Y:%.*]] = call float @llvm.copysign.f32(float [[TMP1]], float [[X:%.*]])
+; CHECK-NEXT: ret float [[Y]]
+;
+ %mag = sub i32 %magx, 1
+ %positive = icmp sgt i32 %magx, 0
+ call void @llvm.assume(i1 %positive)
+ %bits = bitcast float %x to i32
+ %sign = and i32 %bits, -2147483648
+ %res = or i32 %mag, %sign
+ %y = bitcast i32 %res to float
+ ret float %y
+}
+
+; Test with i64 for double precision.
+define double @copysign_idiom_sub1_positive_f64(double %x, i64 %magx) {
+; CHECK-LABEL: @copysign_idiom_sub1_positive_f64(
+; CHECK-NEXT: [[MAG:%.*]] = add nsw i64 [[MAGX:%.*]], -1
+; CHECK-NEXT: [[POSITIVE:%.*]] = icmp sgt i64 [[MAGX]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[POSITIVE]])
+; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[MAG]] to double
+; CHECK-NEXT: [[Y:%.*]] = call double @llvm.copysign.f64(double [[TMP1]], double [[X:%.*]])
+; CHECK-NEXT: ret double [[Y]]
+;
+ %mag = add i64 %magx, -1
+ %positive = icmp sgt i64 %magx, 0
+ call void @llvm.assume(i1 %positive)
+ %bits = bitcast double %x to i64
+ %sign = and i64 %bits, -9223372036854775808
+ %res = or i64 %mag, %sign
+ %y = bitcast i64 %res to double
+ ret double %y
+}
+
+; Negative test: %magx >= 0 (nonnegative) is not enough, need %magx > 0 (positive).
+; %magx could be 0, so %mag = %magx - 1 could be -1.
+define float @copysign_idiom_sub1_nonnegative_not_positive(float %x, i32 %magx) {
+; CHECK-LABEL: @copysign_idiom_sub1_nonnegative_not_positive(
+; CHECK-NEXT: [[MAG:%.*]] = add nsw i32 [[MAGX:%.*]], -1
+; CHECK-NEXT: [[NONNEG:%.*]] = icmp sgt i32 [[MAGX]], -1
+; CHECK-NEXT: call void @llvm.assume(i1 [[NONNEG]])
+; CHECK-NEXT: [[BITS:%.*]] = bitcast float [[X:%.*]] to i32
+; CHECK-NEXT: [[SIGN:%.*]] = and i32 [[BITS]], -2147483648
+; CHECK-NEXT: [[RES:%.*]] = or i32 [[MAG]], [[SIGN]]
+; CHECK-NEXT: [[Y:%.*]] = bitcast i32 [[RES]] to float
+; CHECK-NEXT: ret float [[Y]]
+;
+ %mag = add i32 %magx, -1
+ %nonneg = icmp sgt i32 %magx, -1
+ call void @llvm.assume(i1 %nonneg)
+ %bits = bitcast float %x to i32
+ %sign = and i32 %bits, -2147483648
+ %res = or i32 %mag, %sign
+ %y = bitcast i32 %res to float
+ ret float %y
+}
+
+; Negative test: no assume, so we don't know if %magx is positive.
+define float @copysign_idiom_sub1_no_assume(float %x, i32 %magx) {
+; CHECK-LABEL: @copysign_idiom_sub1_no_assume(
+; CHECK-NEXT: [[MAG:%.*]] = add i32 [[MAGX:%.*]], -1
+; CHECK-NEXT: [[BITS:%.*]] = bitcast float [[X:%.*]] to i32
+; CHECK-NEXT: [[SIGN:%.*]] = and i32 [[BITS]], -2147483648
+; CHECK-NEXT: [[RES:%.*]] = or i32 [[MAG]], [[SIGN]]
+; CHECK-NEXT: [[Y:%.*]] = bitcast i32 [[RES]] to float
+; CHECK-NEXT: ret float [[Y]]
+;
+ %mag = add i32 %magx, -1
+ %bits = bitcast float %x to i32
+ %sign = and i32 %bits, -2147483648
+ %res = or i32 %mag, %sign
+ %y = bitcast i32 %res to float
+ ret float %y
+}
----------------
arsenm wrote:
Test vector cases
https://github.com/llvm/llvm-project/pull/223168
More information about the llvm-commits
mailing list