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,20 @@ 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_c_BinOp(m_ZExtOrSExt(m_Value()), m_Value(Z))) && + cast(Op1)->getOpcode() == LogicOpc) { + // Get the other cast. + match(Op1, m_c_BinOp(m_Value(Y), m_Specific(Z))); + Value *NewOp = Builder.CreateBinOp( + LogicOpc, Builder.CreateBinOp(LogicOpc, Op0, Y), Z, I.getName()); + return replaceInstUsesWith(I, NewOp); + } + 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 @@ -384,3 +384,217 @@ ret i8 %r2 } +; Reassociate chains of extend(X) | (extend(Y) | Z) --> (extend(X) | extend(Y)) | Z +; and eliminate extends. + +define i1 @sext_or_chain(i16* %ptr, i16 %a, i16 %b, i16 %c, i16 %d, i16 %e, i16 %f, i16 %g) { +; CHECK-LABEL: @sext_or_chain( +; CHECK-NEXT: [[CONV:%.*]] = sext i16 [[A:%.*]] to i32 +; CHECK-NEXT: [[SHL1:%.*]] = shl nsw i32 [[CONV]], 11 +; CHECK-NEXT: [[CONV2:%.*]] = sext i32 [[SHL1]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = or i16 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = or i16 [[TMP1]], [[D:%.*]] +; CHECK-NEXT: [[TMP3:%.*]] = or i16 [[TMP2]], [[E:%.*]] +; CHECK-NEXT: [[TMP4:%.*]] = or i16 [[TMP3]], [[F:%.*]] +; CHECK-NEXT: [[TMP5:%.*]] = or i16 [[TMP4]], [[G:%.*]] +; CHECK-NEXT: [[TMP6:%.*]] = sext i16 [[TMP5]] to i64 +; CHECK-NEXT: [[OR196:%.*]] = or i64 [[TMP6]], [[CONV2]] +; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i64 [[OR196]], 0 +; CHECK-NEXT: ret i1 [[TOBOOL_NOT]] +; + %conv = sext i16 %a to i32 + %shl1 = shl nsw i32 %conv, 11 + %conv2 = sext i32 %shl1 to i64 + %conv4 = sext i16 %b to i64 + %or = or i64 %conv2, %conv4 + %conv6 = sext i16 %c to i64 + %or7 = or i64 %or, %conv6 + %conv9 = sext i16 %d to i64 + %or10 = or i64 %or7, %conv9 + %conv12 = sext i16 %e to i64 + %or13 = or i64 %or10, %conv12 + %conv15 = sext i16 %f to i64 + %or16 = or i64 %or13, %conv15 + %conv18 = sext i16 %g to i64 + %or19 = or i64 %or16, %conv18 + %tobool.not = icmp eq i64 %or19, 0 + + ret i1 %tobool.not +} + + + +define i1 @zext_or_chain(i16* %ptr, i16 %a, i16 %b, i16 %c, i16 %d, i16 %e, i16 %f, i16 %g) { +; CHECK-LABEL: @zext_or_chain( +; CHECK-NEXT: [[CONV:%.*]] = zext i16 [[A:%.*]] to i32 +; CHECK-NEXT: [[SHL1:%.*]] = shl nuw nsw i32 [[CONV]], 11 +; CHECK-NEXT: [[CONV2:%.*]] = zext i32 [[SHL1]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = or i16 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = or i16 [[TMP1]], [[D:%.*]] +; CHECK-NEXT: [[TMP3:%.*]] = or i16 [[TMP2]], [[E:%.*]] +; CHECK-NEXT: [[TMP4:%.*]] = or i16 [[TMP3]], [[F:%.*]] +; CHECK-NEXT: [[TMP5:%.*]] = or i16 [[TMP4]], [[G:%.*]] +; CHECK-NEXT: [[TMP6:%.*]] = zext i16 [[TMP5]] to i64 +; CHECK-NEXT: [[OR196:%.*]] = or i64 [[TMP6]], [[CONV2]] +; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i64 [[OR196]], 0 +; CHECK-NEXT: ret i1 [[TOBOOL_NOT]] +; + %conv = zext i16 %a to i32 + %shl1 = shl nsw i32 %conv, 11 + %conv2 = zext i32 %shl1 to i64 + %conv4 = zext i16 %b to i64 + %or = or i64 %conv2, %conv4 + %conv6 = zext i16 %c to i64 + %or7 = or i64 %or, %conv6 + %conv9 = zext i16 %d to i64 + %or10 = or i64 %or7, %conv9 + %conv12 = zext i16 %e to i64 + %or13 = or i64 %or10, %conv12 + %conv15 = zext i16 %f to i64 + %or16 = or i64 %or13, %conv15 + %conv18 = zext i16 %g to i64 + %or19 = or i64 %or16, %conv18 + %tobool.not = icmp eq i64 %or19, 0 + + ret i1 %tobool.not +} + +define i1 @sext_and_chain(i16* %ptr, i16 %a, i16 %b, i16 %c, i16 %d, i16 %e, i16 %f, i16 %g) { +; CHECK-LABEL: @sext_and_chain( +; CHECK-NEXT: [[CONV:%.*]] = sext i16 [[A:%.*]] to i32 +; CHECK-NEXT: [[SHL1:%.*]] = shl nsw i32 [[CONV]], 11 +; CHECK-NEXT: [[CONV2:%.*]] = sext i32 [[SHL1]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = and i16 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i16 [[TMP1]], [[D:%.*]] +; CHECK-NEXT: [[TMP3:%.*]] = and i16 [[TMP2]], [[E:%.*]] +; CHECK-NEXT: [[TMP4:%.*]] = and i16 [[TMP3]], [[F:%.*]] +; CHECK-NEXT: [[TMP5:%.*]] = and i16 [[TMP4]], [[G:%.*]] +; CHECK-NEXT: [[TMP6:%.*]] = sext i16 [[TMP5]] to i64 +; CHECK-NEXT: [[AND196:%.*]] = and i64 [[TMP6]], [[CONV2]] +; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i64 [[AND196]], 0 +; CHECK-NEXT: ret i1 [[TOBOOL_NOT]] +; + %conv = sext i16 %a to i32 + %shl1 = shl nsw i32 %conv, 11 + %conv2 = sext i32 %shl1 to i64 + %conv4 = sext i16 %b to i64 + %and = and i64 %conv2, %conv4 + %conv6 = sext i16 %c to i64 + %and7 = and i64 %and, %conv6 + %conv9 = sext i16 %d to i64 + %and10 = and i64 %and7, %conv9 + %conv12 = sext i16 %e to i64 + %and13 = and i64 %and10, %conv12 + %conv15 = sext i16 %f to i64 + %and16 = and i64 %and13, %conv15 + %conv18 = sext i16 %g to i64 + %and19 = and i64 %and16, %conv18 + %tobool.not = icmp eq i64 %and19, 0 + + ret i1 %tobool.not +} + + + +define i1 @zext_and_chain(i16* %ptr, i16 %a, i16 %b, i16 %c, i16 %d, i16 %e, i16 %f, i16 %g) { +; CHECK-LABEL: @zext_and_chain( +; CHECK-NEXT: [[CONV:%.*]] = zext i16 [[A:%.*]] to i32 +; CHECK-NEXT: [[SHL1:%.*]] = shl nuw nsw i32 [[CONV]], 11 +; CHECK-NEXT: [[CONV2:%.*]] = zext i32 [[SHL1]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = and i16 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i16 [[TMP1]], [[D:%.*]] +; CHECK-NEXT: [[TMP3:%.*]] = and i16 [[TMP2]], [[E:%.*]] +; CHECK-NEXT: [[TMP4:%.*]] = and i16 [[TMP3]], [[F:%.*]] +; CHECK-NEXT: [[TMP5:%.*]] = and i16 [[TMP4]], [[G:%.*]] +; CHECK-NEXT: [[TMP6:%.*]] = zext i16 [[TMP5]] to i64 +; CHECK-NEXT: [[AND196:%.*]] = and i64 [[TMP6]], [[CONV2]] +; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i64 [[AND196]], 0 +; CHECK-NEXT: ret i1 [[TOBOOL_NOT]] +; + %conv = zext i16 %a to i32 + %shl1 = shl nsw i32 %conv, 11 + %conv2 = zext i32 %shl1 to i64 + %conv4 = zext i16 %b to i64 + %and = and i64 %conv2, %conv4 + %conv6 = zext i16 %c to i64 + %and7 = and i64 %and, %conv6 + %conv9 = zext i16 %d to i64 + %and10 = and i64 %and7, %conv9 + %conv12 = zext i16 %e to i64 + %and13 = and i64 %and10, %conv12 + %conv15 = zext i16 %f to i64 + %and16 = and i64 %and13, %conv15 + %conv18 = zext i16 %g to i64 + %and19 = and i64 %and16, %conv18 + %tobool.not = icmp eq i64 %and19, 0 + + ret i1 %tobool.not +} + +define i1 @sext_xor_chain(i16* %ptr, i16 %a, i16 %b, i16 %c, i16 %d, i16 %e, i16 %f, i16 %g) { +; CHECK-LABEL: @sext_xor_chain( +; CHECK-NEXT: [[CONV:%.*]] = sext i16 [[A:%.*]] to i32 +; CHECK-NEXT: [[SHL1:%.*]] = shl nsw i32 [[CONV]], 11 +; CHECK-NEXT: [[TMP1:%.*]] = xor i16 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i16 [[TMP1]], [[D:%.*]] +; CHECK-NEXT: [[TMP3:%.*]] = xor i16 [[TMP2]], [[E:%.*]] +; CHECK-NEXT: [[TMP4:%.*]] = xor i16 [[TMP3]], [[F:%.*]] +; CHECK-NEXT: [[TMP5:%.*]] = xor i16 [[TMP4]], [[G:%.*]] +; CHECK-NEXT: [[TMP6:%.*]] = sext i16 [[TMP5]] to i32 +; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[SHL1]], [[TMP6]] +; CHECK-NEXT: ret i1 [[TOBOOL_NOT]] +; + %conv = sext i16 %a to i32 + %shl1 = shl nsw i32 %conv, 11 + %conv2 = sext i32 %shl1 to i64 + %conv4 = sext i16 %b to i64 + %xor = xor i64 %conv2, %conv4 + %conv6 = sext i16 %c to i64 + %xor7 = xor i64 %xor, %conv6 + %conv9 = sext i16 %d to i64 + %xor10 = xor i64 %xor7, %conv9 + %conv12 = sext i16 %e to i64 + %xor13 = xor i64 %xor10, %conv12 + %conv15 = sext i16 %f to i64 + %xor16 = xor i64 %xor13, %conv15 + %conv18 = sext i16 %g to i64 + %xor19 = xor i64 %xor16, %conv18 + %tobool.not = icmp eq i64 %xor19, 0 + + ret i1 %tobool.not +} + + + +define i1 @zext_xor_chain(i16* %ptr, i16 %a, i16 %b, i16 %c, i16 %d, i16 %e, i16 %f, i16 %g) { +; CHECK-LABEL: @zext_xor_chain( +; CHECK-NEXT: [[CONV:%.*]] = zext i16 [[A:%.*]] to i32 +; CHECK-NEXT: [[SHL1:%.*]] = shl nuw nsw i32 [[CONV]], 11 +; CHECK-NEXT: [[TMP1:%.*]] = xor i16 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i16 [[TMP1]], [[D:%.*]] +; CHECK-NEXT: [[TMP3:%.*]] = xor i16 [[TMP2]], [[E:%.*]] +; CHECK-NEXT: [[TMP4:%.*]] = xor i16 [[TMP3]], [[F:%.*]] +; CHECK-NEXT: [[TMP5:%.*]] = xor i16 [[TMP4]], [[G:%.*]] +; CHECK-NEXT: [[TMP6:%.*]] = zext i16 [[TMP5]] to i32 +; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[SHL1]], [[TMP6]] +; CHECK-NEXT: ret i1 [[TOBOOL_NOT]] +; + %conv = zext i16 %a to i32 + %shl1 = shl nsw i32 %conv, 11 + %conv2 = zext i32 %shl1 to i64 + %conv4 = zext i16 %b to i64 + %xor = xor i64 %conv2, %conv4 + %conv6 = zext i16 %c to i64 + %xor7 = xor i64 %xor, %conv6 + %conv9 = zext i16 %d to i64 + %xor10 = xor i64 %xor7, %conv9 + %conv12 = zext i16 %e to i64 + %xor13 = xor i64 %xor10, %conv12 + %conv15 = zext i16 %f to i64 + %xor16 = xor i64 %xor13, %conv15 + %conv18 = zext i16 %g to i64 + %xor19 = xor i64 %xor16, %conv18 + %tobool.not = icmp eq i64 %xor19, 0 + + ret i1 %tobool.not +}