Skip to content

Commit

Permalink
[InstSimplify] Fold u/sdiv exact (mul nsw/nuw X, C), C --> X when C…
Browse files Browse the repository at this point in the history
… is not a power of 2 (llvm#76445)

Alive2: https://alive2.llvm.org/ce/z/3D9R7d
  • Loading branch information
dtcxzyw authored Dec 28, 2023
1 parent a700298 commit 8a4266a
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 7 deletions.
26 changes: 19 additions & 7 deletions llvm/lib/Analysis/InstructionSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1189,14 +1189,26 @@ static Value *simplifyDiv(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
if (Value *V = simplifyDivRem(Opcode, Op0, Op1, Q, MaxRecurse))
return V;

// If this is an exact divide by a constant, then the dividend (Op0) must have
// at least as many trailing zeros as the divisor to divide evenly. If it has
// less trailing zeros, then the result must be poison.
const APInt *DivC;
if (IsExact && match(Op1, m_APInt(DivC)) && DivC->countr_zero()) {
KnownBits KnownOp0 = computeKnownBits(Op0, /* Depth */ 0, Q);
if (KnownOp0.countMaxTrailingZeros() < DivC->countr_zero())
return PoisonValue::get(Op0->getType());
if (IsExact && match(Op1, m_APInt(DivC))) {
// If this is an exact divide by a constant, then the dividend (Op0) must
// have at least as many trailing zeros as the divisor to divide evenly. If
// it has less trailing zeros, then the result must be poison.
if (DivC->countr_zero()) {
KnownBits KnownOp0 = computeKnownBits(Op0, /* Depth */ 0, Q);
if (KnownOp0.countMaxTrailingZeros() < DivC->countr_zero())
return PoisonValue::get(Op0->getType());
}

// udiv exact (mul nsw X, C), C --> X
// sdiv exact (mul nuw X, C), C --> X
// where C is not a power of 2.
Value *X;
if (!DivC->isPowerOf2() &&
(Opcode == Instruction::UDiv
? match(Op0, m_NSWMul(m_Value(X), m_Specific(Op1)))
: match(Op0, m_NUWMul(m_Value(X), m_Specific(Op1)))))
return X;
}

return nullptr;
Expand Down
97 changes: 97 additions & 0 deletions llvm/test/Transforms/InstSimplify/div.ll
Original file line number Diff line number Diff line change
Expand Up @@ -567,3 +567,100 @@ define <2 x i8> @sdiv_vec_multi_one_bit_divisor(<2 x i8> %x, <2 x i8> %y) {
%res = sdiv <2 x i8> %y, %and
ret <2 x i8> %res
}

define i8 @udiv_exact_mul_nsw(i8 %x) {
; CHECK-LABEL: @udiv_exact_mul_nsw(
; CHECK-NEXT: ret i8 [[X:%.*]]
;
%a = mul nsw i8 %x, 24
%b = udiv exact i8 %a, 24
ret i8 %b
}

define i8 @sdiv_exact_mul_nuw(i8 %x) {
; CHECK-LABEL: @sdiv_exact_mul_nuw(
; CHECK-NEXT: ret i8 [[X:%.*]]
;
%a = mul nuw i8 %x, 24
%b = sdiv exact i8 %a, 24
ret i8 %b
}

; Negative tests

define i8 @udiv_exact_mul_nsw_mismatch(i8 %x) {
; CHECK-LABEL: @udiv_exact_mul_nsw_mismatch(
; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[X:%.*]], 24
; CHECK-NEXT: [[B:%.*]] = udiv exact i8 [[A]], 12
; CHECK-NEXT: ret i8 [[B]]
;
%a = mul nsw i8 %x, 24
%b = udiv exact i8 %a, 12
ret i8 %b
}

define i8 @udiv_exact_mul_nsw_power_of_2(i8 %x) {
; CHECK-LABEL: @udiv_exact_mul_nsw_power_of_2(
; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[X:%.*]], 8
; CHECK-NEXT: [[B:%.*]] = udiv exact i8 [[A]], 8
; CHECK-NEXT: ret i8 [[B]]
;
%a = mul nsw i8 %x, 8
%b = udiv exact i8 %a, 8
ret i8 %b
}

define i8 @sdiv_exact_mul_nuw_power_of_2(i8 %x) {
; CHECK-LABEL: @sdiv_exact_mul_nuw_power_of_2(
; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[X:%.*]], 8
; CHECK-NEXT: [[B:%.*]] = sdiv exact i8 [[A]], 8
; CHECK-NEXT: ret i8 [[B]]
;
%a = mul nuw i8 %x, 8
%b = sdiv exact i8 %a, 8
ret i8 %b
}

define i8 @udiv_exact_mul(i8 %x) {
; CHECK-LABEL: @udiv_exact_mul(
; CHECK-NEXT: [[A:%.*]] = mul i8 [[X:%.*]], 24
; CHECK-NEXT: [[B:%.*]] = udiv exact i8 [[A]], 24
; CHECK-NEXT: ret i8 [[B]]
;
%a = mul i8 %x, 24
%b = udiv exact i8 %a, 24
ret i8 %b
}

define i8 @sdiv_exact_mul(i8 %x) {
; CHECK-LABEL: @sdiv_exact_mul(
; CHECK-NEXT: [[A:%.*]] = mul i8 [[X:%.*]], 24
; CHECK-NEXT: [[B:%.*]] = sdiv exact i8 [[A]], 24
; CHECK-NEXT: ret i8 [[B]]
;
%a = mul i8 %x, 24
%b = sdiv exact i8 %a, 24
ret i8 %b
}

define i8 @udiv_mul_nsw(i8 %x) {
; CHECK-LABEL: @udiv_mul_nsw(
; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[X:%.*]], 24
; CHECK-NEXT: [[B:%.*]] = udiv i8 [[A]], 24
; CHECK-NEXT: ret i8 [[B]]
;
%a = mul nsw i8 %x, 24
%b = udiv i8 %a, 24
ret i8 %b
}

define i8 @sdiv_mul_nuw(i8 %x) {
; CHECK-LABEL: @sdiv_mul_nuw(
; CHECK-NEXT: [[A:%.*]] = mul nuw i8 [[X:%.*]], 24
; CHECK-NEXT: [[B:%.*]] = sdiv i8 [[A]], 24
; CHECK-NEXT: ret i8 [[B]]
;
%a = mul nuw i8 %x, 24
%b = sdiv i8 %a, 24
ret i8 %b
}

0 comments on commit 8a4266a

Please sign in to comment.