Skip to content

Commit 1a5d892

Browse files
authored
[ConstantRange] Add support for shlWithNoWrap (#100594)
This patch adds initial support for `ConstantRange:: shlWithNoWrap` to fold dtcxzyw/llvm-tools#22. However, this patch cannot fix the original issue. Improvements will be submitted in subsequent patches.
1 parent b5fc083 commit 1a5d892

File tree

4 files changed

+128
-5
lines changed

4 files changed

+128
-5
lines changed

llvm/include/llvm/IR/ConstantRange.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,14 @@ class [[nodiscard]] ConstantRange {
501501
/// TODO: This isn't fully implemented yet.
502502
ConstantRange shl(const ConstantRange &Other) const;
503503

504+
/// Return a new range representing the possible values resulting
505+
/// from a left shift with wrap type \p NoWrapKind of a value in this
506+
/// range and a value in \p Other.
507+
/// If the result range is disjoint, the preferred range is determined by the
508+
/// \p PreferredRangeType.
509+
ConstantRange shlWithNoWrap(const ConstantRange &Other, unsigned NoWrapKind,
510+
PreferredRangeType RangeType = Smallest) const;
511+
504512
/// Return a new range representing the possible values resulting from a
505513
/// logical right shift of a value in this range and a value in \p Other.
506514
ConstantRange lshr(const ConstantRange &Other) const;

llvm/lib/IR/ConstantRange.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,8 @@ ConstantRange ConstantRange::overflowingBinaryOp(Instruction::BinaryOps BinOp,
988988
return subWithNoWrap(Other, NoWrapKind);
989989
case Instruction::Mul:
990990
return multiplyWithNoWrap(Other, NoWrapKind);
991+
case Instruction::Shl:
992+
return shlWithNoWrap(Other, NoWrapKind);
991993
default:
992994
// Don't know about this Overflowing Binary Operation.
993995
// Conservatively fallback to plain binop handling.
@@ -1615,6 +1617,23 @@ ConstantRange::shl(const ConstantRange &Other) const {
16151617
return ConstantRange::getNonEmpty(std::move(Min), std::move(Max) + 1);
16161618
}
16171619

1620+
ConstantRange ConstantRange::shlWithNoWrap(const ConstantRange &Other,
1621+
unsigned NoWrapKind,
1622+
PreferredRangeType RangeType) const {
1623+
if (isEmptySet() || Other.isEmptySet())
1624+
return getEmpty();
1625+
1626+
ConstantRange Result = shl(Other);
1627+
1628+
if (NoWrapKind & OverflowingBinaryOperator::NoSignedWrap)
1629+
Result = Result.intersectWith(sshl_sat(Other), RangeType);
1630+
1631+
if (NoWrapKind & OverflowingBinaryOperator::NoUnsignedWrap)
1632+
Result = Result.intersectWith(ushl_sat(Other), RangeType);
1633+
1634+
return Result;
1635+
}
1636+
16181637
ConstantRange
16191638
ConstantRange::lshr(const ConstantRange &Other) const {
16201639
if (isEmptySet() || Other.isEmptySet())

llvm/test/Transforms/CorrelatedValuePropagation/shl.ll

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ define i8 @test4(i8 %a, i8 %b) {
8686
; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]]
8787
; CHECK: bb:
8888
; CHECK-NEXT: [[SHL:%.*]] = shl nuw nsw i8 [[A:%.*]], [[B]]
89-
; CHECK-NEXT: ret i8 [[SHL]]
89+
; CHECK-NEXT: ret i8 -1
9090
; CHECK: exit:
9191
; CHECK-NEXT: ret i8 0
9292
;
@@ -382,8 +382,7 @@ define i1 @nuw_range1(i8 %b) {
382382
; CHECK-NEXT: entry:
383383
; CHECK-NEXT: [[C:%.*]] = add nuw nsw i8 [[B:%.*]], 1
384384
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i8 [[C]], 2
385-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[SHL]], 0
386-
; CHECK-NEXT: ret i1 [[CMP]]
385+
; CHECK-NEXT: ret i1 false
387386
;
388387
entry:
389388
%c = add nuw nsw i8 %b, 1
@@ -397,8 +396,7 @@ define i1 @nuw_range2(i8 %b) {
397396
; CHECK-NEXT: entry:
398397
; CHECK-NEXT: [[C:%.*]] = add nuw nsw i8 [[B:%.*]], 3
399398
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i8 [[C]], 2
400-
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[SHL]], 2
401-
; CHECK-NEXT: ret i1 [[CMP]]
399+
; CHECK-NEXT: ret i1 false
402400
;
403401
entry:
404402
%c = add nuw nsw i8 %b, 3
@@ -420,3 +418,59 @@ entry:
420418
%cmp = icmp slt i8 %c, %shl
421419
ret i1 %cmp
422420
}
421+
422+
define i64 @shl_nuw_nsw_test1(i32 %x) {
423+
; CHECK-LABEL: @shl_nuw_nsw_test1(
424+
; CHECK-NEXT: [[SHL1:%.*]] = shl nuw nsw i32 1, [[X:%.*]]
425+
; CHECK-NEXT: [[ADD1:%.*]] = add nsw i32 [[SHL1]], -1
426+
; CHECK-NEXT: [[EXT:%.*]] = zext nneg i32 [[ADD1]] to i64
427+
; CHECK-NEXT: [[SHL2:%.*]] = shl nuw nsw i64 [[EXT]], 2
428+
; CHECK-NEXT: [[ADD2:%.*]] = add nuw nsw i64 [[SHL2]], 39
429+
; CHECK-NEXT: [[LSHR:%.*]] = lshr i64 [[ADD2]], 3
430+
; CHECK-NEXT: ret i64 [[LSHR]]
431+
;
432+
%shl1 = shl nuw nsw i32 1, %x
433+
%add1 = add nsw i32 %shl1, -1
434+
%ext = sext i32 %add1 to i64
435+
%shl2 = shl nsw i64 %ext, 2
436+
%add2 = add nsw i64 %shl2, 39
437+
%lshr = lshr i64 %add2, 3
438+
%and = and i64 %lshr, 4294967295
439+
ret i64 %and
440+
}
441+
442+
define i32 @shl_nuw_nsw_test2(i32 range(i32 -2147483248, 1) %x) {
443+
; CHECK-LABEL: @shl_nuw_nsw_test2(
444+
; CHECK-NEXT: [[SHL:%.*]] = shl nsw i32 [[X:%.*]], 1
445+
; CHECK-NEXT: ret i32 200
446+
;
447+
%shl = shl nsw i32 %x, 1
448+
%smax = call i32 @llvm.smax.i32(i32 %shl, i32 200)
449+
ret i32 %smax
450+
}
451+
452+
define i64 @shl_nuw_nsw_test3(i1 %cond, i64 range(i64 1, 0) %x, i64 range(i64 3, 0) %y) {
453+
; CHECK-LABEL: @shl_nuw_nsw_test3(
454+
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i64 1, [[X:%.*]]
455+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], i64 [[Y:%.*]], i64 [[SHL]]
456+
; CHECK-NEXT: ret i64 [[SEL]]
457+
;
458+
%shl = shl nuw i64 1, %x
459+
%sel = select i1 %cond, i64 %y, i64 %shl
460+
%umax = call i64 @llvm.umax.i64(i64 %sel, i64 2)
461+
ret i64 %umax
462+
}
463+
464+
define i1 @shl_nuw_nsw_test4(i32 %x, i32 range(i32 0, 32) %k) {
465+
; CHECK-LABEL: @shl_nuw_nsw_test4(
466+
; CHECK-NEXT: [[CONV:%.*]] = sext i32 [[X:%.*]] to i64
467+
; CHECK-NEXT: [[SH_PROM:%.*]] = zext nneg i32 [[K:%.*]] to i64
468+
; CHECK-NEXT: [[SHL:%.*]] = shl nsw i64 [[CONV]], [[SH_PROM]]
469+
; CHECK-NEXT: ret i1 false
470+
;
471+
%conv = sext i32 %x to i64
472+
%sh_prom = zext nneg i32 %k to i64
473+
%shl = shl nsw i64 %conv, %sh_prom
474+
%cmp = icmp eq i64 %shl, -9223372036854775808
475+
ret i1 %cmp
476+
}

llvm/unittests/IR/ConstantRangeTest.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,6 +1502,48 @@ TEST_F(ConstantRangeTest, Shl) {
15021502
});
15031503
}
15041504

1505+
TEST_F(ConstantRangeTest, ShlWithNoWrap) {
1506+
using OBO = OverflowingBinaryOperator;
1507+
TestBinaryOpExhaustive(
1508+
[](const ConstantRange &CR1, const ConstantRange &CR2) {
1509+
return CR1.shlWithNoWrap(CR2, OBO::NoUnsignedWrap);
1510+
},
1511+
[](const APInt &N1, const APInt &N2) -> std::optional<APInt> {
1512+
bool IsOverflow;
1513+
APInt Res = N1.ushl_ov(N2, IsOverflow);
1514+
if (IsOverflow)
1515+
return std::nullopt;
1516+
return Res;
1517+
},
1518+
PreferSmallest, CheckCorrectnessOnly);
1519+
TestBinaryOpExhaustive(
1520+
[](const ConstantRange &CR1, const ConstantRange &CR2) {
1521+
return CR1.shlWithNoWrap(CR2, OBO::NoSignedWrap);
1522+
},
1523+
[](const APInt &N1, const APInt &N2) -> std::optional<APInt> {
1524+
bool IsOverflow;
1525+
APInt Res = N1.sshl_ov(N2, IsOverflow);
1526+
if (IsOverflow)
1527+
return std::nullopt;
1528+
return Res;
1529+
},
1530+
PreferSmallest, CheckCorrectnessOnly);
1531+
TestBinaryOpExhaustive(
1532+
[](const ConstantRange &CR1, const ConstantRange &CR2) {
1533+
return CR1.shlWithNoWrap(CR2, OBO::NoUnsignedWrap | OBO::NoSignedWrap);
1534+
},
1535+
[](const APInt &N1, const APInt &N2) -> std::optional<APInt> {
1536+
bool IsOverflow1, IsOverflow2;
1537+
APInt Res1 = N1.ushl_ov(N2, IsOverflow1);
1538+
APInt Res2 = N1.sshl_ov(N2, IsOverflow2);
1539+
if (IsOverflow1 || IsOverflow2)
1540+
return std::nullopt;
1541+
assert(Res1 == Res2 && "Left shift results differ?");
1542+
return Res1;
1543+
},
1544+
PreferSmallest, CheckCorrectnessOnly);
1545+
}
1546+
15051547
TEST_F(ConstantRangeTest, Lshr) {
15061548
EXPECT_EQ(Full.lshr(Full), Full);
15071549
EXPECT_EQ(Full.lshr(Empty), Empty);

0 commit comments

Comments
 (0)