Skip to content

Commit 6844e21

Browse files
committedMay 9, 2017
[InstCombineCasts] Fix checks in sext->lshr->trunc pattern.
The comment says to avoid the case where zero bits are shifted into the truncated value, but the code checks that the shift is smaller than the truncated value instead of the number of bits added by the sign extension. Fixing this allows a shift by more than the value size to be introduced, which is undefined behavior, so the shift is capped at the value size minus one, which has the expected behavior of filling the value with the sign bit. Patch by Jacob Young! Differential Revision: https://reviews.llvm.org/D32285 llvm-svn: 302548
1 parent 125c030 commit 6844e21

File tree

2 files changed

+20
-12
lines changed

2 files changed

+20
-12
lines changed
 

‎llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,9 @@ Instruction *InstCombiner::visitTrunc(TruncInst &CI) {
559559
return new ICmpInst(ICmpInst::ICMP_NE, Src, Zero);
560560
}
561561

562+
// FIXME: Maybe combine the next two transforms to handle the no cast case
563+
// more efficiently. Support vector types. Cleanup code by using m_OneUse.
564+
562565
// Transform trunc(lshr (zext A), Cst) to eliminate one type conversion.
563566
Value *A = nullptr; ConstantInt *Cst = nullptr;
564567
if (Src->hasOneUse() &&
@@ -588,15 +591,20 @@ Instruction *InstCombiner::visitTrunc(TruncInst &CI) {
588591
// the sign bit of the original value; performing ashr instead of lshr
589592
// generates bits of the same value as the sign bit.
590593
if (Src->hasOneUse() &&
591-
match(Src, m_LShr(m_SExt(m_Value(A)), m_ConstantInt(Cst))) &&
592-
cast<Instruction>(Src)->getOperand(0)->hasOneUse()) {
594+
match(Src, m_LShr(m_SExt(m_Value(A)), m_ConstantInt(Cst)))) {
595+
Value *SExt = cast<Instruction>(Src)->getOperand(0);
596+
const unsigned SExtSize = SExt->getType()->getPrimitiveSizeInBits();
593597
const unsigned ASize = A->getType()->getPrimitiveSizeInBits();
598+
unsigned ShiftAmt = Cst->getZExtValue();
594599
// This optimization can be only performed when zero bits generated by
595600
// the original lshr aren't pulled into the value after truncation, so we
596-
// can only shift by values smaller than the size of destination type (in
597-
// bits).
598-
if (Cst->getValue().ult(ASize)) {
599-
Value *Shift = Builder->CreateAShr(A, Cst->getZExtValue());
601+
// can only shift by values no larger than the number of extension bits.
602+
// FIXME: Instead of bailing when the shift is too large, use and to clear
603+
// the extra bits.
604+
if (SExt->hasOneUse() && ShiftAmt <= SExtSize - ASize) {
605+
// If shifting by the size of the original value in bits or more, it is
606+
// being filled with the sign bit, so shift by ASize-1 to avoid ub.
607+
Value *Shift = Builder->CreateAShr(A, std::min(ShiftAmt, ASize-1));
600608
Shift->takeName(Src);
601609
return CastInst::CreateIntegerCast(Shift, CI.getType(), true);
602610
}

‎llvm/test/Transforms/InstCombine/cast.ll

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1436,8 +1436,10 @@ define <2 x i32> @test90() {
14361436
; Do not optimize to ashr i64 (shift by 48 > 96 - 64)
14371437
define i64 @test91(i64 %A) {
14381438
; CHECK-LABEL: @test91(
1439-
; CHECK-NEXT: [[C:%.*]] = ashr i64 %A, 48
1440-
; CHECK-NEXT: ret i64 [[C]]
1439+
; CHECK-NEXT: [[B:%.*]] = sext i64 %A to i96
1440+
; CHECK-NEXT: [[C:%.*]] = lshr i96 [[B]], 48
1441+
; CHECK-NEXT: [[D:%.*]] = trunc i96 [[C]] to i64
1442+
; CHECK-NEXT: ret i64 [[D]]
14411443
;
14421444
%B = sext i64 %A to i96
14431445
%C = lshr i96 %B, 48
@@ -1460,10 +1462,8 @@ define i64 @test92(i64 %A) {
14601462
; When optimizing to ashr i32, don't shift by more than 31.
14611463
define i32 @test93(i32 %A) {
14621464
; CHECK-LABEL: @test93(
1463-
; CHECK-NEXT: [[B:%.*]] = sext i32 %A to i96
1464-
; CHECK-NEXT: [[C:%.*]] = lshr i96 [[B]], 64
1465-
; CHECK-NEXT: [[D:%.*]] = trunc i96 [[C]] to i32
1466-
; CHECK-NEXT: ret i32 [[D]]
1465+
; CHECK-NEXT: [[C:%.*]] = ashr i32 %A, 31
1466+
; CHECK-NEXT: ret i32 [[C]]
14671467
;
14681468
%B = sext i32 %A to i96
14691469
%C = lshr i96 %B, 64

0 commit comments

Comments
 (0)
Please sign in to comment.