diff options
| -rw-r--r-- | llvm/lib/Transforms/Scalar/InstructionCombining.cpp | 55 | ||||
| -rw-r--r-- | llvm/test/Transforms/InstCombine/zext.ll | 23 | 
2 files changed, 52 insertions, 26 deletions
diff --git a/llvm/lib/Transforms/Scalar/InstructionCombining.cpp b/llvm/lib/Transforms/Scalar/InstructionCombining.cpp index 8bdeb7f514c..bca6abc6051 100644 --- a/llvm/lib/Transforms/Scalar/InstructionCombining.cpp +++ b/llvm/lib/Transforms/Scalar/InstructionCombining.cpp @@ -8271,32 +8271,35 @@ Instruction *InstCombiner::visitZExt(ZExtInst &CI) {    Value *Src = CI.getOperand(0); -  // If this is a cast of a cast -  if (CastInst *CSrc = dyn_cast<CastInst>(Src)) {   // A->B->C cast -    // If this is a TRUNC followed by a ZEXT then we are dealing with integral -    // types and if the sizes are just right we can convert this into a logical -    // 'and' which will be much cheaper than the pair of casts. -    if (isa<TruncInst>(CSrc)) { -      // Get the sizes of the types involved -      Value *A = CSrc->getOperand(0); -      uint32_t SrcSize = A->getType()->getPrimitiveSizeInBits(); -      uint32_t MidSize = CSrc->getType()->getPrimitiveSizeInBits(); -      uint32_t DstSize = CI.getType()->getPrimitiveSizeInBits(); -      // If we're actually extending zero bits and the trunc is a no-op -      if (MidSize < DstSize && SrcSize == DstSize) { -        // Replace both of the casts with an And of the type mask. -        APInt AndValue(APInt::getLowBitsSet(SrcSize, MidSize)); -        Constant *AndConst = ConstantInt::get(AndValue); -        Instruction *And =  -          BinaryOperator::CreateAnd(CSrc->getOperand(0), AndConst); -        // Unfortunately, if the type changed, we need to cast it back. -        if (And->getType() != CI.getType()) { -          And->setName(CSrc->getName()+".mask"); -          InsertNewInstBefore(And, CI); -          And = CastInst::CreateIntegerCast(And, CI.getType(), false/*ZExt*/); -        } -        return And; -      } +  // If this is a TRUNC followed by a ZEXT then we are dealing with integral +  // types and if the sizes are just right we can convert this into a logical +  // 'and' which will be much cheaper than the pair of casts. +  if (TruncInst *CSrc = dyn_cast<TruncInst>(Src)) {   // A->B->C cast +    // Get the sizes of the types involved.  We know that the intermediate type +    // will be smaller than A or C, but don't know the relation between A and C. +    Value *A = CSrc->getOperand(0); +    unsigned SrcSize = A->getType()->getPrimitiveSizeInBits(); +    unsigned MidSize = CSrc->getType()->getPrimitiveSizeInBits(); +    unsigned DstSize = CI.getType()->getPrimitiveSizeInBits(); +    // If we're actually extending zero bits, then if +    // SrcSize <  DstSize: zext(a & mask) +    // SrcSize == DstSize: a & mask +    // SrcSize  > DstSize: trunc(a) & mask +    if (SrcSize < DstSize) { +      APInt AndValue(APInt::getLowBitsSet(SrcSize, MidSize)); +      Constant *AndConst = ConstantInt::get(AndValue); +      Instruction *And = +        BinaryOperator::CreateAnd(A, AndConst, CSrc->getName()+".mask"); +      InsertNewInstBefore(And, CI); +      return new ZExtInst(And, CI.getType()); +    } else if (SrcSize == DstSize) { +      APInt AndValue(APInt::getLowBitsSet(SrcSize, MidSize)); +      return BinaryOperator::CreateAnd(A, ConstantInt::get(AndValue)); +    } else if (SrcSize > DstSize) { +      Instruction *Trunc = new TruncInst(A, CI.getType(), "tmp"); +      InsertNewInstBefore(Trunc, CI); +      APInt AndValue(APInt::getLowBitsSet(DstSize, MidSize)); +      return BinaryOperator::CreateAnd(Trunc, ConstantInt::get(AndValue));      }    } diff --git a/llvm/test/Transforms/InstCombine/zext.ll b/llvm/test/Transforms/InstCombine/zext.ll index ceb8deb6775..c0fa3771cc1 100644 --- a/llvm/test/Transforms/InstCombine/zext.ll +++ b/llvm/test/Transforms/InstCombine/zext.ll @@ -8,3 +8,26 @@ define i64 @test_sext_zext(i16 %A) {          ret i64 %c2  } +; PR3599 +define i32 @test2(i64 %tmp) nounwind readnone { +entry: +	%tmp5 = trunc i64 %tmp to i8		; <i8> [#uses=1] +	%tmp7 = lshr i64 %tmp, 8		; <i64> [#uses=1] +	%tmp8 = trunc i64 %tmp7 to i8		; <i8> [#uses=1] +	%tmp10 = lshr i64 %tmp, 16		; <i64> [#uses=1] +	%tmp11 = trunc i64 %tmp10 to i8		; <i8> [#uses=1] +	%tmp13 = lshr i64 %tmp, 24		; <i64> [#uses=1] +	%tmp14 = trunc i64 %tmp13 to i8		; <i8> [#uses=1] +	%tmp1 = zext i8 %tmp5 to i32		; <i32> [#uses=1] +	%tmp2 = zext i8 %tmp8 to i32		; <i32> [#uses=1] +	%tmp3 = shl i32 %tmp2, 8		; <i32> [#uses=1] +	%tmp4 = zext i8 %tmp11 to i32		; <i32> [#uses=1] +	%tmp6 = shl i32 %tmp4, 16		; <i32> [#uses=1] +	%tmp9 = zext i8 %tmp14 to i32		; <i32> [#uses=1] +	%tmp12 = shl i32 %tmp9, 24		; <i32> [#uses=1] +	%tmp15 = or i32 %tmp12, %tmp1		; <i32> [#uses=1] +	%tmp16 = or i32 %tmp15, %tmp6		; <i32> [#uses=1] +	%tmp17 = or i32 %tmp16, %tmp3		; <i32> [#uses=1] +	ret i32 %tmp17 +} +  | 

