Skip to content

Commit 5d4a0d5

Browse files
committed
[InstCombine] Teach takeLog2 about right shifts, truncation and bitwise-and
We left some easy opportunities for further simplifications. log2(trunc(x)) is simply trunc(log2(x)). This is safe if we know that trunc is NUW because it means that the truncation didn't drop any bits. It is also safe if the caller is OK with zero as a possible answer. log2(x >>u y) is simply `log2(x) - y`. log2(x & y) is a funny one. It comes up when doing something like: ``` unsigned int f(unsigned int x, unsigned int y) { unsigned char a = 1u << x; return y / a; } ``` LLVM would canonicalize this to: ``` %shl = shl nuw i32 1, %x %conv1 = and i32 %shl, 255 %div = udiv i32 %y, %conv1 ``` In cases like these, we can ignore the mask entirely. This is equivalent to `y >> x`.
1 parent d3f70db commit 5d4a0d5

File tree

3 files changed

+74
-7
lines changed

3 files changed

+74
-7
lines changed

llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1427,6 +1427,18 @@ static Value *takeLog2(IRBuilderBase &Builder, Value *Op, unsigned Depth,
14271427
if (Value *LogX = takeLog2(Builder, X, Depth, AssumeNonZero, DoFold))
14281428
return IfFold([&]() { return Builder.CreateZExt(LogX, Op->getType()); });
14291429

1430+
// log2(trunc x) -> trunc log2(X)
1431+
// FIXME: Require one use?
1432+
if (match(Op, m_Trunc(m_Value(X)))) {
1433+
auto *TI = cast<TruncInst>(Op);
1434+
if (AssumeNonZero || TI->hasNoUnsignedWrap())
1435+
if (Value *LogX = takeLog2(Builder, X, Depth, AssumeNonZero, DoFold))
1436+
return IfFold([&]() {
1437+
return Builder.CreateTrunc(LogX, Op->getType(), "",
1438+
/*IsNUW=*/TI->hasNoUnsignedWrap());
1439+
});
1440+
}
1441+
14301442
// log2(X << Y) -> log2(X) + Y
14311443
// FIXME: Require one use unless X is 1?
14321444
if (match(Op, m_Shl(m_Value(X), m_Value(Y)))) {
@@ -1437,6 +1449,24 @@ static Value *takeLog2(IRBuilderBase &Builder, Value *Op, unsigned Depth,
14371449
return IfFold([&]() { return Builder.CreateAdd(LogX, Y); });
14381450
}
14391451

1452+
// log2(X >>u Y) -> log2(X) - Y
1453+
// FIXME: Require one use?
1454+
if (match(Op, m_LShr(m_Value(X), m_Value(Y)))) {
1455+
auto *PEO = cast<PossiblyExactOperator>(Op);
1456+
if (AssumeNonZero || PEO->isExact())
1457+
if (Value *LogX = takeLog2(Builder, X, Depth, AssumeNonZero, DoFold))
1458+
return IfFold([&]() { return Builder.CreateSub(LogX, Y); });
1459+
}
1460+
1461+
// log2(X & Y) -> either log2(X) or log2(Y)
1462+
// This requires `AssumeNonZero` as `X & Y` may be zero when X != Y.
1463+
if (AssumeNonZero && match(Op, m_And(m_Value(X), m_Value(Y)))) {
1464+
if (Value *LogX = takeLog2(Builder, X, Depth, AssumeNonZero, DoFold))
1465+
return IfFold([&]() { return LogX; });
1466+
if (Value *LogY = takeLog2(Builder, Y, Depth, AssumeNonZero, DoFold))
1467+
return IfFold([&]() { return LogY; });
1468+
}
1469+
14401470
// log2(Cond ? X : Y) -> Cond ? log2(X) : log2(Y)
14411471
// FIXME: Require one use?
14421472
if (SelectInst *SI = dyn_cast<SelectInst>(Op))

llvm/test/Transforms/InstCombine/div.ll

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -429,9 +429,8 @@ define <2 x i32> @test31(<2 x i32> %x) {
429429

430430
define i32 @test32(i32 %a, i32 %b) {
431431
; CHECK-LABEL: @test32(
432-
; CHECK-NEXT: [[SHL:%.*]] = shl i32 2, [[B:%.*]]
433-
; CHECK-NEXT: [[DIV:%.*]] = lshr i32 [[SHL]], 2
434-
; CHECK-NEXT: [[DIV2:%.*]] = udiv i32 [[A:%.*]], [[DIV]]
432+
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[B:%.*]], -1
433+
; CHECK-NEXT: [[DIV2:%.*]] = lshr i32 [[A:%.*]], [[TMP1]]
435434
; CHECK-NEXT: ret i32 [[DIV2]]
436435
;
437436
%shl = shl i32 2, %b
@@ -1832,3 +1831,41 @@ define i32 @fold_disjoint_or_over_udiv(i32 %x) {
18321831
%r = udiv i32 %or, 9
18331832
ret i32 %r
18341833
}
1834+
1835+
define i8 @udiv_trunc_shl(i32 %x) {
1836+
; CHECK-LABEL: @udiv_trunc_shl(
1837+
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[X:%.*]] to i8
1838+
; CHECK-NEXT: [[UDIV1:%.*]] = lshr i8 8, [[TMP1]]
1839+
; CHECK-NEXT: ret i8 [[UDIV1]]
1840+
;
1841+
%lshr = shl i32 1, %x
1842+
%trunc = trunc i32 %lshr to i8
1843+
%div = udiv i8 8, %trunc
1844+
ret i8 %div
1845+
}
1846+
1847+
define i32 @zext_udiv_trunc_lshr(i32 %x) {
1848+
; CHECK-LABEL: @zext_udiv_trunc_lshr(
1849+
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[X:%.*]] to i8
1850+
; CHECK-NEXT: [[TMP2:%.*]] = sub i8 5, [[TMP1]]
1851+
; CHECK-NEXT: [[UDIV1:%.*]] = lshr i8 8, [[TMP2]]
1852+
; CHECK-NEXT: [[ZEXT:%.*]] = zext nneg i8 [[UDIV1]] to i32
1853+
; CHECK-NEXT: ret i32 [[ZEXT]]
1854+
;
1855+
%lshr = lshr i32 32, %x
1856+
%trunc = trunc i32 %lshr to i8
1857+
%div = udiv i8 8, %trunc
1858+
%zext = zext i8 %div to i32
1859+
ret i32 %zext
1860+
}
1861+
1862+
define i32 @udiv_and_shl(i32 %a, i32 %b, i32 %c) {
1863+
; CHECK-LABEL: @udiv_and_shl(
1864+
; CHECK-NEXT: [[DIV1:%.*]] = lshr i32 [[C:%.*]], [[A:%.*]]
1865+
; CHECK-NEXT: ret i32 [[DIV1]]
1866+
;
1867+
%shl = shl i32 1, %a
1868+
%and = and i32 %b, %shl
1869+
%div = udiv i32 %c, %and
1870+
ret i32 %div
1871+
}

llvm/test/Transforms/InstCombine/shift.ll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -677,8 +677,8 @@ entry:
677677

678678
define i32 @test42(i32 %a, i32 %b) {
679679
; CHECK-LABEL: @test42(
680-
; CHECK-NEXT: [[DIV:%.*]] = lshr exact i32 4096, [[B:%.*]]
681-
; CHECK-NEXT: [[DIV2:%.*]] = udiv i32 [[A:%.*]], [[DIV]]
680+
; CHECK-NEXT: [[TMP1:%.*]] = sub i32 12, [[B:%.*]]
681+
; CHECK-NEXT: [[DIV2:%.*]] = lshr i32 [[A:%.*]], [[TMP1]]
682682
; CHECK-NEXT: ret i32 [[DIV2]]
683683
;
684684
%div = lshr i32 4096, %b ; must be exact otherwise we'd divide by zero
@@ -688,8 +688,8 @@ define i32 @test42(i32 %a, i32 %b) {
688688

689689
define <2 x i32> @test42vec(<2 x i32> %a, <2 x i32> %b) {
690690
; CHECK-LABEL: @test42vec(
691-
; CHECK-NEXT: [[DIV:%.*]] = lshr exact <2 x i32> <i32 4096, i32 4096>, [[B:%.*]]
692-
; CHECK-NEXT: [[DIV2:%.*]] = udiv <2 x i32> [[A:%.*]], [[DIV]]
691+
; CHECK-NEXT: [[TMP1:%.*]] = sub <2 x i32> <i32 12, i32 12>, [[B:%.*]]
692+
; CHECK-NEXT: [[DIV2:%.*]] = lshr <2 x i32> [[A:%.*]], [[TMP1]]
693693
; CHECK-NEXT: ret <2 x i32> [[DIV2]]
694694
;
695695
%div = lshr <2 x i32> <i32 4096, i32 4096>, %b ; must be exact otherwise we'd divide by zero

0 commit comments

Comments
 (0)