[llvm] Fold (a % b) lt/ge (b-1) where b is a power of 2 (PR #72504)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Sat Nov 18 09:42:01 PST 2023


dtcxzyw wrote:

> @dtcxzyw why doesn't the code optimize the following test?
> 
> ```
> define i1 @srem_slt_test1(i64 %x, i64 %C) {
> ; CHECK-LABEL: @srem_slt_test1(
> ; CHECK-NEXT:    [[PRECOND:%.*]] = icmp sgt i64 [[C:%.*]], -1
> ; CHECK-NEXT:    call void @llvm.assume(i1 [[PRECOND]])
> ; CHECK-NEXT:    [[CMINUS1:%.*]] = add nsw i64 [[C]], -1
> ; CHECK-NEXT:    [[Y:%.*]] = srem i64 [[X:%.*]], [[C]]
> ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[Y]], [[CMINUS1]]
> ; CHECK-NEXT:    ret i1 [[CMP]]
> ;
>   %precond = icmp sge i64 %C, 0
>   call void @llvm.assume(i1 %precond)
>   %Cminus1 = add i64 %C, -1
>   %y = srem i64 %x, %C
>   %cmp = icmp slt i64 %y, %Cminus1
>   ret i1 %cmp
> }
> ```

`m_APInt` only matches a constant integer scalar or a constant splat vector. If you want to handle all non-negative variables, please use `m_Value` and `isKnownNonNegative`. `isKnownNonNegative` will use the information provided by `@llvm.assume`.

For example:
```
if ((Pred == ICmpInst::ICMP_SGE || Pred == ICmpInst::ICMP_SLT) &&
        match(Op0, m_OneUse(m_SRem(m_Value(X), m_Value(Y)))) &&
        match(Op1, m_OneUse(m_c_Add(m_Deferred(Y), m_AllOnes()))) &&
        isKnownNonNegative(Y, DL, 0, &AC, &I, &DT))
```
But I think handling constants is enough:
```
if ((Pred == ICmpInst::ICMP_SGE || Pred == ICmpInst::ICMP_SLT) &&
        match(Op0, m_OneUse(m_SRem(m_Value(X), m_APInt(*C)))) &&
        match(Op1, m_SpecificInt(*C - 1)) &&
        !C->isNegative())
```


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


More information about the llvm-commits mailing list