From aa8b28e50901045476faca1b1047123d4f43d7ce Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Wed, 30 Nov 2016 20:48:54 +0000 Subject: [PATCH] [InstCombine] allow more narrowing transforms for logic ops We had a limited version of this for scalar 'and'; this expands the transform to 'or' and 'xor' and allows vectors types too. llvm-svn: 288273 --- .../Transforms/InstCombine/InstCombineCasts.cpp | 32 ++++++++++++++++------ .../Transforms/InstCombine/InstCombineInternal.h | 1 + llvm/test/Transforms/InstCombine/narrow.ll | 24 ++++++++-------- 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp index 491576e..c934550 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -443,6 +443,26 @@ static Instruction *foldVecTruncToExtElt(TruncInst &Trunc, InstCombiner &IC, return ExtractElementInst::Create(VecInput, IC.Builder->getInt32(Elt)); } +/// Try to narrow the width of bitwise logic instructions with constants. +Instruction *InstCombiner::shrinkBitwiseLogic(TruncInst &Trunc) { + Type *SrcTy = Trunc.getSrcTy(); + Type *DestTy = Trunc.getType(); + if (isa(SrcTy) && !ShouldChangeType(SrcTy, DestTy)) + return nullptr; + + BinaryOperator *LogicOp; + Constant *C; + if (!match(Trunc.getOperand(0), m_OneUse(m_BinOp(LogicOp))) || + !LogicOp->isBitwiseLogicOp() || + !match(LogicOp->getOperand(1), m_Constant(C))) + return nullptr; + + // trunc (logic X, C) --> logic (trunc X, C') + Constant *NarrowC = ConstantExpr::getTrunc(C, DestTy); + Value *NarrowOp0 = Builder->CreateTrunc(LogicOp->getOperand(0), DestTy); + return BinaryOperator::Create(LogicOp->getOpcode(), NarrowOp0, NarrowC); +} + Instruction *InstCombiner::visitTrunc(TruncInst &CI) { if (Instruction *Result = commonCastTransforms(CI)) return Result; @@ -531,17 +551,11 @@ Instruction *InstCombiner::visitTrunc(TruncInst &CI) { } } + if (Instruction *I = shrinkBitwiseLogic(CI)) + return I; + if (Src->hasOneUse() && isa(SrcTy) && ShouldChangeType(SrcTy, DestTy)) { - - // Transform "trunc (and X, cst)" -> "and (trunc X), cst" so long as the - // dest type is native. - if (match(Src, m_And(m_Value(A), m_ConstantInt(Cst)))) { - Value *NewTrunc = Builder->CreateTrunc(A, DestTy, A->getName() + ".tr"); - return BinaryOperator::CreateAnd(NewTrunc, - ConstantExpr::getTrunc(Cst, DestTy)); - } - // Transform "trunc (shl X, cst)" -> "shl (trunc X), cst" so long as the // dest type is native and cst < dest size. if (match(Src, m_Shl(m_Value(A), m_ConstantInt(Cst))) && diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h index 176b7a0..e6b9bca 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -380,6 +380,7 @@ private: Instruction *scalarizePHI(ExtractElementInst &EI, PHINode *PN); Value *EvaluateInDifferentElementOrder(Value *V, ArrayRef Mask); Instruction *foldCastedBitwiseLogic(BinaryOperator &I); + Instruction *shrinkBitwiseLogic(TruncInst &Trunc); Instruction *optimizeBitCastFromPhi(CastInst &CI, PHINode *PN); /// Determine if a pair of casts can be replaced by a single cast. diff --git a/llvm/test/Transforms/InstCombine/narrow.ll b/llvm/test/Transforms/InstCombine/narrow.ll index d511648..0e000e8 100644 --- a/llvm/test/Transforms/InstCombine/narrow.ll +++ b/llvm/test/Transforms/InstCombine/narrow.ll @@ -19,12 +19,12 @@ define i1 @test1(i32 %A, i32 %B) { ret i1 %ELIM3 } -; TODO: The next 6 (3 logic ops * (scalar+vector)) tests show potential cases for narrowing a bitwise logic op. +; The next 6 (3 logic ops * (scalar+vector)) tests show potential cases for narrowing a bitwise logic op. define i32 @shrink_xor(i64 %a) { ; CHECK-LABEL: @shrink_xor( -; CHECK-NEXT: [[XOR:%.*]] = xor i64 %a, 1 -; CHECK-NEXT: [[TRUNC:%.*]] = trunc i64 [[XOR]] to i32 +; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 %a to i32 +; CHECK-NEXT: [[TRUNC:%.*]] = xor i32 [[TMP1]], 1 ; CHECK-NEXT: ret i32 [[TRUNC]] ; %xor = xor i64 %a, 1 @@ -36,8 +36,8 @@ define i32 @shrink_xor(i64 %a) { define <2 x i32> @shrink_xor_vec(<2 x i64> %a) { ; CHECK-LABEL: @shrink_xor_vec( -; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i64> %a, -; CHECK-NEXT: [[TRUNC:%.*]] = trunc <2 x i64> [[XOR]] to <2 x i32> +; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i64> %a to <2 x i32> +; CHECK-NEXT: [[TRUNC:%.*]] = xor <2 x i32> [[TMP1]], ; CHECK-NEXT: ret <2 x i32> [[TRUNC]] ; %xor = xor <2 x i64> %a, @@ -49,8 +49,8 @@ define <2 x i32> @shrink_xor_vec(<2 x i64> %a) { define i3 @shrink_or(i6 %a) { ; CHECK-LABEL: @shrink_or( -; CHECK-NEXT: [[OR:%.*]] = or i6 %a, 1 -; CHECK-NEXT: [[TRUNC:%.*]] = trunc i6 [[OR]] to i3 +; CHECK-NEXT: [[TMP1:%.*]] = trunc i6 %a to i3 +; CHECK-NEXT: [[TRUNC:%.*]] = or i3 [[TMP1]], 1 ; CHECK-NEXT: ret i3 [[TRUNC]] ; %or = or i6 %a, 33 @@ -62,8 +62,8 @@ define i3 @shrink_or(i6 %a) { define <2 x i8> @shrink_or_vec(<2 x i16> %a) { ; CHECK-LABEL: @shrink_or_vec( -; CHECK-NEXT: [[OR:%.*]] = or <2 x i16> %a, -; CHECK-NEXT: [[TRUNC:%.*]] = trunc <2 x i16> [[OR]] to <2 x i8> +; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i16> %a to <2 x i8> +; CHECK-NEXT: [[TRUNC:%.*]] = or <2 x i8> [[TMP1]], ; CHECK-NEXT: ret <2 x i8> [[TRUNC]] ; %or = or <2 x i16> %a, @@ -71,7 +71,7 @@ define <2 x i8> @shrink_or_vec(<2 x i16> %a) { ret <2 x i8> %trunc } -; We discriminate against weird types? +; We discriminate against weird types. define i31 @shrink_and(i64 %a) { ; CHECK-LABEL: @shrink_and( @@ -88,8 +88,8 @@ define i31 @shrink_and(i64 %a) { define <2 x i32> @shrink_and_vec(<2 x i33> %a) { ; CHECK-LABEL: @shrink_and_vec( -; CHECK-NEXT: [[AND:%.*]] = and <2 x i33> %a, -; CHECK-NEXT: [[TRUNC:%.*]] = trunc <2 x i33> [[AND]] to <2 x i32> +; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i33> %a to <2 x i32> +; CHECK-NEXT: [[TRUNC:%.*]] = and <2 x i32> [[TMP1]], ; CHECK-NEXT: ret <2 x i32> [[TRUNC]] ; %and = and <2 x i33> %a, -- 2.7.4