Index: lib/Transforms/InstCombine/InstCombineCasts.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCasts.cpp +++ lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -1778,6 +1778,37 @@ return ExtractElementInst::Create(NewBC, ExtElt->getIndexOperand()); } +/// Change the type of a bitwise logic operation if we can eliminate a bitcast. +static Instruction *foldBitCastBitwiseLogic(BitCastInst &BitCast, + InstCombiner::BuilderTy &Builder) { + BinaryOperator *BO; + if (!match(BitCast.getOperand(0), m_OneUse(m_BinOp(BO)))) + return nullptr; + + auto Opcode = BO->getOpcode(); + if (Opcode != Instruction::And && Opcode != Instruction::Or && + Opcode != Instruction::Xor) + return nullptr; + + Type *DestTy = BitCast.getType(); + Value *X; + if (match(BO->getOperand(0), m_OneUse(m_BitCast(m_Value(X)))) && + X->getType() == DestTy && !isa(X)) { + // bitcast(logic(bitcast(X), Y)) --> logic'(X, bitcast(Y)) + Value *CastedOp1 = Builder.CreateBitCast(BO->getOperand(1), DestTy); + return BinaryOperator::Create(Opcode, X, CastedOp1); + } + + if (match(BO->getOperand(1), m_OneUse(m_BitCast(m_Value(X)))) && + X->getType() == DestTy && !isa(X)) { + // bitcast(logic(Y, bitcast(X))) --> logic'(bitcast(Y), X) + Value *CastedOp0 = Builder.CreateBitCast(BO->getOperand(0), DestTy); + return BinaryOperator::Create(Opcode, CastedOp0, X); + } + + return nullptr; +} + /// Check if all users of CI are StoreInsts. static bool hasStoreUsersOnly(CastInst &CI) { for (User *U : CI.users()) { @@ -2030,6 +2061,9 @@ if (Instruction *I = canonicalizeBitCastExtElt(CI, *this, DL)) return I; + if (Instruction *I = foldBitCastBitwiseLogic(CI, *Builder)) + return I; + if (SrcTy->isPointerTy()) return commonPointerCastTransforms(CI); return commonCastTransforms(CI); Index: test/Transforms/InstCombine/bitcast.ll =================================================================== --- test/Transforms/InstCombine/bitcast.ll +++ test/Transforms/InstCombine/bitcast.ll @@ -74,10 +74,8 @@ define <4 x i32> @bitcasts_and_bitcast(<4 x i32> %a, <8 x i16> %b) { ; CHECK-LABEL: @bitcasts_and_bitcast( -; CHECK-NEXT: [[BC1:%.*]] = bitcast <4 x i32> %a to <2 x i64> -; CHECK-NEXT: [[BC2:%.*]] = bitcast <8 x i16> %b to <2 x i64> -; CHECK-NEXT: [[AND:%.*]] = and <2 x i64> [[BC2]], [[BC1]] -; CHECK-NEXT: [[BC3:%.*]] = bitcast <2 x i64> [[AND]] to <4 x i32> +; CHECK-NEXT: [[TMP1:%.*]] = bitcast <8 x i16> %b to <4 x i32> +; CHECK-NEXT: [[BC3:%.*]] = and <4 x i32> [[TMP1]], %a ; CHECK-NEXT: ret <4 x i32> [[BC3]] ; %bc1 = bitcast <4 x i32> %a to <2 x i64> @@ -89,9 +87,8 @@ define i128 @bitcast_or_bitcast(i128 %a, <2 x i64> %b) { ; CHECK-LABEL: @bitcast_or_bitcast( -; CHECK-NEXT: [[BC1:%.*]] = bitcast i128 %a to <2 x i64> -; CHECK-NEXT: [[OR:%.*]] = or <2 x i64> [[BC1]], %b -; CHECK-NEXT: [[BC2:%.*]] = bitcast <2 x i64> [[OR]] to i128 +; CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x i64> %b to i128 +; CHECK-NEXT: [[BC2:%.*]] = or i128 [[TMP1]], %a ; CHECK-NEXT: ret i128 [[BC2]] ; %bc1 = bitcast i128 %a to <2 x i64> @@ -102,9 +99,8 @@ define <4 x i32> @bitcast_xor_bitcast(<4 x i32> %a, i128 %b) { ; CHECK-LABEL: @bitcast_xor_bitcast( -; CHECK-NEXT: [[BC1:%.*]] = bitcast <4 x i32> %a to i128 -; CHECK-NEXT: [[XOR:%.*]] = xor i128 [[BC1]], %b -; CHECK-NEXT: [[BC2:%.*]] = bitcast i128 [[XOR]] to <4 x i32> +; CHECK-NEXT: [[TMP1:%.*]] = bitcast i128 %b to <4 x i32> +; CHECK-NEXT: [[BC2:%.*]] = xor <4 x i32> [[TMP1]], %a ; CHECK-NEXT: ret <4 x i32> [[BC2]] ; %bc1 = bitcast <4 x i32> %a to i128