[llvm] [InstCombine] fold ((x - 1) | (2^k - 1)) + 1 to (x + (2^k - 1)) & -(2^k) (PR #216436)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Sat Aug 15 02:48:59 PDT 2026
================
@@ -287,5 +287,120 @@ define <2 x i32> @align_up_vec_poison_elt(<2 x i32> %x) {
ret <2 x i32> %r
}
+;
+; ((X - 1) | C) + 1 -> (X + C) & ~C, for power-of-two C
+;
+
+define i32 @align_up_via_or(i32 %x) {
+; CHECK-LABEL: @align_up_via_or(
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], 4095
+; CHECK-NEXT: [[ADD:%.*]] = and i32 [[TMP1]], -4096
+; CHECK-NEXT: ret i32 [[ADD]]
+;
+ %sub = add i32 %x, -1
+ %or = or i32 %sub, 4095
+ %add = add i32 %or, 1
+ ret i32 %add
+}
+
+define i32 @align_up_via_or_commuted(i32 %x) {
+; CHECK-LABEL: @align_up_via_or_commuted(
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], 4095
+; CHECK-NEXT: [[ADD:%.*]] = and i32 [[TMP1]], -4096
+; CHECK-NEXT: ret i32 [[ADD]]
+;
+ %sub = add i32 %x, -1
+ %or = or i32 %sub, 4095
+ %add = add i32 1, %or
+ ret i32 %add
+}
+
+define i32 @align_up_via_or_commuted_or(i32 %x) {
+; CHECK-LABEL: @align_up_via_or_commuted_or(
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], 4095
+; CHECK-NEXT: [[ADD:%.*]] = and i32 [[TMP1]], -4096
+; CHECK-NEXT: ret i32 [[ADD]]
+;
+ %sub = add i32 %x, -1
+ %or = or i32 4095, %sub
+ %add = add i32 %or, 1
+ ret i32 %add
+}
+
+define <2 x i32> @align_up_via_or_vec(<2 x i32> %x) {
+; CHECK-LABEL: @align_up_via_or_vec(
+; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i32> [[X:%.*]], splat (i32 4095)
+; CHECK-NEXT: [[ADD:%.*]] = and <2 x i32> [[TMP1]], splat (i32 -4096)
+; CHECK-NEXT: ret <2 x i32> [[ADD]]
+;
+ %sub = add <2 x i32> %x, splat (i32 -1)
+ %or = or <2 x i32> %sub, splat (i32 4095)
+ %add = add <2 x i32> %or, splat (i32 1)
+ ret <2 x i32> %add
+}
+
+; negative test - the mask is not a low bit mask
+
+
+define i32 @align_up_via_or_not_lowbitmask(i32 %x) {
+; CHECK-LABEL: @align_up_via_or_not_lowbitmask(
+; CHECK-NEXT: [[SUB:%.*]] = add i32 [[X:%.*]], -1
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[SUB]], 13
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[OR]], 1
+; CHECK-NEXT: ret i32 [[ADD]]
+;
+ %sub = add i32 %x, -1
+ %or = or i32 %sub, 13
+ %add = add i32 %or, 1
+ ret i32 %add
+}
+
+; negative test - extra use of the or
+
+define i32 @align_up_via_or_multiuse_or(i32 %x) {
+; CHECK-LABEL: @align_up_via_or_multiuse_or(
+; CHECK-NEXT: [[SUB:%.*]] = add i32 [[X:%.*]], -1
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[SUB]], 4095
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[OR]], 1
+; CHECK-NEXT: call void @use(i32 [[OR]])
+; CHECK-NEXT: ret i32 [[ADD]]
+;
+ %sub = add i32 %x, -1
+ %or = or i32 %sub, 4095
+ %add = add i32 %or, 1
+ call void @use(i32 %or)
+ ret i32 %add
+}
+
+; extra use of the sub is not affecting
+
+define i32 @align_up_via_or_multiuse_sub(i32 %x) {
+; CHECK-LABEL: @align_up_via_or_multiuse_sub(
+; CHECK-NEXT: [[SUB:%.*]] = add i32 [[X:%.*]], -1
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X]], 4095
+; CHECK-NEXT: [[ADD:%.*]] = and i32 [[TMP1]], -4096
+; CHECK-NEXT: call void @use(i32 [[SUB]])
+; CHECK-NEXT: ret i32 [[ADD]]
+;
+ %sub = add i32 %x, -1
+ %or = or i32 %sub, 4095
+ %add = add i32 %or, 1
+ call void @use(i32 %sub)
+ ret i32 %add
+}
+
+; nsw/nuw on the source add are dropped
+
+define i32 @align_up_via_or_nsw_nuw(i32 %x){
+; CHECK-LABEL: @align_up_via_or_nsw_nuw(
+; CHECK-NEXT: ret i32 0
+;
+ %sub = add nuw nsw i32 %x, -1
----------------
dtcxzyw wrote:
This issue is still standing.
https://github.com/llvm/llvm-project/pull/216436
More information about the llvm-commits
mailing list