Index: lib/Transforms/InstCombine/InstCombineCasts.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCasts.cpp +++ lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -498,6 +498,26 @@ return CastInst::CreateIntegerCast(Shift, CI.getType(), false); } + // Transform trunc(lshr (sext A), Cst) to ashr A, Cst to eliminate type + // conversion. + // It works because bits coming from sign extension have the same value as + // sign bit of the original value; performing ashr instead of lshr + // generates bits of the same value as the sign bit. + if (Src->hasOneUse() && + match(Src, m_LShr(m_SExt(m_Value(A)), m_ConstantInt(Cst))) && + cast(Src)->getOperand(0)->hasOneUse()) { + const unsigned ASize = A->getType()->getPrimitiveSizeInBits(); + // This optimization can be only performed when zero bits generated by + // the original lshr aren't pulled into the value after truncation, so we + // can only shift by values smaller then the size of destination type (in + // bits). + if (Cst->getValue().ult(ASize)) { + Value *Shift = Builder->CreateAShr(A, Cst->getZExtValue()); + Shift->takeName(Src); + return CastInst::CreateIntegerCast(Shift, CI.getType(), true); + } + } + // Transform "trunc (and X, cst)" -> "and (trunc X), cst" so long as the dest // type isn't non-native. if (Src->hasOneUse() && isa(Src->getType()) && Index: test/Transforms/InstCombine/cast.ll =================================================================== --- test/Transforms/InstCombine/cast.ll +++ test/Transforms/InstCombine/cast.ll @@ -1062,6 +1062,43 @@ ; CHECK: [[CST:%.*]] = trunc i32 [[SHR]] to i8 } +define i16 @test86(i16 %v) { + %a = sext i16 %v to i32 + %s = ashr i32 %a, 4 + %t = trunc i32 %s to i16 + ret i16 %t + +; CHECK-LABEL: @test86( +; CHECK: [[ASHR:%.*]] = ashr i16 %v, 4 +; CHECK-NEXT: ret i16 [[ASHR]] +} + +define i16 @test87(i16 %v) { + %c = sext i16 %v to i32 + %m = mul nsw i32 %c, 16 + %a = ashr i32 %m, 16 + %t = trunc i32 %a to i16 + ret i16 %t + +; CHECK-LABEL: @test87( +; CHECK: [[ASHR:%.*]] = ashr i16 %v, 12 +; CHECK-NEXT: ret i16 [[ASHR]] +} + +define i16 @test88(i16 %v) { + %a = sext i16 %v to i32 + %s = ashr i32 %a, 18 + %t = trunc i32 %s to i16 + ret i16 %t + +; Do not optimize to ashr i16 (shift by 18) +; CHECK-LABEL: @test88( +; CHECK: [[SEXT:%.*]] = sext i16 %v to i32 +; CHECK-NEXT: [[ASHR:%.*]] = ashr i32 [[SEXT]], 18 +; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 [[ASHR]] to i16 +; CHECK-NEXT: ret i16 [[TRUNC]] +} + ; Overflow on a float to int or int to float conversion is undefined (PR21130). define i8 @overflow_fptosi() { @@ -1137,3 +1174,14 @@ %trunc = trunc i32 %sub to i1 ret i1 %trunc } + +define i16 @PR24763(i8 %V) { +; CHECK-LABEL: @PR24763( +; CHECK-NEXT: %[[sh:.*]] = ashr i8 +; CHECK-NEXT: %[[ext:.*]] = sext i8 %[[sh]] to i16 +; CHECK-NEXT: ret i16 %[[ext]] + %conv = sext i8 %V to i32 + %l = lshr i32 %conv, 1 + %t = trunc i32 %l to i16 + ret i16 %t +}