[llvm] f7bb060 - [SelectionDAG] SimplifySetCC - Improve shifted range checks with add offsets (#207955)

via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 14 14:59:28 PDT 2026


Author: 陈子昂
Date: 2026-08-15T05:59:24+08:00
New Revision: f7bb0605d73c2bef79aa27ffa4bc58f4f1d73e78

URL: https://github.com/llvm/llvm-project/commit/f7bb0605d73c2bef79aa27ffa4bc58f4f1d73e78
DIFF: https://github.com/llvm/llvm-project/commit/f7bb0605d73c2bef79aa27ffa4bc58f4f1d73e78.diff

LOG: [SelectionDAG] SimplifySetCC - Improve shifted range checks with add offsets (#207955)

SelectionDAG currently shrinks large unsigned compare immediates by
shifting the compare operand as a whole. For top-bit range checks that
have been canonicalized to `icmp ult (add x, C), Width`, this can
preserve the pre-shift add and lead to extra masks, zero-extends, or
large immediates.

When the add offset and range width are aligned to the selected shift
and the original unsigned range does not wrap, move the offset after the
shift instead. This lets cases such as checking whether `x >> 48` is in
`[10, 20)` lower to shift/add/cmp.

Fixes #172674

Added: 
    llvm/test/CodeGen/X86/icmp-range-check-shift.ll

Modified: 
    llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
    llvm/test/CodeGen/X86/combine-i64-trunc-srl-add.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 97c998b6b842c..af93a2a3d2388 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -5583,10 +5583,34 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
         } else {
           ShiftBits = C1.countr_zero();
         }
+        APInt RangeWidth = NewC;
         NewC.lshrInPlace(ShiftBits);
         if (ShiftBits && NewC.getSignificantBits() <= 64 &&
             isLegalICmpImmediate(NewC.getSExtValue()) &&
             !shouldAvoidTransformToShift(ShValTy, ShiftBits)) {
+          // If this is an offset range check, try to move the offset after the
+          // shift to avoid preserving the pre-shift add with a mask.
+          if (N0.getOpcode() == ISD::ADD && N0.hasOneUse()) {
+            if (auto *AddC = isConstOrConstSplat(N0.getOperand(1))) {
+              const APInt &AddVal = AddC->getAPIntValue();
+              if (AddVal.countr_zero() >= ShiftBits) {
+                APInt RangeLower = -AddVal;
+                bool Overflow;
+                (void)RangeLower.uadd_ov(RangeWidth, Overflow);
+                if (!RangeWidth.isZero() && !Overflow) {
+                  SDValue Shift = DAG.getNode(
+                      ISD::SRL, dl, ShValTy, N0.getOperand(0),
+                      DAG.getShiftAmountConstant(ShiftBits, ShValTy, dl));
+                  APInt Offset = -RangeLower.lshr(ShiftBits);
+                  SDValue ShiftedAdd =
+                      DAG.getNode(ISD::ADD, dl, ShValTy, Shift,
+                                  DAG.getConstant(Offset, dl, ShValTy));
+                  SDValue CmpRHS = DAG.getConstant(NewC, dl, ShValTy);
+                  return DAG.getSetCC(dl, VT, ShiftedAdd, CmpRHS, NewCond);
+                }
+              }
+            }
+          }
           SDValue Shift =
               DAG.getNode(ISD::SRL, dl, ShValTy, N0,
                           DAG.getShiftAmountConstant(ShiftBits, ShValTy, dl));

diff  --git a/llvm/test/CodeGen/X86/combine-i64-trunc-srl-add.ll b/llvm/test/CodeGen/X86/combine-i64-trunc-srl-add.ll
index f7906e5a009ae..27cca3c55ed0c 100644
--- a/llvm/test/CodeGen/X86/combine-i64-trunc-srl-add.ll
+++ b/llvm/test/CodeGen/X86/combine-i64-trunc-srl-add.ll
@@ -23,9 +23,8 @@ define i1 @test_ult_add(i64 %x) {
 ; X64-LABEL: test_ult_add:
 ; X64:       # %bb.0:
 ; X64-NEXT:    shrq $48, %rdi
-; X64-NEXT:    addl $14, %edi
-; X64-NEXT:    movzwl %di, %eax
-; X64-NEXT:    cmpl $3, %eax
+; X64-NEXT:    addl $-65522, %edi # imm = 0xFFFF000E
+; X64-NEXT:    cmpl $3, %edi
 ; X64-NEXT:    setb %al
 ; X64-NEXT:    retq
   %add = add i64 3940649673949184, %x
@@ -230,13 +229,12 @@ define i32 @test_trunc_xor_2(i64 %x) {
 define i32 @pr128158(i64 %x) {
 ; X64-LABEL: pr128158:
 ; X64:       # %bb.0: # %entry
-; X64-NEXT:    movabsq $-4294967296, %rax # imm = 0xFFFFFFFF00000000
-; X64-NEXT:    addq %rdi, %rax
-; X64-NEXT:    shrq $32, %rax
+; X64-NEXT:    shrq $32, %rdi
+; X64-NEXT:    decq %rdi
 ; X64-NEXT:    .p2align 4
 ; X64-NEXT:  .LBB16_1: # %for.body
 ; X64-NEXT:    # =>This Inner Loop Header: Depth=1
-; X64-NEXT:    cmpl $9, %eax
+; X64-NEXT:    cmpq $9, %rdi
 ; X64-NEXT:    jb .LBB16_1
 ; X64-NEXT:  # %bb.2: # %exit
 ; X64-NEXT:    xorl %eax, %eax

diff  --git a/llvm/test/CodeGen/X86/icmp-range-check-shift.ll b/llvm/test/CodeGen/X86/icmp-range-check-shift.ll
new file mode 100644
index 0000000000000..3c0e919461940
--- /dev/null
+++ b/llvm/test/CodeGen/X86/icmp-range-check-shift.ll
@@ -0,0 +1,181 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple=x86_64-- | FileCheck %s --check-prefixes=X64
+; RUN: llc < %s -mtriple=i686-- | FileCheck %s --check-prefixes=X86
+
+; Test for https://github.com/llvm/llvm-project/issues/172674.
+
+define i1 @top_i16_range(i64 %x) nounwind {
+; X64-LABEL: top_i16_range:
+; X64:       # %bb.0:
+; X64-NEXT:    shrq $49, %rdi
+; X64-NEXT:    addl $-5, %edi
+; X64-NEXT:    cmpl $5, %edi
+; X64-NEXT:    setb %al
+; X64-NEXT:    retq
+;
+; X86-LABEL: top_i16_range:
+; X86:       # %bb.0:
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    shrl $17, %eax
+; X86-NEXT:    xorl %ecx, %ecx
+; X86-NEXT:    addl $-5, %eax
+; X86-NEXT:    adcl $-1, %ecx
+; X86-NEXT:    cmpl $5, %eax
+; X86-NEXT:    sbbl $0, %ecx
+; X86-NEXT:    setb %al
+; X86-NEXT:    retl
+  %offset = add i64 %x, -2814749767106560
+  %in.range = icmp ult i64 %offset, 2814749767106560
+  ret i1 %in.range
+}
+
+define i1 @top_i32_range(i64 %x) nounwind {
+; X64-LABEL: top_i32_range:
+; X64:       # %bb.0:
+; X64-NEXT:    shrq $32, %rdi
+; X64-NEXT:    addq $-123, %rdi
+; X64-NEXT:    cmpq $333, %rdi # imm = 0x14D
+; X64-NEXT:    setb %al
+; X64-NEXT:    retq
+;
+; X86-LABEL: top_i32_range:
+; X86:       # %bb.0:
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    xorl %ecx, %ecx
+; X86-NEXT:    addl $-123, %eax
+; X86-NEXT:    adcl $-1, %ecx
+; X86-NEXT:    cmpl $333, %eax # imm = 0x14D
+; X86-NEXT:    sbbl $0, %ecx
+; X86-NEXT:    setb %al
+; X86-NEXT:    retl
+  %offset = add i64 %x, -528280977408
+  %in.range = icmp ult i64 %offset, 1430224109568
+  ret i1 %in.range
+}
+
+define i1 @top_i32_range_uge(i64 %x) nounwind {
+; X64-LABEL: top_i32_range_uge:
+; X64:       # %bb.0:
+; X64-NEXT:    shrq $32, %rdi
+; X64-NEXT:    addq $-123, %rdi
+; X64-NEXT:    cmpq $333, %rdi # imm = 0x14D
+; X64-NEXT:    setae %al
+; X64-NEXT:    retq
+;
+; X86-LABEL: top_i32_range_uge:
+; X86:       # %bb.0:
+; X86-NEXT:    pushl %esi
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    xorl %ecx, %ecx
+; X86-NEXT:    addl $-123, %eax
+; X86-NEXT:    movl $0, %edx
+; X86-NEXT:    adcl $-1, %edx
+; X86-NEXT:    movl $332, %esi # imm = 0x14C
+; X86-NEXT:    cmpl %eax, %esi
+; X86-NEXT:    sbbl %edx, %ecx
+; X86-NEXT:    setb %al
+; X86-NEXT:    popl %esi
+; X86-NEXT:    retl
+  %offset = add i64 %x, -528280977408
+  %out.range = icmp uge i64 %offset, 1430224109568
+  ret i1 %out.range
+}
+
+define i1 @top_i16_range_ule(i64 %x) nounwind {
+; X64-LABEL: top_i16_range_ule:
+; X64:       # %bb.0:
+; X64-NEXT:    shrq $49, %rdi
+; X64-NEXT:    addl $-5, %edi
+; X64-NEXT:    cmpl $5, %edi
+; X64-NEXT:    setb %al
+; X64-NEXT:    retq
+;
+; X86-LABEL: top_i16_range_ule:
+; X86:       # %bb.0:
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    shrl $17, %eax
+; X86-NEXT:    xorl %ecx, %ecx
+; X86-NEXT:    addl $-5, %eax
+; X86-NEXT:    adcl $-1, %ecx
+; X86-NEXT:    cmpl $5, %eax
+; X86-NEXT:    sbbl $0, %ecx
+; X86-NEXT:    setb %al
+; X86-NEXT:    retl
+  %offset = add i64 %x, -2814749767106560
+  %in.range = icmp ule i64 %offset, 2814749767106559
+  ret i1 %in.range
+}
+
+define i1 @top_i8_range(i64 %x) nounwind {
+; X64-LABEL: top_i8_range:
+; X64:       # %bb.0:
+; X64-NEXT:    shrq $56, %rdi
+; X64-NEXT:    addl $-200, %edi
+; X64-NEXT:    cmpl $5, %edi
+; X64-NEXT:    setb %al
+; X64-NEXT:    retq
+;
+; X86-LABEL: top_i8_range:
+; X86:       # %bb.0:
+; X86-NEXT:    movzbl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    xorl %ecx, %ecx
+; X86-NEXT:    addl $-200, %eax
+; X86-NEXT:    adcl $-1, %ecx
+; X86-NEXT:    cmpl $5, %eax
+; X86-NEXT:    sbbl $0, %ecx
+; X86-NEXT:    setb %al
+; X86-NEXT:    retl
+  %offset = add i64 %x, 4035225266123964416
+  %in.range = icmp ult i64 %offset, 360287970189639680
+  ret i1 %in.range
+}
+
+define i1 @signed_min_add_offset(i64 %x) nounwind {
+; X64-LABEL: signed_min_add_offset:
+; X64:       # %bb.0:
+; X64-NEXT:    shrq $60, %rdi
+; X64-NEXT:    addl $-8, %edi
+; X64-NEXT:    cmpl $3, %edi
+; X64-NEXT:    setb %al
+; X64-NEXT:    retq
+;
+; X86-LABEL: signed_min_add_offset:
+; X86:       # %bb.0:
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    shrl $28, %eax
+; X86-NEXT:    xorl %ecx, %ecx
+; X86-NEXT:    addl $-8, %eax
+; X86-NEXT:    adcl $-1, %ecx
+; X86-NEXT:    cmpl $3, %eax
+; X86-NEXT:    sbbl $0, %ecx
+; X86-NEXT:    setb %al
+; X86-NEXT:    retl
+  %offset = add i64 %x, -9223372036854775808
+  %in.range = icmp ult i64 %offset, 3458764513820540928
+  ret i1 %in.range
+}
+
+; The selected range wraps around the 8-bit boundary, so the offset cannot be
+; moved after the shift without preserving that wrapping behavior.
+define i1 @wrapping_range(i64 %x) nounwind {
+; X64-LABEL: wrapping_range:
+; X64:       # %bb.0:
+; X64-NEXT:    movabsq $432345564227567616, %rax # imm = 0x600000000000000
+; X64-NEXT:    addq %rdi, %rax
+; X64-NEXT:    shrq $58, %rax
+; X64-NEXT:    cmpl $5, %eax
+; X64-NEXT:    setb %al
+; X64-NEXT:    retq
+;
+; X86-LABEL: wrapping_range:
+; X86:       # %bb.0:
+; X86-NEXT:    movl $100663296, %eax # imm = 0x6000000
+; X86-NEXT:    addl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    shrl $26, %eax
+; X86-NEXT:    cmpl $5, %eax
+; X86-NEXT:    setb %al
+; X86-NEXT:    retl
+  %offset = add i64 %x, 432345564227567616
+  %in.range = icmp ult i64 %offset, 1441151880758558720
+  ret i1 %in.range
+}


        


More information about the llvm-commits mailing list