diff options
author | Han-Kuan Chen <hankuan.chen@sifive.com> | 2025-04-15 06:02:42 -0700 |
---|---|---|
committer | Han-Kuan Chen <hankuan.chen@sifive.com> | 2025-04-15 06:02:42 -0700 |
commit | e1382b3b459d39659694ee854073bbdb1aa1d98d (patch) | |
tree | b123e902ecb543747f33c5f59c95c200dae426f1 /llvm/lib | |
parent | ddfd81bb76c05b095c8eca7a45f71547c3df2a89 (diff) | |
download | llvm-e1382b3b459d39659694ee854073bbdb1aa1d98d.zip llvm-e1382b3b459d39659694ee854073bbdb1aa1d98d.tar.gz llvm-e1382b3b459d39659694ee854073bbdb1aa1d98d.tar.bz2 |
Revert "[SLP] Make getSameOpcode support interchangeable instructions. (#133888)"
This reverts commit 123993fd974629ca0a094918db4c21ad1c2624d0.
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp | 461 |
1 files changed, 51 insertions, 410 deletions
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp index a0837ab..50c4039 100644 --- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp +++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp @@ -599,28 +599,6 @@ static std::optional<unsigned> getElementIndex(const Value *Inst, return Index; } -/// \returns true if all of the values in \p VL use the same opcode. -/// For comparison instructions, also checks if predicates match. -/// PoisonValues are considered matching. -/// Interchangeable instructions are not considered. -static bool allSameOpcode(ArrayRef<Value *> VL) { - auto *It = find_if(VL, IsaPred<Instruction>); - if (It == VL.end()) - return true; - Instruction *MainOp = cast<Instruction>(*It); - unsigned Opcode = MainOp->getOpcode(); - bool IsCmpOp = isa<CmpInst>(MainOp); - CmpInst::Predicate BasePred = IsCmpOp ? cast<CmpInst>(MainOp)->getPredicate() - : CmpInst::BAD_ICMP_PREDICATE; - return std::all_of(It, VL.end(), [&](Value *V) { - if (auto *CI = dyn_cast<CmpInst>(V)) - return BasePred == CI->getPredicate(); - if (auto *I = dyn_cast<Instruction>(V)) - return I->getOpcode() == Opcode; - return isa<PoisonValue>(V); - }); -} - namespace { /// Specifies the way the mask should be analyzed for undefs/poisonous elements /// in the shuffle mask. @@ -836,271 +814,6 @@ static std::optional<unsigned> getExtractIndex(const Instruction *E) { } namespace { -/// \returns true if \p Opcode is allowed as part of the main/alternate -/// instruction for SLP vectorization. -/// -/// Example of unsupported opcode is SDIV that can potentially cause UB if the -/// "shuffled out" lane would result in division by zero. -bool isValidForAlternation(unsigned Opcode) { - return !Instruction::isIntDivRem(Opcode); -} - -/// Helper class that determines VL can use the same opcode. -/// Alternate instruction is supported. In addition, it supports interchangeable -/// instruction. An interchangeable instruction is an instruction that can be -/// converted to another instruction with same semantics. For example, x << 1 is -/// equal to x * 2. x * 1 is equal to x | 0. -class BinOpSameOpcodeHelper { - using MaskType = std::uint_fast16_t; - /// Sort SupportedOp because it is used by binary_search. - constexpr static std::initializer_list<unsigned> SupportedOp = { - Instruction::Add, Instruction::Sub, Instruction::Mul, Instruction::Shl, - Instruction::AShr, Instruction::And, Instruction::Or, Instruction::Xor}; - enum : MaskType { - ShlBIT = 0b1, - AShrBIT = 0b10, - MulBIT = 0b100, - AddBIT = 0b1000, - SubBIT = 0b10000, - AndBIT = 0b100000, - OrBIT = 0b1000000, - XorBIT = 0b10000000, - MainOpBIT = 0b100000000, - LLVM_MARK_AS_BITMASK_ENUM(MainOpBIT) - }; - /// Return a non-nullptr if either operand of I is a ConstantInt. - /// The second return value represents the operand position. We check the - /// right-hand side first (1). If the right hand side is not a ConstantInt and - /// the instruction is neither Sub, Shl, nor AShr, we then check the left hand - /// side (0). - static std::pair<ConstantInt *, unsigned> - isBinOpWithConstantInt(const Instruction *I) { - unsigned Opcode = I->getOpcode(); - assert(binary_search(SupportedOp, Opcode) && "Unsupported opcode."); - (void)SupportedOp; - auto *BinOp = cast<BinaryOperator>(I); - if (auto *CI = dyn_cast<ConstantInt>(BinOp->getOperand(1))) - return {CI, 1}; - if (Opcode == Instruction::Sub || Opcode == Instruction::Shl || - Opcode == Instruction::AShr) - return {nullptr, 0}; - if (auto *CI = dyn_cast<ConstantInt>(BinOp->getOperand(0))) - return {CI, 0}; - return {nullptr, 0}; - } - struct InterchangeableInfo { - const Instruction *I = nullptr; - /// The bit it sets represents whether MainOp can be converted to. - MaskType Mask = MainOpBIT | XorBIT | OrBIT | AndBIT | SubBIT | AddBIT | - MulBIT | AShrBIT | ShlBIT; - /// We cannot create an interchangeable instruction that does not exist in - /// VL. For example, VL [x + 0, y * 1] can be converted to [x << 0, y << 0], - /// but << does not exist in VL. In the end, we convert VL to [x * 1, y * - /// 1]. SeenBefore is used to know what operations have been seen before. - MaskType SeenBefore = 0; - InterchangeableInfo(const Instruction *I) : I(I) {} - /// Return false allows BinOpSameOpcodeHelper to find an alternate - /// instruction. Directly setting the mask will destroy the mask state, - /// preventing us from determining which instruction it should convert to. - bool trySet(MaskType OpcodeInMaskForm, MaskType InterchangeableMask) { - if (Mask & InterchangeableMask) { - SeenBefore |= OpcodeInMaskForm; - Mask &= InterchangeableMask; - return true; - } - return false; - } - bool equal(unsigned Opcode) { - if (Opcode == I->getOpcode()) - return trySet(MainOpBIT, MainOpBIT); - return false; - } - unsigned getOpcode() const { - MaskType Candidate = Mask & SeenBefore; - if (Candidate & MainOpBIT) - return I->getOpcode(); - if (Candidate & ShlBIT) - return Instruction::Shl; - if (Candidate & AShrBIT) - return Instruction::AShr; - if (Candidate & MulBIT) - return Instruction::Mul; - if (Candidate & AddBIT) - return Instruction::Add; - if (Candidate & SubBIT) - return Instruction::Sub; - if (Candidate & AndBIT) - return Instruction::And; - if (Candidate & OrBIT) - return Instruction::Or; - if (Candidate & XorBIT) - return Instruction::Xor; - llvm_unreachable("Cannot find interchangeable instruction."); - } - SmallVector<Value *> getOperand(const Instruction *To) const { - unsigned ToOpcode = To->getOpcode(); - unsigned FromOpcode = I->getOpcode(); - if (FromOpcode == ToOpcode) - return SmallVector<Value *>(I->operands()); - assert(binary_search(SupportedOp, ToOpcode) && "Unsupported opcode."); - auto [CI, Pos] = isBinOpWithConstantInt(I); - const APInt &FromCIValue = CI->getValue(); - unsigned FromCIValueBitWidth = FromCIValue.getBitWidth(); - APInt ToCIValue; - switch (FromOpcode) { - case Instruction::Shl: - if (ToOpcode == Instruction::Mul) { - ToCIValue = APInt::getOneBitSet(FromCIValueBitWidth, - FromCIValue.getZExtValue()); - } else { - assert(FromCIValue.isZero() && "Cannot convert the instruction."); - ToCIValue = ToOpcode == Instruction::And - ? APInt::getAllOnes(FromCIValueBitWidth) - : APInt::getZero(FromCIValueBitWidth); - } - break; - case Instruction::Mul: - assert(FromCIValue.isPowerOf2() && "Cannot convert the instruction."); - if (ToOpcode == Instruction::Shl) { - ToCIValue = APInt(FromCIValueBitWidth, FromCIValue.logBase2()); - } else { - assert(FromCIValue.isOne() && "Cannot convert the instruction."); - ToCIValue = ToOpcode == Instruction::And - ? APInt::getAllOnes(FromCIValueBitWidth) - : APInt::getZero(FromCIValueBitWidth); - } - break; - case Instruction::Add: - case Instruction::Sub: - if (FromCIValue.isZero()) { - ToCIValue = APInt::getZero(FromCIValueBitWidth); - } else { - assert(is_contained({Instruction::Add, Instruction::Sub}, ToOpcode) && - "Cannot convert the instruction."); - ToCIValue = FromCIValue; - ToCIValue.negate(); - } - break; - case Instruction::And: - assert(FromCIValue.isAllOnes() && "Cannot convert the instruction."); - ToCIValue = ToOpcode == Instruction::Mul - ? APInt::getOneBitSet(FromCIValueBitWidth, 0) - : APInt::getZero(FromCIValueBitWidth); - break; - default: - assert(FromCIValue.isZero() && "Cannot convert the instruction."); - ToCIValue = APInt::getZero(FromCIValueBitWidth); - break; - } - Value *LHS = I->getOperand(1 - Pos); - Constant *RHS = - ConstantInt::get(I->getOperand(Pos)->getType(), ToCIValue); - if (Pos == 1) - return SmallVector<Value *>({LHS, RHS}); - return SmallVector<Value *>({RHS, LHS}); - } - }; - InterchangeableInfo MainOp; - InterchangeableInfo AltOp; - bool isValidForAlternation(const Instruction *I) const { - return ::isValidForAlternation(MainOp.I->getOpcode()) && - ::isValidForAlternation(I->getOpcode()); - } - bool initializeAltOp(const Instruction *I) { - if (AltOp.I) - return true; - if (!isValidForAlternation(I)) - return false; - AltOp.I = I; - return true; - } - -public: - BinOpSameOpcodeHelper(const Instruction *MainOp, - const Instruction *AltOp = nullptr) - : MainOp(MainOp), AltOp(AltOp) { - assert(is_sorted(SupportedOp) && "SupportedOp is not sorted."); - } - bool add(const Instruction *I) { - assert(isa<BinaryOperator>(I) && - "BinOpSameOpcodeHelper only accepts BinaryOperator."); - unsigned Opcode = I->getOpcode(); - MaskType OpcodeInMaskForm; - // Prefer Shl, AShr, Mul, Add, Sub, And, Or and Xor over MainOp. - switch (Opcode) { - case Instruction::Shl: - OpcodeInMaskForm = ShlBIT; - break; - case Instruction::AShr: - OpcodeInMaskForm = AShrBIT; - break; - case Instruction::Mul: - OpcodeInMaskForm = MulBIT; - break; - case Instruction::Add: - OpcodeInMaskForm = AddBIT; - break; - case Instruction::Sub: - OpcodeInMaskForm = SubBIT; - break; - case Instruction::And: - OpcodeInMaskForm = AndBIT; - break; - case Instruction::Or: - OpcodeInMaskForm = OrBIT; - break; - case Instruction::Xor: - OpcodeInMaskForm = XorBIT; - break; - default: - return MainOp.equal(Opcode) || - (initializeAltOp(I) && AltOp.equal(Opcode)); - } - MaskType InterchangeableMask = OpcodeInMaskForm; - ConstantInt *CI = isBinOpWithConstantInt(I).first; - if (CI) { - constexpr MaskType CanBeAll = - XorBIT | OrBIT | AndBIT | SubBIT | AddBIT | MulBIT | AShrBIT | ShlBIT; - const APInt &CIValue = CI->getValue(); - switch (Opcode) { - case Instruction::Shl: - InterchangeableMask = CIValue.isZero() ? CanBeAll : MulBIT | ShlBIT; - break; - case Instruction::Mul: - if (CIValue.isOne()) { - InterchangeableMask = CanBeAll; - break; - } - if (CIValue.isPowerOf2()) - InterchangeableMask = MulBIT | ShlBIT; - break; - case Instruction::Add: - case Instruction::Sub: - InterchangeableMask = CIValue.isZero() ? CanBeAll : SubBIT | AddBIT; - break; - case Instruction::And: - if (CIValue.isAllOnes()) - InterchangeableMask = CanBeAll; - break; - default: - if (CIValue.isZero()) - InterchangeableMask = CanBeAll; - break; - } - } - return MainOp.trySet(OpcodeInMaskForm, InterchangeableMask) || - (initializeAltOp(I) && - AltOp.trySet(OpcodeInMaskForm, InterchangeableMask)); - } - unsigned getMainOpcode() const { return MainOp.getOpcode(); } - bool hasAltOp() const { return AltOp.I; } - unsigned getAltOpcode() const { - return hasAltOp() ? AltOp.getOpcode() : getMainOpcode(); - } - SmallVector<Value *> getOperand(const Instruction *I) const { - return MainOp.getOperand(I); - } -}; /// Main data required for vectorization of instructions. class InstructionsState { @@ -1148,27 +861,9 @@ public: /// Some of the instructions in the list have alternate opcodes. bool isAltShuffle() const { return getMainOp() != getAltOp(); } - /// Checks if the instruction matches either the main or alternate opcode. - /// \returns - /// - MainOp if \param I matches MainOp's opcode directly or can be converted - /// to it - /// - AltOp if \param I matches AltOp's opcode directly or can be converted to - /// it - /// - nullptr if \param I cannot be matched or converted to either opcode - Instruction *getMatchingMainOpOrAltOp(Instruction *I) const { - assert(MainOp && "MainOp cannot be nullptr."); - if (I->getOpcode() == MainOp->getOpcode()) - return MainOp; - // Prefer AltOp instead of interchangeable instruction of MainOp. - assert(AltOp && "AltOp cannot be nullptr."); - if (I->getOpcode() == AltOp->getOpcode()) - return AltOp; - if (!I->isBinaryOp()) - return nullptr; - BinOpSameOpcodeHelper Converter(MainOp); - if (Converter.add(I) && Converter.add(MainOp) && !Converter.hasAltOp()) - return MainOp; - return AltOp; + bool isOpcodeOrAlt(Instruction *I) const { + unsigned CheckedOpcode = I->getOpcode(); + return getOpcode() == CheckedOpcode || getAltOpcode() == CheckedOpcode; } /// Checks if main/alt instructions are shift operations. @@ -1218,41 +913,23 @@ public: static InstructionsState invalid() { return {nullptr, nullptr}; } }; -std::pair<Instruction *, SmallVector<Value *>> -convertTo(Instruction *I, const InstructionsState &S) { - Instruction *SelectedOp = S.getMatchingMainOpOrAltOp(I); - assert(SelectedOp && "Cannot convert the instruction."); - if (I->isBinaryOp()) { - BinOpSameOpcodeHelper Converter(I); - return std::make_pair(SelectedOp, Converter.getOperand(SelectedOp)); - } - return std::make_pair(SelectedOp, SmallVector<Value *>(I->operands())); -} - } // end anonymous namespace -static InstructionsState getSameOpcode(ArrayRef<Value *> VL, - const TargetLibraryInfo &TLI); +/// \returns true if \p Opcode is allowed as part of the main/alternate +/// instruction for SLP vectorization. +/// +/// Example of unsupported opcode is SDIV that can potentially cause UB if the +/// "shuffled out" lane would result in division by zero. +static bool isValidForAlternation(unsigned Opcode) { + if (Instruction::isIntDivRem(Opcode)) + return false; -/// Find an instruction with a specific opcode in VL. -/// \param VL Array of values to search through. Must contain only Instructions -/// and PoisonValues. -/// \param Opcode The instruction opcode to search for -/// \returns -/// - The first instruction found with matching opcode -/// - nullptr if no matching instruction is found -Instruction *findInstructionWithOpcode(ArrayRef<Value *> VL, unsigned Opcode) { - for (Value *V : VL) { - if (isa<PoisonValue>(V)) - continue; - assert(isa<Instruction>(V) && "Only accepts PoisonValue and Instruction."); - auto *Inst = cast<Instruction>(V); - if (Inst->getOpcode() == Opcode) - return Inst; - } - return nullptr; + return true; } +static InstructionsState getSameOpcode(ArrayRef<Value *> VL, + const TargetLibraryInfo &TLI); + /// Checks if the provided operands of 2 cmp instructions are compatible, i.e. /// compatible instructions or constants, or just some other regular values. static bool areCompatibleCmpOps(Value *BaseOp0, Value *BaseOp1, Value *Op0, @@ -1316,7 +993,6 @@ static InstructionsState getSameOpcode(ArrayRef<Value *> VL, unsigned Opcode = MainOp->getOpcode(); unsigned AltOpcode = Opcode; - BinOpSameOpcodeHelper BinOpHelper(MainOp); bool SwappedPredsCompatible = IsCmpOp && [&]() { SetVector<unsigned> UniquePreds, UniqueNonSwappedPreds; UniquePreds.insert(BasePred); @@ -1363,8 +1039,14 @@ static InstructionsState getSameOpcode(ArrayRef<Value *> VL, return InstructionsState::invalid(); unsigned InstOpcode = I->getOpcode(); if (IsBinOp && isa<BinaryOperator>(I)) { - if (BinOpHelper.add(I)) + if (InstOpcode == Opcode || InstOpcode == AltOpcode) continue; + if (Opcode == AltOpcode && isValidForAlternation(InstOpcode) && + isValidForAlternation(Opcode)) { + AltOpcode = InstOpcode; + AltOp = I; + continue; + } } else if (IsCastOp && isa<CastInst>(I)) { Value *Op0 = MainOp->getOperand(0); Type *Ty0 = Op0->getType(); @@ -1465,22 +1147,7 @@ static InstructionsState getSameOpcode(ArrayRef<Value *> VL, return InstructionsState::invalid(); } - if (IsBinOp) { - MainOp = findInstructionWithOpcode(VL, BinOpHelper.getMainOpcode()); - assert(MainOp && "Cannot find MainOp with Opcode from BinOpHelper."); - AltOp = findInstructionWithOpcode(VL, BinOpHelper.getAltOpcode()); - assert(MainOp && "Cannot find AltOp with Opcode from BinOpHelper."); - } - assert((MainOp == AltOp || !allSameOpcode(VL)) && - "Incorrect implementation of allSameOpcode."); - InstructionsState S(MainOp, AltOp); - assert(all_of(VL, - [&](Value *V) { - return isa<PoisonValue>(V) || - S.getMatchingMainOpOrAltOp(cast<Instruction>(V)); - }) && - "Invalid InstructionsState."); - return S; + return InstructionsState(MainOp, AltOp); } /// \returns true if all of the values in \p VL have the same type or false @@ -2893,11 +2560,11 @@ public: // Since operand reordering is performed on groups of commutative // operations or alternating sequences (e.g., +, -), we can safely tell // the inverse operations by checking commutativity. - auto [SelectedOp, Ops] = convertTo(cast<Instruction>(VL[Lane]), S); - bool IsInverseOperation = !isCommutative(SelectedOp); + bool IsInverseOperation = !isCommutative(cast<Instruction>(V)); for (unsigned OpIdx = 0; OpIdx != NumOperands; ++OpIdx) { bool APO = (OpIdx == 0) ? false : IsInverseOperation; - OpsVec[OpIdx][Lane] = {Ops[OpIdx], APO, false}; + OpsVec[OpIdx][Lane] = {cast<Instruction>(V)->getOperand(OpIdx), APO, + false}; } } } @@ -3875,16 +3542,14 @@ private: /// Some of the instructions in the list have alternate opcodes. bool isAltShuffle() const { return S.isAltShuffle(); } - Instruction *getMatchingMainOpOrAltOp(Instruction *I) const { - return S.getMatchingMainOpOrAltOp(I); - } + bool isOpcodeOrAlt(Instruction *I) const { return S.isOpcodeOrAlt(I); } /// Chooses the correct key for scheduling data. If \p Op has the same (or /// alternate) opcode as \p OpValue, the key is \p Op. Otherwise the key is /// \p OpValue. Value *isOneOf(Value *Op) const { auto *I = dyn_cast<Instruction>(Op); - if (I && getMatchingMainOpOrAltOp(I)) + if (I && isOpcodeOrAlt(I)) return Op; return S.getMainOp(); } @@ -8763,15 +8428,11 @@ static std::pair<size_t, size_t> generateKeySubkey( return std::make_pair(Key, SubKey); } -/// Checks if the specified instruction \p I is an main operation for the given -/// \p MainOp and \p AltOp instructions. -static bool isMainInstruction(Instruction *I, Instruction *MainOp, - Instruction *AltOp, const TargetLibraryInfo &TLI); - /// Checks if the specified instruction \p I is an alternate operation for /// the given \p MainOp and \p AltOp instructions. -static bool isAlternateInstruction(Instruction *I, Instruction *MainOp, - Instruction *AltOp, +static bool isAlternateInstruction(const Instruction *I, + const Instruction *MainOp, + const Instruction *AltOp, const TargetLibraryInfo &TLI); bool BoUpSLP::areAltOperandsProfitable(const InstructionsState &S, @@ -9584,8 +9245,7 @@ bool BoUpSLP::canBuildSplitNode(ArrayRef<Value *> VL, continue; } if ((LocalState.getAltOpcode() != LocalState.getOpcode() && - isMainInstruction(I, LocalState.getMainOp(), LocalState.getAltOp(), - *TLI)) || + I->getOpcode() == LocalState.getOpcode()) || (LocalState.getAltOpcode() == LocalState.getOpcode() && !isAlternateInstruction(I, LocalState.getMainOp(), LocalState.getAltOp(), *TLI))) { @@ -10684,14 +10344,9 @@ void BoUpSLP::TreeEntry::buildAltOpShuffleMask( } } -static bool isMainInstruction(Instruction *I, Instruction *MainOp, - Instruction *AltOp, - const TargetLibraryInfo &TLI) { - return InstructionsState(MainOp, AltOp).getMatchingMainOpOrAltOp(I) == MainOp; -} - -static bool isAlternateInstruction(Instruction *I, Instruction *MainOp, - Instruction *AltOp, +static bool isAlternateInstruction(const Instruction *I, + const Instruction *MainOp, + const Instruction *AltOp, const TargetLibraryInfo &TLI) { if (auto *MainCI = dyn_cast<CmpInst>(MainOp)) { auto *AltCI = cast<CmpInst>(AltOp); @@ -10711,7 +10366,7 @@ static bool isAlternateInstruction(Instruction *I, Instruction *MainOp, "their swap."); return MainP != P && MainP != SwappedP; } - return InstructionsState(MainOp, AltOp).getMatchingMainOpOrAltOp(I) == AltOp; + return I->getOpcode() == AltOp->getOpcode(); } TTI::OperandValueInfo BoUpSLP::getOperandInfo(ArrayRef<Value *> Ops) { @@ -11474,9 +11129,7 @@ void BoUpSLP::transformNodes() { // same opcode and same parent block or all constants. if (VL.size() <= 2 || LoadEntriesToVectorize.contains(Idx) || !(!E.hasState() || E.getOpcode() == Instruction::Load || - // We use allSameOpcode instead of isAltShuffle because we don't - // want to use interchangeable instruction here. - !allSameOpcode(VL) || !allSameBlock(VL)) || + E.isAltShuffle() || !allSameBlock(VL)) || allConstant(VL) || isSplat(VL)) continue; if (ForceLoadGather && E.hasState() && E.getOpcode() == Instruction::Load) @@ -11521,7 +11174,7 @@ void BoUpSLP::transformNodes() { if (IsSplat) continue; InstructionsState S = getSameOpcode(Slice, *TLI); - if (!S || !allSameOpcode(Slice) || !allSameBlock(Slice) || + if (!S || S.isAltShuffle() || !allSameBlock(Slice) || (S.getOpcode() == Instruction::Load && areKnownNonVectorizableLoads(Slice)) || (S.getOpcode() != Instruction::Load && @@ -13321,22 +12974,14 @@ BoUpSLP::getEntryCost(const TreeEntry *E, ArrayRef<Value *> VectorizedVals, if (isa<PoisonValue>(UniqueValues[Idx])) return InstructionCost(TTI::TCC_Free); - // We cannot retrieve the operand from UniqueValues[Idx] because an - // interchangeable instruction may be used. The order and the actual - // operand might differ from what is retrieved from UniqueValues[Idx]. - Value *Op1 = E->getOperand(0)[Idx]; - Value *Op2; - SmallVector<const Value *, 2> Operands(1, Op1); - if (isa<UnaryOperator>(UniqueValues[Idx])) { - Op2 = Op1; - } else { - Op2 = E->getOperand(1)[Idx]; - Operands.push_back(Op2); - } - TTI::OperandValueInfo Op1Info = TTI::getOperandInfo(Op1); - TTI::OperandValueInfo Op2Info = TTI::getOperandInfo(Op2); + auto *VI = cast<Instruction>(UniqueValues[Idx]); + unsigned OpIdx = isa<UnaryOperator>(VI) ? 0 : 1; + TTI::OperandValueInfo Op1Info = TTI::getOperandInfo(VI->getOperand(0)); + TTI::OperandValueInfo Op2Info = + TTI::getOperandInfo(VI->getOperand(OpIdx)); + SmallVector<const Value *> Operands(VI->operand_values()); return TTI->getArithmeticInstrCost(ShuffleOrOp, OrigScalarTy, CostKind, - Op1Info, Op2Info, Operands); + Op1Info, Op2Info, Operands, VI); }; auto GetVectorCost = [=](InstructionCost CommonCost) { if (ShuffleOrOp == Instruction::And && It != MinBWs.end()) { @@ -13566,8 +13211,7 @@ BoUpSLP::getEntryCost(const TreeEntry *E, ArrayRef<Value *> VectorizedVals, return InstructionCost(TTI::TCC_Free); auto *VI = cast<Instruction>(UniqueValues[Idx]); - assert(E->getMatchingMainOpOrAltOp(VI) && - "Unexpected main/alternate opcode"); + assert(E->isOpcodeOrAlt(VI) && "Unexpected main/alternate opcode"); (void)E; return TTI->getInstructionCost(VI, CostKind); }; @@ -13635,8 +13279,7 @@ BoUpSLP::getEntryCost(const TreeEntry *E, ArrayRef<Value *> VectorizedVals, SmallVector<int> Mask; E->buildAltOpShuffleMask( [&](Instruction *I) { - assert(E->getMatchingMainOpOrAltOp(I) && - "Unexpected main/alternate opcode"); + assert(E->isOpcodeOrAlt(I) && "Unexpected main/alternate opcode"); return isAlternateInstruction(I, E->getMainOp(), E->getAltOp(), *TLI); }, @@ -15798,8 +15441,7 @@ Instruction &BoUpSLP::getLastInstructionInBundle(const TreeEntry *E) { !isa<GetElementPtrInst>(V)) return true; auto *I = dyn_cast<Instruction>(V); - return !I || !E->getMatchingMainOpOrAltOp(I) || - I->getParent() == BB || + return !I || !E->isOpcodeOrAlt(I) || I->getParent() == BB || isVectorLikeInstWithConstOps(I); })) && "Expected gathered loads or GEPs or instructions from same basic " @@ -17943,7 +17585,7 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E) { Value *V = Builder.CreateBinOp( static_cast<Instruction::BinaryOps>(E->getOpcode()), LHS, RHS); - propagateIRFlags(V, E->Scalars, nullptr, It == MinBWs.end()); + propagateIRFlags(V, E->Scalars, VL0, It == MinBWs.end()); if (auto *I = dyn_cast<Instruction>(V)) { V = ::propagateMetadata(I, E->Scalars); // Drop nuw flags for abs(sub(commutative), true). @@ -18363,8 +18005,7 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E) { SmallVector<int> Mask; E->buildAltOpShuffleMask( [E, this](Instruction *I) { - assert(E->getMatchingMainOpOrAltOp(I) && - "Unexpected main/alternate opcode"); + assert(E->isOpcodeOrAlt(I) && "Unexpected main/alternate opcode"); return isAlternateInstruction(I, E->getMainOp(), E->getAltOp(), *TLI); }, @@ -22151,7 +21792,7 @@ public: // Also check if the instruction was folded to constant/other value. auto *Inst = dyn_cast<Instruction>(RdxVal); if ((Inst && isVectorLikeInstWithConstOps(Inst) && - (!S || !S.getMatchingMainOpOrAltOp(Inst))) || + (!S || !S.isOpcodeOrAlt(Inst))) || (S && !Inst)) continue; Candidates.push_back(RdxVal); |