Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1610,8 +1610,12 @@ Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); CastInst *Cast0 = dyn_cast(Op0); - if (!Cast0) - return nullptr; + if (!Cast0) { + std::swap(Op0, Op1); + Cast0 = dyn_cast(Op0); + if (!Cast0) + return nullptr; + } // This must be a cast from an integer or integer vector source type to allow // transformation of the logic operation to the source type. @@ -1623,6 +1627,19 @@ if (Instruction *Ret = foldLogicCastConstant(I, Cast0, Builder)) return Ret; + // Reassociate chains of Ops {and,or,xor} where one side is an extend. + // extend(X) | (extend(Y) | Z) --> (extend(X) | extend(Y)) | Z + // (extend(X) | extend(Y)) may then be further optimized to narrow the + // operation to smaller types. + Value *Y, *Z; + if (match(Op1, m_OneUse(m_c_BinOp( + m_CombineAnd(m_ZExtOrSExt(m_Value()), m_Value(Y)), + m_Value(Z)))) && + cast(Op1)->getOpcode() == LogicOpc) { + Value *NewOp = Builder.CreateBinOp(LogicOpc, Op0, Y); + return BinaryOperator::Create(LogicOpc, NewOp, Z); + } + CastInst *Cast1 = dyn_cast(Op1); if (!Cast1) return nullptr; Index: llvm/test/Transforms/InstCombine/and-xor-or.ll =================================================================== --- llvm/test/Transforms/InstCombine/and-xor-or.ll +++ llvm/test/Transforms/InstCombine/and-xor-or.ll @@ -389,10 +389,9 @@ define i64 @sext_or_chain(i64 %a, i16 %b, i16 %c) { ; CHECK-LABEL: @sext_or_chain( -; CHECK-NEXT: [[CONV:%.*]] = sext i16 [[B:%.*]] to i64 -; CHECK-NEXT: [[CONV2:%.*]] = sext i16 [[C:%.*]] to i64 -; CHECK-NEXT: [[OR:%.*]] = or i64 [[CONV]], [[A:%.*]] -; CHECK-NEXT: [[OR2:%.*]] = or i64 [[OR]], [[CONV2]] +; CHECK-NEXT: [[TMP1:%.*]] = or i16 [[C:%.*]], [[B:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = sext i16 [[TMP1]] to i64 +; CHECK-NEXT: [[OR2:%.*]] = or i64 [[TMP2]], [[A:%.*]] ; CHECK-NEXT: ret i64 [[OR2]] ; %conv = sext i16 %b to i64 @@ -404,10 +403,9 @@ define i64 @zext_or_chain(i64 %a, i16 %b, i16 %c) { ; CHECK-LABEL: @zext_or_chain( -; CHECK-NEXT: [[CONV:%.*]] = zext i16 [[B:%.*]] to i64 -; CHECK-NEXT: [[CONV2:%.*]] = zext i16 [[C:%.*]] to i64 -; CHECK-NEXT: [[OR:%.*]] = or i64 [[CONV]], [[A:%.*]] -; CHECK-NEXT: [[OR2:%.*]] = or i64 [[OR]], [[CONV2]] +; CHECK-NEXT: [[TMP1:%.*]] = or i16 [[C:%.*]], [[B:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = zext i16 [[TMP1]] to i64 +; CHECK-NEXT: [[OR2:%.*]] = or i64 [[TMP2]], [[A:%.*]] ; CHECK-NEXT: ret i64 [[OR2]] ; %conv = zext i16 %b to i64 @@ -419,10 +417,9 @@ define i64 @sext_and_chain(i64 %a, i16 %b, i16 %c) { ; CHECK-LABEL: @sext_and_chain( -; CHECK-NEXT: [[CONV:%.*]] = sext i16 [[B:%.*]] to i64 -; CHECK-NEXT: [[CONV2:%.*]] = sext i16 [[C:%.*]] to i64 -; CHECK-NEXT: [[AND:%.*]] = and i64 [[CONV]], [[A:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i64 [[AND]], [[CONV2]] +; CHECK-NEXT: [[TMP1:%.*]] = and i16 [[C:%.*]], [[B:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = sext i16 [[TMP1]] to i64 +; CHECK-NEXT: [[AND2:%.*]] = and i64 [[TMP2]], [[A:%.*]] ; CHECK-NEXT: ret i64 [[AND2]] ; %conv = sext i16 %b to i64 @@ -434,10 +431,9 @@ define i64 @zext_and_chain(i64 %a, i16 %b, i16 %c) { ; CHECK-LABEL: @zext_and_chain( -; CHECK-NEXT: [[CONV:%.*]] = zext i16 [[B:%.*]] to i64 -; CHECK-NEXT: [[CONV2:%.*]] = zext i16 [[C:%.*]] to i64 -; CHECK-NEXT: [[AND:%.*]] = and i64 [[CONV]], [[A:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i64 [[AND]], [[CONV2]] +; CHECK-NEXT: [[TMP1:%.*]] = and i16 [[C:%.*]], [[B:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = zext i16 [[TMP1]] to i64 +; CHECK-NEXT: [[AND2:%.*]] = and i64 [[TMP2]], [[A:%.*]] ; CHECK-NEXT: ret i64 [[AND2]] ; %conv = zext i16 %b to i64 @@ -449,10 +445,9 @@ define i64 @sext_xor_chain(i64 %a, i16 %b, i16 %c) { ; CHECK-LABEL: @sext_xor_chain( -; CHECK-NEXT: [[CONV:%.*]] = sext i16 [[B:%.*]] to i64 -; CHECK-NEXT: [[CONV2:%.*]] = sext i16 [[C:%.*]] to i64 -; CHECK-NEXT: [[XOR:%.*]] = xor i64 [[CONV]], [[A:%.*]] -; CHECK-NEXT: [[XOR2:%.*]] = xor i64 [[XOR]], [[CONV2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i16 [[C:%.*]], [[B:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = sext i16 [[TMP1]] to i64 +; CHECK-NEXT: [[XOR2:%.*]] = xor i64 [[TMP2]], [[A:%.*]] ; CHECK-NEXT: ret i64 [[XOR2]] ; %conv = sext i16 %b to i64 @@ -464,10 +459,9 @@ define i64 @zext_xor_chain(i64 %a, i16 %b, i16 %c) { ; CHECK-LABEL: @zext_xor_chain( -; CHECK-NEXT: [[CONV:%.*]] = zext i16 [[B:%.*]] to i64 -; CHECK-NEXT: [[CONV2:%.*]] = zext i16 [[C:%.*]] to i64 -; CHECK-NEXT: [[XOR:%.*]] = xor i64 [[CONV]], [[A:%.*]] -; CHECK-NEXT: [[XOR2:%.*]] = xor i64 [[XOR]], [[CONV2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i16 [[C:%.*]], [[B:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = zext i16 [[TMP1]] to i64 +; CHECK-NEXT: [[XOR2:%.*]] = xor i64 [[TMP2]], [[A:%.*]] ; CHECK-NEXT: ret i64 [[XOR2]] ; %conv = zext i16 %b to i64