4841 lines · cpp
1//===------- VectorCombine.cpp - Optimize partial vector operations -------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This pass optimizes scalar/vector interactions using target cost models. The10// transforms implemented here may not fit in traditional loop-based or SLP11// vectorization passes.12//13//===----------------------------------------------------------------------===//14 15#include "llvm/Transforms/Vectorize/VectorCombine.h"16#include "llvm/ADT/DenseMap.h"17#include "llvm/ADT/STLExtras.h"18#include "llvm/ADT/ScopeExit.h"19#include "llvm/ADT/SmallVector.h"20#include "llvm/ADT/Statistic.h"21#include "llvm/Analysis/AssumptionCache.h"22#include "llvm/Analysis/BasicAliasAnalysis.h"23#include "llvm/Analysis/GlobalsModRef.h"24#include "llvm/Analysis/InstSimplifyFolder.h"25#include "llvm/Analysis/Loads.h"26#include "llvm/Analysis/TargetFolder.h"27#include "llvm/Analysis/TargetTransformInfo.h"28#include "llvm/Analysis/ValueTracking.h"29#include "llvm/Analysis/VectorUtils.h"30#include "llvm/IR/Dominators.h"31#include "llvm/IR/Function.h"32#include "llvm/IR/IRBuilder.h"33#include "llvm/IR/Instructions.h"34#include "llvm/IR/PatternMatch.h"35#include "llvm/Support/CommandLine.h"36#include "llvm/Transforms/Utils/Local.h"37#include "llvm/Transforms/Utils/LoopUtils.h"38#include <numeric>39#include <optional>40#include <queue>41#include <set>42 43#define DEBUG_TYPE "vector-combine"44#include "llvm/Transforms/Utils/InstructionWorklist.h"45 46using namespace llvm;47using namespace llvm::PatternMatch;48 49STATISTIC(NumVecLoad, "Number of vector loads formed");50STATISTIC(NumVecCmp, "Number of vector compares formed");51STATISTIC(NumVecBO, "Number of vector binops formed");52STATISTIC(NumVecCmpBO, "Number of vector compare + binop formed");53STATISTIC(NumShufOfBitcast, "Number of shuffles moved after bitcast");54STATISTIC(NumScalarOps, "Number of scalar unary + binary ops formed");55STATISTIC(NumScalarCmp, "Number of scalar compares formed");56STATISTIC(NumScalarIntrinsic, "Number of scalar intrinsic calls formed");57 58static cl::opt<bool> DisableVectorCombine(59 "disable-vector-combine", cl::init(false), cl::Hidden,60 cl::desc("Disable all vector combine transforms"));61 62static cl::opt<bool> DisableBinopExtractShuffle(63 "disable-binop-extract-shuffle", cl::init(false), cl::Hidden,64 cl::desc("Disable binop extract to shuffle transforms"));65 66static cl::opt<unsigned> MaxInstrsToScan(67 "vector-combine-max-scan-instrs", cl::init(30), cl::Hidden,68 cl::desc("Max number of instructions to scan for vector combining."));69 70static const unsigned InvalidIndex = std::numeric_limits<unsigned>::max();71 72namespace {73class VectorCombine {74public:75 VectorCombine(Function &F, const TargetTransformInfo &TTI,76 const DominatorTree &DT, AAResults &AA, AssumptionCache &AC,77 const DataLayout *DL, TTI::TargetCostKind CostKind,78 bool TryEarlyFoldsOnly)79 : F(F), Builder(F.getContext(), InstSimplifyFolder(*DL)), TTI(TTI),80 DT(DT), AA(AA), AC(AC), DL(DL), CostKind(CostKind), SQ(*DL),81 TryEarlyFoldsOnly(TryEarlyFoldsOnly) {}82 83 bool run();84 85private:86 Function &F;87 IRBuilder<InstSimplifyFolder> Builder;88 const TargetTransformInfo &TTI;89 const DominatorTree &DT;90 AAResults &AA;91 AssumptionCache &AC;92 const DataLayout *DL;93 TTI::TargetCostKind CostKind;94 const SimplifyQuery SQ;95 96 /// If true, only perform beneficial early IR transforms. Do not introduce new97 /// vector operations.98 bool TryEarlyFoldsOnly;99 100 InstructionWorklist Worklist;101 102 /// Next instruction to iterate. It will be updated when it is erased by103 /// RecursivelyDeleteTriviallyDeadInstructions.104 Instruction *NextInst;105 106 // TODO: Direct calls from the top-level "run" loop use a plain "Instruction"107 // parameter. That should be updated to specific sub-classes because the108 // run loop was changed to dispatch on opcode.109 bool vectorizeLoadInsert(Instruction &I);110 bool widenSubvectorLoad(Instruction &I);111 ExtractElementInst *getShuffleExtract(ExtractElementInst *Ext0,112 ExtractElementInst *Ext1,113 unsigned PreferredExtractIndex) const;114 bool isExtractExtractCheap(ExtractElementInst *Ext0, ExtractElementInst *Ext1,115 const Instruction &I,116 ExtractElementInst *&ConvertToShuffle,117 unsigned PreferredExtractIndex);118 Value *foldExtExtCmp(Value *V0, Value *V1, Value *ExtIndex, Instruction &I);119 Value *foldExtExtBinop(Value *V0, Value *V1, Value *ExtIndex, Instruction &I);120 bool foldExtractExtract(Instruction &I);121 bool foldInsExtFNeg(Instruction &I);122 bool foldInsExtBinop(Instruction &I);123 bool foldInsExtVectorToShuffle(Instruction &I);124 bool foldBitOpOfCastops(Instruction &I);125 bool foldBitOpOfCastConstant(Instruction &I);126 bool foldBitcastShuffle(Instruction &I);127 bool scalarizeOpOrCmp(Instruction &I);128 bool scalarizeVPIntrinsic(Instruction &I);129 bool foldExtractedCmps(Instruction &I);130 bool foldBinopOfReductions(Instruction &I);131 bool foldSingleElementStore(Instruction &I);132 bool scalarizeLoad(Instruction &I);133 bool scalarizeLoadExtract(LoadInst *LI, VectorType *VecTy, Value *Ptr);134 bool scalarizeLoadBitcast(LoadInst *LI, VectorType *VecTy, Value *Ptr);135 bool scalarizeExtExtract(Instruction &I);136 bool foldConcatOfBoolMasks(Instruction &I);137 bool foldPermuteOfBinops(Instruction &I);138 bool foldShuffleOfBinops(Instruction &I);139 bool foldShuffleOfSelects(Instruction &I);140 bool foldShuffleOfCastops(Instruction &I);141 bool foldShuffleOfShuffles(Instruction &I);142 bool foldShuffleOfIntrinsics(Instruction &I);143 bool foldShuffleToIdentity(Instruction &I);144 bool foldShuffleFromReductions(Instruction &I);145 bool foldShuffleChainsToReduce(Instruction &I);146 bool foldCastFromReductions(Instruction &I);147 bool foldSelectShuffle(Instruction &I, bool FromReduction = false);148 bool foldInterleaveIntrinsics(Instruction &I);149 bool shrinkType(Instruction &I);150 bool shrinkLoadForShuffles(Instruction &I);151 bool shrinkPhiOfShuffles(Instruction &I);152 153 void replaceValue(Instruction &Old, Value &New, bool Erase = true) {154 LLVM_DEBUG(dbgs() << "VC: Replacing: " << Old << '\n');155 LLVM_DEBUG(dbgs() << " With: " << New << '\n');156 Old.replaceAllUsesWith(&New);157 if (auto *NewI = dyn_cast<Instruction>(&New)) {158 New.takeName(&Old);159 Worklist.pushUsersToWorkList(*NewI);160 Worklist.pushValue(NewI);161 }162 if (Erase && isInstructionTriviallyDead(&Old)) {163 eraseInstruction(Old);164 } else {165 Worklist.push(&Old);166 }167 }168 169 void eraseInstruction(Instruction &I) {170 LLVM_DEBUG(dbgs() << "VC: Erasing: " << I << '\n');171 SmallVector<Value *> Ops(I.operands());172 Worklist.remove(&I);173 I.eraseFromParent();174 175 // Push remaining users of the operands and then the operand itself - allows176 // further folds that were hindered by OneUse limits.177 SmallPtrSet<Value *, 4> Visited;178 for (Value *Op : Ops) {179 if (!Visited.contains(Op)) {180 if (auto *OpI = dyn_cast<Instruction>(Op)) {181 if (RecursivelyDeleteTriviallyDeadInstructions(182 OpI, nullptr, nullptr, [&](Value *V) {183 if (auto *I = dyn_cast<Instruction>(V)) {184 LLVM_DEBUG(dbgs() << "VC: Erased: " << *I << '\n');185 Worklist.remove(I);186 if (I == NextInst)187 NextInst = NextInst->getNextNode();188 Visited.insert(I);189 }190 }))191 continue;192 Worklist.pushUsersToWorkList(*OpI);193 Worklist.pushValue(OpI);194 }195 }196 }197 }198};199} // namespace200 201/// Return the source operand of a potentially bitcasted value. If there is no202/// bitcast, return the input value itself.203static Value *peekThroughBitcasts(Value *V) {204 while (auto *BitCast = dyn_cast<BitCastInst>(V))205 V = BitCast->getOperand(0);206 return V;207}208 209static bool canWidenLoad(LoadInst *Load, const TargetTransformInfo &TTI) {210 // Do not widen load if atomic/volatile or under asan/hwasan/memtag/tsan.211 // The widened load may load data from dirty regions or create data races212 // non-existent in the source.213 if (!Load || !Load->isSimple() || !Load->hasOneUse() ||214 Load->getFunction()->hasFnAttribute(Attribute::SanitizeMemTag) ||215 mustSuppressSpeculation(*Load))216 return false;217 218 // We are potentially transforming byte-sized (8-bit) memory accesses, so make219 // sure we have all of our type-based constraints in place for this target.220 Type *ScalarTy = Load->getType()->getScalarType();221 uint64_t ScalarSize = ScalarTy->getPrimitiveSizeInBits();222 unsigned MinVectorSize = TTI.getMinVectorRegisterBitWidth();223 if (!ScalarSize || !MinVectorSize || MinVectorSize % ScalarSize != 0 ||224 ScalarSize % 8 != 0)225 return false;226 227 return true;228}229 230bool VectorCombine::vectorizeLoadInsert(Instruction &I) {231 // Match insert into fixed vector of scalar value.232 // TODO: Handle non-zero insert index.233 Value *Scalar;234 if (!match(&I,235 m_InsertElt(m_Poison(), m_OneUse(m_Value(Scalar)), m_ZeroInt())))236 return false;237 238 // Optionally match an extract from another vector.239 Value *X;240 bool HasExtract = match(Scalar, m_ExtractElt(m_Value(X), m_ZeroInt()));241 if (!HasExtract)242 X = Scalar;243 244 auto *Load = dyn_cast<LoadInst>(X);245 if (!canWidenLoad(Load, TTI))246 return false;247 248 Type *ScalarTy = Scalar->getType();249 uint64_t ScalarSize = ScalarTy->getPrimitiveSizeInBits();250 unsigned MinVectorSize = TTI.getMinVectorRegisterBitWidth();251 252 // Check safety of replacing the scalar load with a larger vector load.253 // We use minimal alignment (maximum flexibility) because we only care about254 // the dereferenceable region. When calculating cost and creating a new op,255 // we may use a larger value based on alignment attributes.256 Value *SrcPtr = Load->getPointerOperand()->stripPointerCasts();257 assert(isa<PointerType>(SrcPtr->getType()) && "Expected a pointer type");258 259 unsigned MinVecNumElts = MinVectorSize / ScalarSize;260 auto *MinVecTy = VectorType::get(ScalarTy, MinVecNumElts, false);261 unsigned OffsetEltIndex = 0;262 Align Alignment = Load->getAlign();263 if (!isSafeToLoadUnconditionally(SrcPtr, MinVecTy, Align(1), *DL, Load, &AC,264 &DT)) {265 // It is not safe to load directly from the pointer, but we can still peek266 // through gep offsets and check if it safe to load from a base address with267 // updated alignment. If it is, we can shuffle the element(s) into place268 // after loading.269 unsigned OffsetBitWidth = DL->getIndexTypeSizeInBits(SrcPtr->getType());270 APInt Offset(OffsetBitWidth, 0);271 SrcPtr = SrcPtr->stripAndAccumulateInBoundsConstantOffsets(*DL, Offset);272 273 // We want to shuffle the result down from a high element of a vector, so274 // the offset must be positive.275 if (Offset.isNegative())276 return false;277 278 // The offset must be a multiple of the scalar element to shuffle cleanly279 // in the element's size.280 uint64_t ScalarSizeInBytes = ScalarSize / 8;281 if (Offset.urem(ScalarSizeInBytes) != 0)282 return false;283 284 // If we load MinVecNumElts, will our target element still be loaded?285 OffsetEltIndex = Offset.udiv(ScalarSizeInBytes).getZExtValue();286 if (OffsetEltIndex >= MinVecNumElts)287 return false;288 289 if (!isSafeToLoadUnconditionally(SrcPtr, MinVecTy, Align(1), *DL, Load, &AC,290 &DT))291 return false;292 293 // Update alignment with offset value. Note that the offset could be negated294 // to more accurately represent "(new) SrcPtr - Offset = (old) SrcPtr", but295 // negation does not change the result of the alignment calculation.296 Alignment = commonAlignment(Alignment, Offset.getZExtValue());297 }298 299 // Original pattern: insertelt undef, load [free casts of] PtrOp, 0300 // Use the greater of the alignment on the load or its source pointer.301 Alignment = std::max(SrcPtr->getPointerAlignment(*DL), Alignment);302 Type *LoadTy = Load->getType();303 unsigned AS = Load->getPointerAddressSpace();304 InstructionCost OldCost =305 TTI.getMemoryOpCost(Instruction::Load, LoadTy, Alignment, AS, CostKind);306 APInt DemandedElts = APInt::getOneBitSet(MinVecNumElts, 0);307 OldCost +=308 TTI.getScalarizationOverhead(MinVecTy, DemandedElts,309 /* Insert */ true, HasExtract, CostKind);310 311 // New pattern: load VecPtr312 InstructionCost NewCost =313 TTI.getMemoryOpCost(Instruction::Load, MinVecTy, Alignment, AS, CostKind);314 // Optionally, we are shuffling the loaded vector element(s) into place.315 // For the mask set everything but element 0 to undef to prevent poison from316 // propagating from the extra loaded memory. This will also optionally317 // shrink/grow the vector from the loaded size to the output size.318 // We assume this operation has no cost in codegen if there was no offset.319 // Note that we could use freeze to avoid poison problems, but then we might320 // still need a shuffle to change the vector size.321 auto *Ty = cast<FixedVectorType>(I.getType());322 unsigned OutputNumElts = Ty->getNumElements();323 SmallVector<int, 16> Mask(OutputNumElts, PoisonMaskElem);324 assert(OffsetEltIndex < MinVecNumElts && "Address offset too big");325 Mask[0] = OffsetEltIndex;326 if (OffsetEltIndex)327 NewCost += TTI.getShuffleCost(TTI::SK_PermuteSingleSrc, Ty, MinVecTy, Mask,328 CostKind);329 330 // We can aggressively convert to the vector form because the backend can331 // invert this transform if it does not result in a performance win.332 if (OldCost < NewCost || !NewCost.isValid())333 return false;334 335 // It is safe and potentially profitable to load a vector directly:336 // inselt undef, load Scalar, 0 --> load VecPtr337 IRBuilder<> Builder(Load);338 Value *CastedPtr =339 Builder.CreatePointerBitCastOrAddrSpaceCast(SrcPtr, Builder.getPtrTy(AS));340 Value *VecLd = Builder.CreateAlignedLoad(MinVecTy, CastedPtr, Alignment);341 VecLd = Builder.CreateShuffleVector(VecLd, Mask);342 343 replaceValue(I, *VecLd);344 ++NumVecLoad;345 return true;346}347 348/// If we are loading a vector and then inserting it into a larger vector with349/// undefined elements, try to load the larger vector and eliminate the insert.350/// This removes a shuffle in IR and may allow combining of other loaded values.351bool VectorCombine::widenSubvectorLoad(Instruction &I) {352 // Match subvector insert of fixed vector.353 auto *Shuf = cast<ShuffleVectorInst>(&I);354 if (!Shuf->isIdentityWithPadding())355 return false;356 357 // Allow a non-canonical shuffle mask that is choosing elements from op1.358 unsigned NumOpElts =359 cast<FixedVectorType>(Shuf->getOperand(0)->getType())->getNumElements();360 unsigned OpIndex = any_of(Shuf->getShuffleMask(), [&NumOpElts](int M) {361 return M >= (int)(NumOpElts);362 });363 364 auto *Load = dyn_cast<LoadInst>(Shuf->getOperand(OpIndex));365 if (!canWidenLoad(Load, TTI))366 return false;367 368 // We use minimal alignment (maximum flexibility) because we only care about369 // the dereferenceable region. When calculating cost and creating a new op,370 // we may use a larger value based on alignment attributes.371 auto *Ty = cast<FixedVectorType>(I.getType());372 Value *SrcPtr = Load->getPointerOperand()->stripPointerCasts();373 assert(isa<PointerType>(SrcPtr->getType()) && "Expected a pointer type");374 Align Alignment = Load->getAlign();375 if (!isSafeToLoadUnconditionally(SrcPtr, Ty, Align(1), *DL, Load, &AC, &DT))376 return false;377 378 Alignment = std::max(SrcPtr->getPointerAlignment(*DL), Alignment);379 Type *LoadTy = Load->getType();380 unsigned AS = Load->getPointerAddressSpace();381 382 // Original pattern: insert_subvector (load PtrOp)383 // This conservatively assumes that the cost of a subvector insert into an384 // undef value is 0. We could add that cost if the cost model accurately385 // reflects the real cost of that operation.386 InstructionCost OldCost =387 TTI.getMemoryOpCost(Instruction::Load, LoadTy, Alignment, AS, CostKind);388 389 // New pattern: load PtrOp390 InstructionCost NewCost =391 TTI.getMemoryOpCost(Instruction::Load, Ty, Alignment, AS, CostKind);392 393 // We can aggressively convert to the vector form because the backend can394 // invert this transform if it does not result in a performance win.395 if (OldCost < NewCost || !NewCost.isValid())396 return false;397 398 IRBuilder<> Builder(Load);399 Value *CastedPtr =400 Builder.CreatePointerBitCastOrAddrSpaceCast(SrcPtr, Builder.getPtrTy(AS));401 Value *VecLd = Builder.CreateAlignedLoad(Ty, CastedPtr, Alignment);402 replaceValue(I, *VecLd);403 ++NumVecLoad;404 return true;405}406 407/// Determine which, if any, of the inputs should be replaced by a shuffle408/// followed by extract from a different index.409ExtractElementInst *VectorCombine::getShuffleExtract(410 ExtractElementInst *Ext0, ExtractElementInst *Ext1,411 unsigned PreferredExtractIndex = InvalidIndex) const {412 auto *Index0C = dyn_cast<ConstantInt>(Ext0->getIndexOperand());413 auto *Index1C = dyn_cast<ConstantInt>(Ext1->getIndexOperand());414 assert(Index0C && Index1C && "Expected constant extract indexes");415 416 unsigned Index0 = Index0C->getZExtValue();417 unsigned Index1 = Index1C->getZExtValue();418 419 // If the extract indexes are identical, no shuffle is needed.420 if (Index0 == Index1)421 return nullptr;422 423 Type *VecTy = Ext0->getVectorOperand()->getType();424 assert(VecTy == Ext1->getVectorOperand()->getType() && "Need matching types");425 InstructionCost Cost0 =426 TTI.getVectorInstrCost(*Ext0, VecTy, CostKind, Index0);427 InstructionCost Cost1 =428 TTI.getVectorInstrCost(*Ext1, VecTy, CostKind, Index1);429 430 // If both costs are invalid no shuffle is needed431 if (!Cost0.isValid() && !Cost1.isValid())432 return nullptr;433 434 // We are extracting from 2 different indexes, so one operand must be shuffled435 // before performing a vector operation and/or extract. The more expensive436 // extract will be replaced by a shuffle.437 if (Cost0 > Cost1)438 return Ext0;439 if (Cost1 > Cost0)440 return Ext1;441 442 // If the costs are equal and there is a preferred extract index, shuffle the443 // opposite operand.444 if (PreferredExtractIndex == Index0)445 return Ext1;446 if (PreferredExtractIndex == Index1)447 return Ext0;448 449 // Otherwise, replace the extract with the higher index.450 return Index0 > Index1 ? Ext0 : Ext1;451}452 453/// Compare the relative costs of 2 extracts followed by scalar operation vs.454/// vector operation(s) followed by extract. Return true if the existing455/// instructions are cheaper than a vector alternative. Otherwise, return false456/// and if one of the extracts should be transformed to a shufflevector, set457/// \p ConvertToShuffle to that extract instruction.458bool VectorCombine::isExtractExtractCheap(ExtractElementInst *Ext0,459 ExtractElementInst *Ext1,460 const Instruction &I,461 ExtractElementInst *&ConvertToShuffle,462 unsigned PreferredExtractIndex) {463 auto *Ext0IndexC = dyn_cast<ConstantInt>(Ext0->getIndexOperand());464 auto *Ext1IndexC = dyn_cast<ConstantInt>(Ext1->getIndexOperand());465 assert(Ext0IndexC && Ext1IndexC && "Expected constant extract indexes");466 467 unsigned Opcode = I.getOpcode();468 Value *Ext0Src = Ext0->getVectorOperand();469 Value *Ext1Src = Ext1->getVectorOperand();470 Type *ScalarTy = Ext0->getType();471 auto *VecTy = cast<VectorType>(Ext0Src->getType());472 InstructionCost ScalarOpCost, VectorOpCost;473 474 // Get cost estimates for scalar and vector versions of the operation.475 bool IsBinOp = Instruction::isBinaryOp(Opcode);476 if (IsBinOp) {477 ScalarOpCost = TTI.getArithmeticInstrCost(Opcode, ScalarTy, CostKind);478 VectorOpCost = TTI.getArithmeticInstrCost(Opcode, VecTy, CostKind);479 } else {480 assert((Opcode == Instruction::ICmp || Opcode == Instruction::FCmp) &&481 "Expected a compare");482 CmpInst::Predicate Pred = cast<CmpInst>(I).getPredicate();483 ScalarOpCost = TTI.getCmpSelInstrCost(484 Opcode, ScalarTy, CmpInst::makeCmpResultType(ScalarTy), Pred, CostKind);485 VectorOpCost = TTI.getCmpSelInstrCost(486 Opcode, VecTy, CmpInst::makeCmpResultType(VecTy), Pred, CostKind);487 }488 489 // Get cost estimates for the extract elements. These costs will factor into490 // both sequences.491 unsigned Ext0Index = Ext0IndexC->getZExtValue();492 unsigned Ext1Index = Ext1IndexC->getZExtValue();493 494 InstructionCost Extract0Cost =495 TTI.getVectorInstrCost(*Ext0, VecTy, CostKind, Ext0Index);496 InstructionCost Extract1Cost =497 TTI.getVectorInstrCost(*Ext1, VecTy, CostKind, Ext1Index);498 499 // A more expensive extract will always be replaced by a splat shuffle.500 // For example, if Ext0 is more expensive:501 // opcode (extelt V0, Ext0), (ext V1, Ext1) -->502 // extelt (opcode (splat V0, Ext0), V1), Ext1503 // TODO: Evaluate whether that always results in lowest cost. Alternatively,504 // check the cost of creating a broadcast shuffle and shuffling both505 // operands to element 0.506 unsigned BestExtIndex = Extract0Cost > Extract1Cost ? Ext0Index : Ext1Index;507 unsigned BestInsIndex = Extract0Cost > Extract1Cost ? Ext1Index : Ext0Index;508 InstructionCost CheapExtractCost = std::min(Extract0Cost, Extract1Cost);509 510 // Extra uses of the extracts mean that we include those costs in the511 // vector total because those instructions will not be eliminated.512 InstructionCost OldCost, NewCost;513 if (Ext0Src == Ext1Src && Ext0Index == Ext1Index) {514 // Handle a special case. If the 2 extracts are identical, adjust the515 // formulas to account for that. The extra use charge allows for either the516 // CSE'd pattern or an unoptimized form with identical values:517 // opcode (extelt V, C), (extelt V, C) --> extelt (opcode V, V), C518 bool HasUseTax = Ext0 == Ext1 ? !Ext0->hasNUses(2)519 : !Ext0->hasOneUse() || !Ext1->hasOneUse();520 OldCost = CheapExtractCost + ScalarOpCost;521 NewCost = VectorOpCost + CheapExtractCost + HasUseTax * CheapExtractCost;522 } else {523 // Handle the general case. Each extract is actually a different value:524 // opcode (extelt V0, C0), (extelt V1, C1) --> extelt (opcode V0, V1), C525 OldCost = Extract0Cost + Extract1Cost + ScalarOpCost;526 NewCost = VectorOpCost + CheapExtractCost +527 !Ext0->hasOneUse() * Extract0Cost +528 !Ext1->hasOneUse() * Extract1Cost;529 }530 531 ConvertToShuffle = getShuffleExtract(Ext0, Ext1, PreferredExtractIndex);532 if (ConvertToShuffle) {533 if (IsBinOp && DisableBinopExtractShuffle)534 return true;535 536 // If we are extracting from 2 different indexes, then one operand must be537 // shuffled before performing the vector operation. The shuffle mask is538 // poison except for 1 lane that is being translated to the remaining539 // extraction lane. Therefore, it is a splat shuffle. Ex:540 // ShufMask = { poison, poison, 0, poison }541 // TODO: The cost model has an option for a "broadcast" shuffle542 // (splat-from-element-0), but no option for a more general splat.543 if (auto *FixedVecTy = dyn_cast<FixedVectorType>(VecTy)) {544 SmallVector<int> ShuffleMask(FixedVecTy->getNumElements(),545 PoisonMaskElem);546 ShuffleMask[BestInsIndex] = BestExtIndex;547 NewCost += TTI.getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc,548 VecTy, VecTy, ShuffleMask, CostKind, 0,549 nullptr, {ConvertToShuffle});550 } else {551 NewCost += TTI.getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc,552 VecTy, VecTy, {}, CostKind, 0, nullptr,553 {ConvertToShuffle});554 }555 }556 557 // Aggressively form a vector op if the cost is equal because the transform558 // may enable further optimization.559 // Codegen can reverse this transform (scalarize) if it was not profitable.560 return OldCost < NewCost;561}562 563/// Create a shuffle that translates (shifts) 1 element from the input vector564/// to a new element location.565static Value *createShiftShuffle(Value *Vec, unsigned OldIndex,566 unsigned NewIndex, IRBuilderBase &Builder) {567 // The shuffle mask is poison except for 1 lane that is being translated568 // to the new element index. Example for OldIndex == 2 and NewIndex == 0:569 // ShufMask = { 2, poison, poison, poison }570 auto *VecTy = cast<FixedVectorType>(Vec->getType());571 SmallVector<int, 32> ShufMask(VecTy->getNumElements(), PoisonMaskElem);572 ShufMask[NewIndex] = OldIndex;573 return Builder.CreateShuffleVector(Vec, ShufMask, "shift");574}575 576/// Given an extract element instruction with constant index operand, shuffle577/// the source vector (shift the scalar element) to a NewIndex for extraction.578/// Return null if the input can be constant folded, so that we are not creating579/// unnecessary instructions.580static Value *translateExtract(ExtractElementInst *ExtElt, unsigned NewIndex,581 IRBuilderBase &Builder) {582 // Shufflevectors can only be created for fixed-width vectors.583 Value *X = ExtElt->getVectorOperand();584 if (!isa<FixedVectorType>(X->getType()))585 return nullptr;586 587 // If the extract can be constant-folded, this code is unsimplified. Defer588 // to other passes to handle that.589 Value *C = ExtElt->getIndexOperand();590 assert(isa<ConstantInt>(C) && "Expected a constant index operand");591 if (isa<Constant>(X))592 return nullptr;593 594 Value *Shuf = createShiftShuffle(X, cast<ConstantInt>(C)->getZExtValue(),595 NewIndex, Builder);596 return Shuf;597}598 599/// Try to reduce extract element costs by converting scalar compares to vector600/// compares followed by extract.601/// cmp (ext0 V0, ExtIndex), (ext1 V1, ExtIndex)602Value *VectorCombine::foldExtExtCmp(Value *V0, Value *V1, Value *ExtIndex,603 Instruction &I) {604 assert(isa<CmpInst>(&I) && "Expected a compare");605 606 // cmp Pred (extelt V0, ExtIndex), (extelt V1, ExtIndex)607 // --> extelt (cmp Pred V0, V1), ExtIndex608 ++NumVecCmp;609 CmpInst::Predicate Pred = cast<CmpInst>(&I)->getPredicate();610 Value *VecCmp = Builder.CreateCmp(Pred, V0, V1);611 return Builder.CreateExtractElement(VecCmp, ExtIndex, "foldExtExtCmp");612}613 614/// Try to reduce extract element costs by converting scalar binops to vector615/// binops followed by extract.616/// bo (ext0 V0, ExtIndex), (ext1 V1, ExtIndex)617Value *VectorCombine::foldExtExtBinop(Value *V0, Value *V1, Value *ExtIndex,618 Instruction &I) {619 assert(isa<BinaryOperator>(&I) && "Expected a binary operator");620 621 // bo (extelt V0, ExtIndex), (extelt V1, ExtIndex)622 // --> extelt (bo V0, V1), ExtIndex623 ++NumVecBO;624 Value *VecBO = Builder.CreateBinOp(cast<BinaryOperator>(&I)->getOpcode(), V0,625 V1, "foldExtExtBinop");626 627 // All IR flags are safe to back-propagate because any potential poison628 // created in unused vector elements is discarded by the extract.629 if (auto *VecBOInst = dyn_cast<Instruction>(VecBO))630 VecBOInst->copyIRFlags(&I);631 632 return Builder.CreateExtractElement(VecBO, ExtIndex, "foldExtExtBinop");633}634 635/// Match an instruction with extracted vector operands.636bool VectorCombine::foldExtractExtract(Instruction &I) {637 // It is not safe to transform things like div, urem, etc. because we may638 // create undefined behavior when executing those on unknown vector elements.639 if (!isSafeToSpeculativelyExecute(&I))640 return false;641 642 Instruction *I0, *I1;643 CmpPredicate Pred = CmpInst::BAD_ICMP_PREDICATE;644 if (!match(&I, m_Cmp(Pred, m_Instruction(I0), m_Instruction(I1))) &&645 !match(&I, m_BinOp(m_Instruction(I0), m_Instruction(I1))))646 return false;647 648 Value *V0, *V1;649 uint64_t C0, C1;650 if (!match(I0, m_ExtractElt(m_Value(V0), m_ConstantInt(C0))) ||651 !match(I1, m_ExtractElt(m_Value(V1), m_ConstantInt(C1))) ||652 V0->getType() != V1->getType())653 return false;654 655 // If the scalar value 'I' is going to be re-inserted into a vector, then try656 // to create an extract to that same element. The extract/insert can be657 // reduced to a "select shuffle".658 // TODO: If we add a larger pattern match that starts from an insert, this659 // probably becomes unnecessary.660 auto *Ext0 = cast<ExtractElementInst>(I0);661 auto *Ext1 = cast<ExtractElementInst>(I1);662 uint64_t InsertIndex = InvalidIndex;663 if (I.hasOneUse())664 match(I.user_back(),665 m_InsertElt(m_Value(), m_Value(), m_ConstantInt(InsertIndex)));666 667 ExtractElementInst *ExtractToChange;668 if (isExtractExtractCheap(Ext0, Ext1, I, ExtractToChange, InsertIndex))669 return false;670 671 Value *ExtOp0 = Ext0->getVectorOperand();672 Value *ExtOp1 = Ext1->getVectorOperand();673 674 if (ExtractToChange) {675 unsigned CheapExtractIdx = ExtractToChange == Ext0 ? C1 : C0;676 Value *NewExtOp =677 translateExtract(ExtractToChange, CheapExtractIdx, Builder);678 if (!NewExtOp)679 return false;680 if (ExtractToChange == Ext0)681 ExtOp0 = NewExtOp;682 else683 ExtOp1 = NewExtOp;684 }685 686 Value *ExtIndex = ExtractToChange == Ext0 ? Ext1->getIndexOperand()687 : Ext0->getIndexOperand();688 Value *NewExt = Pred != CmpInst::BAD_ICMP_PREDICATE689 ? foldExtExtCmp(ExtOp0, ExtOp1, ExtIndex, I)690 : foldExtExtBinop(ExtOp0, ExtOp1, ExtIndex, I);691 Worklist.push(Ext0);692 Worklist.push(Ext1);693 replaceValue(I, *NewExt);694 return true;695}696 697/// Try to replace an extract + scalar fneg + insert with a vector fneg +698/// shuffle.699bool VectorCombine::foldInsExtFNeg(Instruction &I) {700 // Match an insert (op (extract)) pattern.701 Value *DstVec;702 uint64_t ExtIdx, InsIdx;703 Instruction *FNeg;704 if (!match(&I, m_InsertElt(m_Value(DstVec), m_OneUse(m_Instruction(FNeg)),705 m_ConstantInt(InsIdx))))706 return false;707 708 // Note: This handles the canonical fneg instruction and "fsub -0.0, X".709 Value *SrcVec;710 Instruction *Extract;711 if (!match(FNeg, m_FNeg(m_CombineAnd(712 m_Instruction(Extract),713 m_ExtractElt(m_Value(SrcVec), m_ConstantInt(ExtIdx))))))714 return false;715 716 auto *DstVecTy = cast<FixedVectorType>(DstVec->getType());717 auto *DstVecScalarTy = DstVecTy->getScalarType();718 auto *SrcVecTy = dyn_cast<FixedVectorType>(SrcVec->getType());719 if (!SrcVecTy || DstVecScalarTy != SrcVecTy->getScalarType())720 return false;721 722 // Ignore if insert/extract index is out of bounds or destination vector has723 // one element724 unsigned NumDstElts = DstVecTy->getNumElements();725 unsigned NumSrcElts = SrcVecTy->getNumElements();726 if (ExtIdx > NumSrcElts || InsIdx >= NumDstElts || NumDstElts == 1)727 return false;728 729 // We are inserting the negated element into the same lane that we extracted730 // from. This is equivalent to a select-shuffle that chooses all but the731 // negated element from the destination vector.732 SmallVector<int> Mask(NumDstElts);733 std::iota(Mask.begin(), Mask.end(), 0);734 Mask[InsIdx] = (ExtIdx % NumDstElts) + NumDstElts;735 InstructionCost OldCost =736 TTI.getArithmeticInstrCost(Instruction::FNeg, DstVecScalarTy, CostKind) +737 TTI.getVectorInstrCost(I, DstVecTy, CostKind, InsIdx);738 739 // If the extract has one use, it will be eliminated, so count it in the740 // original cost. If it has more than one use, ignore the cost because it will741 // be the same before/after.742 if (Extract->hasOneUse())743 OldCost += TTI.getVectorInstrCost(*Extract, SrcVecTy, CostKind, ExtIdx);744 745 InstructionCost NewCost =746 TTI.getArithmeticInstrCost(Instruction::FNeg, SrcVecTy, CostKind) +747 TTI.getShuffleCost(TargetTransformInfo::SK_PermuteTwoSrc, DstVecTy,748 DstVecTy, Mask, CostKind);749 750 bool NeedLenChg = SrcVecTy->getNumElements() != NumDstElts;751 // If the lengths of the two vectors are not equal,752 // we need to add a length-change vector. Add this cost.753 SmallVector<int> SrcMask;754 if (NeedLenChg) {755 SrcMask.assign(NumDstElts, PoisonMaskElem);756 SrcMask[ExtIdx % NumDstElts] = ExtIdx;757 NewCost += TTI.getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc,758 DstVecTy, SrcVecTy, SrcMask, CostKind);759 }760 761 LLVM_DEBUG(dbgs() << "Found an insertion of (extract)fneg : " << I762 << "\n OldCost: " << OldCost << " vs NewCost: " << NewCost763 << "\n");764 if (NewCost > OldCost)765 return false;766 767 Value *NewShuf, *LenChgShuf = nullptr;768 // insertelt DstVec, (fneg (extractelt SrcVec, Index)), Index769 Value *VecFNeg = Builder.CreateFNegFMF(SrcVec, FNeg);770 if (NeedLenChg) {771 // shuffle DstVec, (shuffle (fneg SrcVec), poison, SrcMask), Mask772 LenChgShuf = Builder.CreateShuffleVector(VecFNeg, SrcMask);773 NewShuf = Builder.CreateShuffleVector(DstVec, LenChgShuf, Mask);774 Worklist.pushValue(LenChgShuf);775 } else {776 // shuffle DstVec, (fneg SrcVec), Mask777 NewShuf = Builder.CreateShuffleVector(DstVec, VecFNeg, Mask);778 }779 780 Worklist.pushValue(VecFNeg);781 replaceValue(I, *NewShuf);782 return true;783}784 785/// Try to fold insert(binop(x,y),binop(a,b),idx)786/// --> binop(insert(x,a,idx),insert(y,b,idx))787bool VectorCombine::foldInsExtBinop(Instruction &I) {788 BinaryOperator *VecBinOp, *SclBinOp;789 uint64_t Index;790 if (!match(&I,791 m_InsertElt(m_OneUse(m_BinOp(VecBinOp)),792 m_OneUse(m_BinOp(SclBinOp)), m_ConstantInt(Index))))793 return false;794 795 // TODO: Add support for addlike etc.796 Instruction::BinaryOps BinOpcode = VecBinOp->getOpcode();797 if (BinOpcode != SclBinOp->getOpcode())798 return false;799 800 auto *ResultTy = dyn_cast<FixedVectorType>(I.getType());801 if (!ResultTy)802 return false;803 804 // TODO: Attempt to detect m_ExtractElt for scalar operands and convert to805 // shuffle?806 807 InstructionCost OldCost = TTI.getInstructionCost(&I, CostKind) +808 TTI.getInstructionCost(VecBinOp, CostKind) +809 TTI.getInstructionCost(SclBinOp, CostKind);810 InstructionCost NewCost =811 TTI.getArithmeticInstrCost(BinOpcode, ResultTy, CostKind) +812 TTI.getVectorInstrCost(Instruction::InsertElement, ResultTy, CostKind,813 Index, VecBinOp->getOperand(0),814 SclBinOp->getOperand(0)) +815 TTI.getVectorInstrCost(Instruction::InsertElement, ResultTy, CostKind,816 Index, VecBinOp->getOperand(1),817 SclBinOp->getOperand(1));818 819 LLVM_DEBUG(dbgs() << "Found an insertion of two binops: " << I820 << "\n OldCost: " << OldCost << " vs NewCost: " << NewCost821 << "\n");822 if (NewCost > OldCost)823 return false;824 825 Value *NewIns0 = Builder.CreateInsertElement(VecBinOp->getOperand(0),826 SclBinOp->getOperand(0), Index);827 Value *NewIns1 = Builder.CreateInsertElement(VecBinOp->getOperand(1),828 SclBinOp->getOperand(1), Index);829 Value *NewBO = Builder.CreateBinOp(BinOpcode, NewIns0, NewIns1);830 831 // Intersect flags from the old binops.832 if (auto *NewInst = dyn_cast<Instruction>(NewBO)) {833 NewInst->copyIRFlags(VecBinOp);834 NewInst->andIRFlags(SclBinOp);835 }836 837 Worklist.pushValue(NewIns0);838 Worklist.pushValue(NewIns1);839 replaceValue(I, *NewBO);840 return true;841}842 843/// Match: bitop(castop(x), castop(y)) -> castop(bitop(x, y))844/// Supports: bitcast, trunc, sext, zext845bool VectorCombine::foldBitOpOfCastops(Instruction &I) {846 // Check if this is a bitwise logic operation847 auto *BinOp = dyn_cast<BinaryOperator>(&I);848 if (!BinOp || !BinOp->isBitwiseLogicOp())849 return false;850 851 // Get the cast instructions852 auto *LHSCast = dyn_cast<CastInst>(BinOp->getOperand(0));853 auto *RHSCast = dyn_cast<CastInst>(BinOp->getOperand(1));854 if (!LHSCast || !RHSCast) {855 LLVM_DEBUG(dbgs() << " One or both operands are not cast instructions\n");856 return false;857 }858 859 // Both casts must be the same type860 Instruction::CastOps CastOpcode = LHSCast->getOpcode();861 if (CastOpcode != RHSCast->getOpcode())862 return false;863 864 // Only handle supported cast operations865 switch (CastOpcode) {866 case Instruction::BitCast:867 case Instruction::Trunc:868 case Instruction::SExt:869 case Instruction::ZExt:870 break;871 default:872 return false;873 }874 875 Value *LHSSrc = LHSCast->getOperand(0);876 Value *RHSSrc = RHSCast->getOperand(0);877 878 // Source types must match879 if (LHSSrc->getType() != RHSSrc->getType())880 return false;881 882 auto *SrcTy = LHSSrc->getType();883 auto *DstTy = I.getType();884 // Bitcasts can handle scalar/vector mixes, such as i16 -> <16 x i1>.885 // Other casts only handle vector types with integer elements.886 if (CastOpcode != Instruction::BitCast &&887 (!isa<FixedVectorType>(SrcTy) || !isa<FixedVectorType>(DstTy)))888 return false;889 890 // Only integer scalar/vector values are legal for bitwise logic operations.891 if (!SrcTy->getScalarType()->isIntegerTy() ||892 !DstTy->getScalarType()->isIntegerTy())893 return false;894 895 // Cost Check :896 // OldCost = bitlogic + 2*casts897 // NewCost = bitlogic + cast898 899 // Calculate specific costs for each cast with instruction context900 InstructionCost LHSCastCost = TTI.getCastInstrCost(901 CastOpcode, DstTy, SrcTy, TTI::CastContextHint::None, CostKind, LHSCast);902 InstructionCost RHSCastCost = TTI.getCastInstrCost(903 CastOpcode, DstTy, SrcTy, TTI::CastContextHint::None, CostKind, RHSCast);904 905 InstructionCost OldCost =906 TTI.getArithmeticInstrCost(BinOp->getOpcode(), DstTy, CostKind) +907 LHSCastCost + RHSCastCost;908 909 // For new cost, we can't provide an instruction (it doesn't exist yet)910 InstructionCost GenericCastCost = TTI.getCastInstrCost(911 CastOpcode, DstTy, SrcTy, TTI::CastContextHint::None, CostKind);912 913 InstructionCost NewCost =914 TTI.getArithmeticInstrCost(BinOp->getOpcode(), SrcTy, CostKind) +915 GenericCastCost;916 917 // Account for multi-use casts using specific costs918 if (!LHSCast->hasOneUse())919 NewCost += LHSCastCost;920 if (!RHSCast->hasOneUse())921 NewCost += RHSCastCost;922 923 LLVM_DEBUG(dbgs() << "foldBitOpOfCastops: OldCost=" << OldCost924 << " NewCost=" << NewCost << "\n");925 926 if (NewCost > OldCost)927 return false;928 929 // Create the operation on the source type930 Value *NewOp = Builder.CreateBinOp(BinOp->getOpcode(), LHSSrc, RHSSrc,931 BinOp->getName() + ".inner");932 if (auto *NewBinOp = dyn_cast<BinaryOperator>(NewOp))933 NewBinOp->copyIRFlags(BinOp);934 935 Worklist.pushValue(NewOp);936 937 // Create the cast operation directly to ensure we get a new instruction938 Instruction *NewCast = CastInst::Create(CastOpcode, NewOp, I.getType());939 940 // Preserve cast instruction flags941 NewCast->copyIRFlags(LHSCast);942 NewCast->andIRFlags(RHSCast);943 944 // Insert the new instruction945 Value *Result = Builder.Insert(NewCast);946 947 replaceValue(I, *Result);948 return true;949}950 951/// Match:952// bitop(castop(x), C) ->953// bitop(castop(x), castop(InvC)) ->954// castop(bitop(x, InvC))955// Supports: bitcast956bool VectorCombine::foldBitOpOfCastConstant(Instruction &I) {957 Instruction *LHS;958 Constant *C;959 960 // Check if this is a bitwise logic operation961 if (!match(&I, m_c_BitwiseLogic(m_Instruction(LHS), m_Constant(C))))962 return false;963 964 // Get the cast instructions965 auto *LHSCast = dyn_cast<CastInst>(LHS);966 if (!LHSCast)967 return false;968 969 Instruction::CastOps CastOpcode = LHSCast->getOpcode();970 971 // Only handle supported cast operations972 switch (CastOpcode) {973 case Instruction::BitCast:974 case Instruction::ZExt:975 case Instruction::SExt:976 case Instruction::Trunc:977 break;978 default:979 return false;980 }981 982 Value *LHSSrc = LHSCast->getOperand(0);983 984 auto *SrcTy = LHSSrc->getType();985 auto *DstTy = I.getType();986 // Bitcasts can handle scalar/vector mixes, such as i16 -> <16 x i1>.987 // Other casts only handle vector types with integer elements.988 if (CastOpcode != Instruction::BitCast &&989 (!isa<FixedVectorType>(SrcTy) || !isa<FixedVectorType>(DstTy)))990 return false;991 992 // Only integer scalar/vector values are legal for bitwise logic operations.993 if (!SrcTy->getScalarType()->isIntegerTy() ||994 !DstTy->getScalarType()->isIntegerTy())995 return false;996 997 // Find the constant InvC, such that castop(InvC) equals to C.998 PreservedCastFlags RHSFlags;999 Constant *InvC = getLosslessInvCast(C, SrcTy, CastOpcode, *DL, &RHSFlags);1000 if (!InvC)1001 return false;1002 1003 // Cost Check :1004 // OldCost = bitlogic + cast1005 // NewCost = bitlogic + cast1006 1007 // Calculate specific costs for each cast with instruction context1008 InstructionCost LHSCastCost = TTI.getCastInstrCost(1009 CastOpcode, DstTy, SrcTy, TTI::CastContextHint::None, CostKind, LHSCast);1010 1011 InstructionCost OldCost =1012 TTI.getArithmeticInstrCost(I.getOpcode(), DstTy, CostKind) + LHSCastCost;1013 1014 // For new cost, we can't provide an instruction (it doesn't exist yet)1015 InstructionCost GenericCastCost = TTI.getCastInstrCost(1016 CastOpcode, DstTy, SrcTy, TTI::CastContextHint::None, CostKind);1017 1018 InstructionCost NewCost =1019 TTI.getArithmeticInstrCost(I.getOpcode(), SrcTy, CostKind) +1020 GenericCastCost;1021 1022 // Account for multi-use casts using specific costs1023 if (!LHSCast->hasOneUse())1024 NewCost += LHSCastCost;1025 1026 LLVM_DEBUG(dbgs() << "foldBitOpOfCastConstant: OldCost=" << OldCost1027 << " NewCost=" << NewCost << "\n");1028 1029 if (NewCost > OldCost)1030 return false;1031 1032 // Create the operation on the source type1033 Value *NewOp = Builder.CreateBinOp((Instruction::BinaryOps)I.getOpcode(),1034 LHSSrc, InvC, I.getName() + ".inner");1035 if (auto *NewBinOp = dyn_cast<BinaryOperator>(NewOp))1036 NewBinOp->copyIRFlags(&I);1037 1038 Worklist.pushValue(NewOp);1039 1040 // Create the cast operation directly to ensure we get a new instruction1041 Instruction *NewCast = CastInst::Create(CastOpcode, NewOp, I.getType());1042 1043 // Preserve cast instruction flags1044 if (RHSFlags.NNeg)1045 NewCast->setNonNeg();1046 if (RHSFlags.NUW)1047 NewCast->setHasNoUnsignedWrap();1048 if (RHSFlags.NSW)1049 NewCast->setHasNoSignedWrap();1050 1051 NewCast->andIRFlags(LHSCast);1052 1053 // Insert the new instruction1054 Value *Result = Builder.Insert(NewCast);1055 1056 replaceValue(I, *Result);1057 return true;1058}1059 1060/// If this is a bitcast of a shuffle, try to bitcast the source vector to the1061/// destination type followed by shuffle. This can enable further transforms by1062/// moving bitcasts or shuffles together.1063bool VectorCombine::foldBitcastShuffle(Instruction &I) {1064 Value *V0, *V1;1065 ArrayRef<int> Mask;1066 if (!match(&I, m_BitCast(m_OneUse(1067 m_Shuffle(m_Value(V0), m_Value(V1), m_Mask(Mask))))))1068 return false;1069 1070 // 1) Do not fold bitcast shuffle for scalable type. First, shuffle cost for1071 // scalable type is unknown; Second, we cannot reason if the narrowed shuffle1072 // mask for scalable type is a splat or not.1073 // 2) Disallow non-vector casts.1074 // TODO: We could allow any shuffle.1075 auto *DestTy = dyn_cast<FixedVectorType>(I.getType());1076 auto *SrcTy = dyn_cast<FixedVectorType>(V0->getType());1077 if (!DestTy || !SrcTy)1078 return false;1079 1080 unsigned DestEltSize = DestTy->getScalarSizeInBits();1081 unsigned SrcEltSize = SrcTy->getScalarSizeInBits();1082 if (SrcTy->getPrimitiveSizeInBits() % DestEltSize != 0)1083 return false;1084 1085 bool IsUnary = isa<UndefValue>(V1);1086 1087 // For binary shuffles, only fold bitcast(shuffle(X,Y))1088 // if it won't increase the number of bitcasts.1089 if (!IsUnary) {1090 auto *BCTy0 = dyn_cast<FixedVectorType>(peekThroughBitcasts(V0)->getType());1091 auto *BCTy1 = dyn_cast<FixedVectorType>(peekThroughBitcasts(V1)->getType());1092 if (!(BCTy0 && BCTy0->getElementType() == DestTy->getElementType()) &&1093 !(BCTy1 && BCTy1->getElementType() == DestTy->getElementType()))1094 return false;1095 }1096 1097 SmallVector<int, 16> NewMask;1098 if (DestEltSize <= SrcEltSize) {1099 // The bitcast is from wide to narrow/equal elements. The shuffle mask can1100 // always be expanded to the equivalent form choosing narrower elements.1101 assert(SrcEltSize % DestEltSize == 0 && "Unexpected shuffle mask");1102 unsigned ScaleFactor = SrcEltSize / DestEltSize;1103 narrowShuffleMaskElts(ScaleFactor, Mask, NewMask);1104 } else {1105 // The bitcast is from narrow elements to wide elements. The shuffle mask1106 // must choose consecutive elements to allow casting first.1107 assert(DestEltSize % SrcEltSize == 0 && "Unexpected shuffle mask");1108 unsigned ScaleFactor = DestEltSize / SrcEltSize;1109 if (!widenShuffleMaskElts(ScaleFactor, Mask, NewMask))1110 return false;1111 }1112 1113 // Bitcast the shuffle src - keep its original width but using the destination1114 // scalar type.1115 unsigned NumSrcElts = SrcTy->getPrimitiveSizeInBits() / DestEltSize;1116 auto *NewShuffleTy =1117 FixedVectorType::get(DestTy->getScalarType(), NumSrcElts);1118 auto *OldShuffleTy =1119 FixedVectorType::get(SrcTy->getScalarType(), Mask.size());1120 unsigned NumOps = IsUnary ? 1 : 2;1121 1122 // The new shuffle must not cost more than the old shuffle.1123 TargetTransformInfo::ShuffleKind SK =1124 IsUnary ? TargetTransformInfo::SK_PermuteSingleSrc1125 : TargetTransformInfo::SK_PermuteTwoSrc;1126 1127 InstructionCost NewCost =1128 TTI.getShuffleCost(SK, DestTy, NewShuffleTy, NewMask, CostKind) +1129 (NumOps * TTI.getCastInstrCost(Instruction::BitCast, NewShuffleTy, SrcTy,1130 TargetTransformInfo::CastContextHint::None,1131 CostKind));1132 InstructionCost OldCost =1133 TTI.getShuffleCost(SK, OldShuffleTy, SrcTy, Mask, CostKind) +1134 TTI.getCastInstrCost(Instruction::BitCast, DestTy, OldShuffleTy,1135 TargetTransformInfo::CastContextHint::None,1136 CostKind);1137 1138 LLVM_DEBUG(dbgs() << "Found a bitcasted shuffle: " << I << "\n OldCost: "1139 << OldCost << " vs NewCost: " << NewCost << "\n");1140 1141 if (NewCost > OldCost || !NewCost.isValid())1142 return false;1143 1144 // bitcast (shuf V0, V1, MaskC) --> shuf (bitcast V0), (bitcast V1), MaskC'1145 ++NumShufOfBitcast;1146 Value *CastV0 = Builder.CreateBitCast(peekThroughBitcasts(V0), NewShuffleTy);1147 Value *CastV1 = Builder.CreateBitCast(peekThroughBitcasts(V1), NewShuffleTy);1148 Value *Shuf = Builder.CreateShuffleVector(CastV0, CastV1, NewMask);1149 replaceValue(I, *Shuf);1150 return true;1151}1152 1153/// VP Intrinsics whose vector operands are both splat values may be simplified1154/// into the scalar version of the operation and the result splatted. This1155/// can lead to scalarization down the line.1156bool VectorCombine::scalarizeVPIntrinsic(Instruction &I) {1157 if (!isa<VPIntrinsic>(I))1158 return false;1159 VPIntrinsic &VPI = cast<VPIntrinsic>(I);1160 Value *Op0 = VPI.getArgOperand(0);1161 Value *Op1 = VPI.getArgOperand(1);1162 1163 if (!isSplatValue(Op0) || !isSplatValue(Op1))1164 return false;1165 1166 // Check getSplatValue early in this function, to avoid doing unnecessary1167 // work.1168 Value *ScalarOp0 = getSplatValue(Op0);1169 Value *ScalarOp1 = getSplatValue(Op1);1170 if (!ScalarOp0 || !ScalarOp1)1171 return false;1172 1173 // For the binary VP intrinsics supported here, the result on disabled lanes1174 // is a poison value. For now, only do this simplification if all lanes1175 // are active.1176 // TODO: Relax the condition that all lanes are active by using insertelement1177 // on inactive lanes.1178 auto IsAllTrueMask = [](Value *MaskVal) {1179 if (Value *SplattedVal = getSplatValue(MaskVal))1180 if (auto *ConstValue = dyn_cast<Constant>(SplattedVal))1181 return ConstValue->isAllOnesValue();1182 return false;1183 };1184 if (!IsAllTrueMask(VPI.getArgOperand(2)))1185 return false;1186 1187 // Check to make sure we support scalarization of the intrinsic1188 Intrinsic::ID IntrID = VPI.getIntrinsicID();1189 if (!VPBinOpIntrinsic::isVPBinOp(IntrID))1190 return false;1191 1192 // Calculate cost of splatting both operands into vectors and the vector1193 // intrinsic1194 VectorType *VecTy = cast<VectorType>(VPI.getType());1195 SmallVector<int> Mask;1196 if (auto *FVTy = dyn_cast<FixedVectorType>(VecTy))1197 Mask.resize(FVTy->getNumElements(), 0);1198 InstructionCost SplatCost =1199 TTI.getVectorInstrCost(Instruction::InsertElement, VecTy, CostKind, 0) +1200 TTI.getShuffleCost(TargetTransformInfo::SK_Broadcast, VecTy, VecTy, Mask,1201 CostKind);1202 1203 // Calculate the cost of the VP Intrinsic1204 SmallVector<Type *, 4> Args;1205 for (Value *V : VPI.args())1206 Args.push_back(V->getType());1207 IntrinsicCostAttributes Attrs(IntrID, VecTy, Args);1208 InstructionCost VectorOpCost = TTI.getIntrinsicInstrCost(Attrs, CostKind);1209 InstructionCost OldCost = 2 * SplatCost + VectorOpCost;1210 1211 // Determine scalar opcode1212 std::optional<unsigned> FunctionalOpcode =1213 VPI.getFunctionalOpcode();1214 std::optional<Intrinsic::ID> ScalarIntrID = std::nullopt;1215 if (!FunctionalOpcode) {1216 ScalarIntrID = VPI.getFunctionalIntrinsicID();1217 if (!ScalarIntrID)1218 return false;1219 }1220 1221 // Calculate cost of scalarizing1222 InstructionCost ScalarOpCost = 0;1223 if (ScalarIntrID) {1224 IntrinsicCostAttributes Attrs(*ScalarIntrID, VecTy->getScalarType(), Args);1225 ScalarOpCost = TTI.getIntrinsicInstrCost(Attrs, CostKind);1226 } else {1227 ScalarOpCost = TTI.getArithmeticInstrCost(*FunctionalOpcode,1228 VecTy->getScalarType(), CostKind);1229 }1230 1231 // The existing splats may be kept around if other instructions use them.1232 InstructionCost CostToKeepSplats =1233 (SplatCost * !Op0->hasOneUse()) + (SplatCost * !Op1->hasOneUse());1234 InstructionCost NewCost = ScalarOpCost + SplatCost + CostToKeepSplats;1235 1236 LLVM_DEBUG(dbgs() << "Found a VP Intrinsic to scalarize: " << VPI1237 << "\n");1238 LLVM_DEBUG(dbgs() << "Cost of Intrinsic: " << OldCost1239 << ", Cost of scalarizing:" << NewCost << "\n");1240 1241 // We want to scalarize unless the vector variant actually has lower cost.1242 if (OldCost < NewCost || !NewCost.isValid())1243 return false;1244 1245 // Scalarize the intrinsic1246 ElementCount EC = cast<VectorType>(Op0->getType())->getElementCount();1247 Value *EVL = VPI.getArgOperand(3);1248 1249 // If the VP op might introduce UB or poison, we can scalarize it provided1250 // that we know the EVL > 0: If the EVL is zero, then the original VP op1251 // becomes a no-op and thus won't be UB, so make sure we don't introduce UB by1252 // scalarizing it.1253 bool SafeToSpeculate;1254 if (ScalarIntrID)1255 SafeToSpeculate = Intrinsic::getFnAttributes(I.getContext(), *ScalarIntrID)1256 .hasAttribute(Attribute::AttrKind::Speculatable);1257 else1258 SafeToSpeculate = isSafeToSpeculativelyExecuteWithOpcode(1259 *FunctionalOpcode, &VPI, nullptr, &AC, &DT);1260 if (!SafeToSpeculate &&1261 !isKnownNonZero(EVL, SimplifyQuery(*DL, &DT, &AC, &VPI)))1262 return false;1263 1264 Value *ScalarVal =1265 ScalarIntrID1266 ? Builder.CreateIntrinsic(VecTy->getScalarType(), *ScalarIntrID,1267 {ScalarOp0, ScalarOp1})1268 : Builder.CreateBinOp((Instruction::BinaryOps)(*FunctionalOpcode),1269 ScalarOp0, ScalarOp1);1270 1271 replaceValue(VPI, *Builder.CreateVectorSplat(EC, ScalarVal));1272 return true;1273}1274 1275/// Match a vector op/compare/intrinsic with at least one1276/// inserted scalar operand and convert to scalar op/cmp/intrinsic followed1277/// by insertelement.1278bool VectorCombine::scalarizeOpOrCmp(Instruction &I) {1279 auto *UO = dyn_cast<UnaryOperator>(&I);1280 auto *BO = dyn_cast<BinaryOperator>(&I);1281 auto *CI = dyn_cast<CmpInst>(&I);1282 auto *II = dyn_cast<IntrinsicInst>(&I);1283 if (!UO && !BO && !CI && !II)1284 return false;1285 1286 // TODO: Allow intrinsics with different argument types1287 if (II) {1288 if (!isTriviallyVectorizable(II->getIntrinsicID()))1289 return false;1290 for (auto [Idx, Arg] : enumerate(II->args()))1291 if (Arg->getType() != II->getType() &&1292 !isVectorIntrinsicWithScalarOpAtArg(II->getIntrinsicID(), Idx, &TTI))1293 return false;1294 }1295 1296 // Do not convert the vector condition of a vector select into a scalar1297 // condition. That may cause problems for codegen because of differences in1298 // boolean formats and register-file transfers.1299 // TODO: Can we account for that in the cost model?1300 if (CI)1301 for (User *U : I.users())1302 if (match(U, m_Select(m_Specific(&I), m_Value(), m_Value())))1303 return false;1304 1305 // Match constant vectors or scalars being inserted into constant vectors:1306 // vec_op [VecC0 | (inselt VecC0, V0, Index)], ...1307 SmallVector<Value *> VecCs, ScalarOps;1308 std::optional<uint64_t> Index;1309 1310 auto Ops = II ? II->args() : I.operands();1311 for (auto [OpNum, Op] : enumerate(Ops)) {1312 Constant *VecC;1313 Value *V;1314 uint64_t InsIdx = 0;1315 if (match(Op.get(), m_InsertElt(m_Constant(VecC), m_Value(V),1316 m_ConstantInt(InsIdx)))) {1317 // Bail if any inserts are out of bounds.1318 VectorType *OpTy = cast<VectorType>(Op->getType());1319 if (OpTy->getElementCount().getKnownMinValue() <= InsIdx)1320 return false;1321 // All inserts must have the same index.1322 // TODO: Deal with mismatched index constants and variable indexes?1323 if (!Index)1324 Index = InsIdx;1325 else if (InsIdx != *Index)1326 return false;1327 VecCs.push_back(VecC);1328 ScalarOps.push_back(V);1329 } else if (II && isVectorIntrinsicWithScalarOpAtArg(II->getIntrinsicID(),1330 OpNum, &TTI)) {1331 VecCs.push_back(Op.get());1332 ScalarOps.push_back(Op.get());1333 } else if (match(Op.get(), m_Constant(VecC))) {1334 VecCs.push_back(VecC);1335 ScalarOps.push_back(nullptr);1336 } else {1337 return false;1338 }1339 }1340 1341 // Bail if all operands are constant.1342 if (!Index.has_value())1343 return false;1344 1345 VectorType *VecTy = cast<VectorType>(I.getType());1346 Type *ScalarTy = VecTy->getScalarType();1347 assert(VecTy->isVectorTy() &&1348 (ScalarTy->isIntegerTy() || ScalarTy->isFloatingPointTy() ||1349 ScalarTy->isPointerTy()) &&1350 "Unexpected types for insert element into binop or cmp");1351 1352 unsigned Opcode = I.getOpcode();1353 InstructionCost ScalarOpCost, VectorOpCost;1354 if (CI) {1355 CmpInst::Predicate Pred = CI->getPredicate();1356 ScalarOpCost = TTI.getCmpSelInstrCost(1357 Opcode, ScalarTy, CmpInst::makeCmpResultType(ScalarTy), Pred, CostKind);1358 VectorOpCost = TTI.getCmpSelInstrCost(1359 Opcode, VecTy, CmpInst::makeCmpResultType(VecTy), Pred, CostKind);1360 } else if (UO || BO) {1361 ScalarOpCost = TTI.getArithmeticInstrCost(Opcode, ScalarTy, CostKind);1362 VectorOpCost = TTI.getArithmeticInstrCost(Opcode, VecTy, CostKind);1363 } else {1364 IntrinsicCostAttributes ScalarICA(1365 II->getIntrinsicID(), ScalarTy,1366 SmallVector<Type *>(II->arg_size(), ScalarTy));1367 ScalarOpCost = TTI.getIntrinsicInstrCost(ScalarICA, CostKind);1368 IntrinsicCostAttributes VectorICA(1369 II->getIntrinsicID(), VecTy,1370 SmallVector<Type *>(II->arg_size(), VecTy));1371 VectorOpCost = TTI.getIntrinsicInstrCost(VectorICA, CostKind);1372 }1373 1374 // Fold the vector constants in the original vectors into a new base vector to1375 // get more accurate cost modelling.1376 Value *NewVecC = nullptr;1377 if (CI)1378 NewVecC = simplifyCmpInst(CI->getPredicate(), VecCs[0], VecCs[1], SQ);1379 else if (UO)1380 NewVecC =1381 simplifyUnOp(UO->getOpcode(), VecCs[0], UO->getFastMathFlags(), SQ);1382 else if (BO)1383 NewVecC = simplifyBinOp(BO->getOpcode(), VecCs[0], VecCs[1], SQ);1384 else if (II)1385 NewVecC = simplifyCall(II, II->getCalledOperand(), VecCs, SQ);1386 1387 if (!NewVecC)1388 return false;1389 1390 // Get cost estimate for the insert element. This cost will factor into1391 // both sequences.1392 InstructionCost OldCost = VectorOpCost;1393 InstructionCost NewCost =1394 ScalarOpCost + TTI.getVectorInstrCost(Instruction::InsertElement, VecTy,1395 CostKind, *Index, NewVecC);1396 1397 for (auto [Idx, Op, VecC, Scalar] : enumerate(Ops, VecCs, ScalarOps)) {1398 if (!Scalar || (II && isVectorIntrinsicWithScalarOpAtArg(1399 II->getIntrinsicID(), Idx, &TTI)))1400 continue;1401 InstructionCost InsertCost = TTI.getVectorInstrCost(1402 Instruction::InsertElement, VecTy, CostKind, *Index, VecC, Scalar);1403 OldCost += InsertCost;1404 NewCost += !Op->hasOneUse() * InsertCost;1405 }1406 1407 // We want to scalarize unless the vector variant actually has lower cost.1408 if (OldCost < NewCost || !NewCost.isValid())1409 return false;1410 1411 // vec_op (inselt VecC0, V0, Index), (inselt VecC1, V1, Index) -->1412 // inselt NewVecC, (scalar_op V0, V1), Index1413 if (CI)1414 ++NumScalarCmp;1415 else if (UO || BO)1416 ++NumScalarOps;1417 else1418 ++NumScalarIntrinsic;1419 1420 // For constant cases, extract the scalar element, this should constant fold.1421 for (auto [OpIdx, Scalar, VecC] : enumerate(ScalarOps, VecCs))1422 if (!Scalar)1423 ScalarOps[OpIdx] = ConstantExpr::getExtractElement(1424 cast<Constant>(VecC), Builder.getInt64(*Index));1425 1426 Value *Scalar;1427 if (CI)1428 Scalar = Builder.CreateCmp(CI->getPredicate(), ScalarOps[0], ScalarOps[1]);1429 else if (UO || BO)1430 Scalar = Builder.CreateNAryOp(Opcode, ScalarOps);1431 else1432 Scalar = Builder.CreateIntrinsic(ScalarTy, II->getIntrinsicID(), ScalarOps);1433 1434 Scalar->setName(I.getName() + ".scalar");1435 1436 // All IR flags are safe to back-propagate. There is no potential for extra1437 // poison to be created by the scalar instruction.1438 if (auto *ScalarInst = dyn_cast<Instruction>(Scalar))1439 ScalarInst->copyIRFlags(&I);1440 1441 Value *Insert = Builder.CreateInsertElement(NewVecC, Scalar, *Index);1442 replaceValue(I, *Insert);1443 return true;1444}1445 1446/// Try to combine a scalar binop + 2 scalar compares of extracted elements of1447/// a vector into vector operations followed by extract. Note: The SLP pass1448/// may miss this pattern because of implementation problems.1449bool VectorCombine::foldExtractedCmps(Instruction &I) {1450 auto *BI = dyn_cast<BinaryOperator>(&I);1451 1452 // We are looking for a scalar binop of booleans.1453 // binop i1 (cmp Pred I0, C0), (cmp Pred I1, C1)1454 if (!BI || !I.getType()->isIntegerTy(1))1455 return false;1456 1457 // The compare predicates should match, and each compare should have a1458 // constant operand.1459 Value *B0 = I.getOperand(0), *B1 = I.getOperand(1);1460 Instruction *I0, *I1;1461 Constant *C0, *C1;1462 CmpPredicate P0, P1;1463 if (!match(B0, m_Cmp(P0, m_Instruction(I0), m_Constant(C0))) ||1464 !match(B1, m_Cmp(P1, m_Instruction(I1), m_Constant(C1))))1465 return false;1466 1467 auto MatchingPred = CmpPredicate::getMatching(P0, P1);1468 if (!MatchingPred)1469 return false;1470 1471 // The compare operands must be extracts of the same vector with constant1472 // extract indexes.1473 Value *X;1474 uint64_t Index0, Index1;1475 if (!match(I0, m_ExtractElt(m_Value(X), m_ConstantInt(Index0))) ||1476 !match(I1, m_ExtractElt(m_Specific(X), m_ConstantInt(Index1))))1477 return false;1478 1479 auto *Ext0 = cast<ExtractElementInst>(I0);1480 auto *Ext1 = cast<ExtractElementInst>(I1);1481 ExtractElementInst *ConvertToShuf = getShuffleExtract(Ext0, Ext1, CostKind);1482 if (!ConvertToShuf)1483 return false;1484 assert((ConvertToShuf == Ext0 || ConvertToShuf == Ext1) &&1485 "Unknown ExtractElementInst");1486 1487 // The original scalar pattern is:1488 // binop i1 (cmp Pred (ext X, Index0), C0), (cmp Pred (ext X, Index1), C1)1489 CmpInst::Predicate Pred = *MatchingPred;1490 unsigned CmpOpcode =1491 CmpInst::isFPPredicate(Pred) ? Instruction::FCmp : Instruction::ICmp;1492 auto *VecTy = dyn_cast<FixedVectorType>(X->getType());1493 if (!VecTy)1494 return false;1495 1496 InstructionCost Ext0Cost =1497 TTI.getVectorInstrCost(*Ext0, VecTy, CostKind, Index0);1498 InstructionCost Ext1Cost =1499 TTI.getVectorInstrCost(*Ext1, VecTy, CostKind, Index1);1500 InstructionCost CmpCost = TTI.getCmpSelInstrCost(1501 CmpOpcode, I0->getType(), CmpInst::makeCmpResultType(I0->getType()), Pred,1502 CostKind);1503 1504 InstructionCost OldCost =1505 Ext0Cost + Ext1Cost + CmpCost * 2 +1506 TTI.getArithmeticInstrCost(I.getOpcode(), I.getType(), CostKind);1507 1508 // The proposed vector pattern is:1509 // vcmp = cmp Pred X, VecC1510 // ext (binop vNi1 vcmp, (shuffle vcmp, Index1)), Index01511 int CheapIndex = ConvertToShuf == Ext0 ? Index1 : Index0;1512 int ExpensiveIndex = ConvertToShuf == Ext0 ? Index0 : Index1;1513 auto *CmpTy = cast<FixedVectorType>(CmpInst::makeCmpResultType(VecTy));1514 InstructionCost NewCost = TTI.getCmpSelInstrCost(1515 CmpOpcode, VecTy, CmpInst::makeCmpResultType(VecTy), Pred, CostKind);1516 SmallVector<int, 32> ShufMask(VecTy->getNumElements(), PoisonMaskElem);1517 ShufMask[CheapIndex] = ExpensiveIndex;1518 NewCost += TTI.getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc, CmpTy,1519 CmpTy, ShufMask, CostKind);1520 NewCost += TTI.getArithmeticInstrCost(I.getOpcode(), CmpTy, CostKind);1521 NewCost += TTI.getVectorInstrCost(*Ext0, CmpTy, CostKind, CheapIndex);1522 NewCost += Ext0->hasOneUse() ? 0 : Ext0Cost;1523 NewCost += Ext1->hasOneUse() ? 0 : Ext1Cost;1524 1525 // Aggressively form vector ops if the cost is equal because the transform1526 // may enable further optimization.1527 // Codegen can reverse this transform (scalarize) if it was not profitable.1528 if (OldCost < NewCost || !NewCost.isValid())1529 return false;1530 1531 // Create a vector constant from the 2 scalar constants.1532 SmallVector<Constant *, 32> CmpC(VecTy->getNumElements(),1533 PoisonValue::get(VecTy->getElementType()));1534 CmpC[Index0] = C0;1535 CmpC[Index1] = C1;1536 Value *VCmp = Builder.CreateCmp(Pred, X, ConstantVector::get(CmpC));1537 Value *Shuf = createShiftShuffle(VCmp, ExpensiveIndex, CheapIndex, Builder);1538 Value *LHS = ConvertToShuf == Ext0 ? Shuf : VCmp;1539 Value *RHS = ConvertToShuf == Ext0 ? VCmp : Shuf;1540 Value *VecLogic = Builder.CreateBinOp(BI->getOpcode(), LHS, RHS);1541 Value *NewExt = Builder.CreateExtractElement(VecLogic, CheapIndex);1542 replaceValue(I, *NewExt);1543 ++NumVecCmpBO;1544 return true;1545}1546 1547static void analyzeCostOfVecReduction(const IntrinsicInst &II,1548 TTI::TargetCostKind CostKind,1549 const TargetTransformInfo &TTI,1550 InstructionCost &CostBeforeReduction,1551 InstructionCost &CostAfterReduction) {1552 Instruction *Op0, *Op1;1553 auto *RedOp = dyn_cast<Instruction>(II.getOperand(0));1554 auto *VecRedTy = cast<VectorType>(II.getOperand(0)->getType());1555 unsigned ReductionOpc =1556 getArithmeticReductionInstruction(II.getIntrinsicID());1557 if (RedOp && match(RedOp, m_ZExtOrSExt(m_Value()))) {1558 bool IsUnsigned = isa<ZExtInst>(RedOp);1559 auto *ExtType = cast<VectorType>(RedOp->getOperand(0)->getType());1560 1561 CostBeforeReduction =1562 TTI.getCastInstrCost(RedOp->getOpcode(), VecRedTy, ExtType,1563 TTI::CastContextHint::None, CostKind, RedOp);1564 CostAfterReduction =1565 TTI.getExtendedReductionCost(ReductionOpc, IsUnsigned, II.getType(),1566 ExtType, FastMathFlags(), CostKind);1567 return;1568 }1569 if (RedOp && II.getIntrinsicID() == Intrinsic::vector_reduce_add &&1570 match(RedOp,1571 m_ZExtOrSExt(m_Mul(m_Instruction(Op0), m_Instruction(Op1)))) &&1572 match(Op0, m_ZExtOrSExt(m_Value())) &&1573 Op0->getOpcode() == Op1->getOpcode() &&1574 Op0->getOperand(0)->getType() == Op1->getOperand(0)->getType() &&1575 (Op0->getOpcode() == RedOp->getOpcode() || Op0 == Op1)) {1576 // Matched reduce.add(ext(mul(ext(A), ext(B)))1577 bool IsUnsigned = isa<ZExtInst>(Op0);1578 auto *ExtType = cast<VectorType>(Op0->getOperand(0)->getType());1579 VectorType *MulType = VectorType::get(Op0->getType(), VecRedTy);1580 1581 InstructionCost ExtCost =1582 TTI.getCastInstrCost(Op0->getOpcode(), MulType, ExtType,1583 TTI::CastContextHint::None, CostKind, Op0);1584 InstructionCost MulCost =1585 TTI.getArithmeticInstrCost(Instruction::Mul, MulType, CostKind);1586 InstructionCost Ext2Cost =1587 TTI.getCastInstrCost(RedOp->getOpcode(), VecRedTy, MulType,1588 TTI::CastContextHint::None, CostKind, RedOp);1589 1590 CostBeforeReduction = ExtCost * 2 + MulCost + Ext2Cost;1591 CostAfterReduction = TTI.getMulAccReductionCost(1592 IsUnsigned, ReductionOpc, II.getType(), ExtType, CostKind);1593 return;1594 }1595 CostAfterReduction = TTI.getArithmeticReductionCost(ReductionOpc, VecRedTy,1596 std::nullopt, CostKind);1597}1598 1599bool VectorCombine::foldBinopOfReductions(Instruction &I) {1600 Instruction::BinaryOps BinOpOpc = cast<BinaryOperator>(&I)->getOpcode();1601 Intrinsic::ID ReductionIID = getReductionForBinop(BinOpOpc);1602 if (BinOpOpc == Instruction::Sub)1603 ReductionIID = Intrinsic::vector_reduce_add;1604 if (ReductionIID == Intrinsic::not_intrinsic)1605 return false;1606 1607 auto checkIntrinsicAndGetItsArgument = [](Value *V,1608 Intrinsic::ID IID) -> Value * {1609 auto *II = dyn_cast<IntrinsicInst>(V);1610 if (!II)1611 return nullptr;1612 if (II->getIntrinsicID() == IID && II->hasOneUse())1613 return II->getArgOperand(0);1614 return nullptr;1615 };1616 1617 Value *V0 = checkIntrinsicAndGetItsArgument(I.getOperand(0), ReductionIID);1618 if (!V0)1619 return false;1620 Value *V1 = checkIntrinsicAndGetItsArgument(I.getOperand(1), ReductionIID);1621 if (!V1)1622 return false;1623 1624 auto *VTy = cast<VectorType>(V0->getType());1625 if (V1->getType() != VTy)1626 return false;1627 const auto &II0 = *cast<IntrinsicInst>(I.getOperand(0));1628 const auto &II1 = *cast<IntrinsicInst>(I.getOperand(1));1629 unsigned ReductionOpc =1630 getArithmeticReductionInstruction(II0.getIntrinsicID());1631 1632 InstructionCost OldCost = 0;1633 InstructionCost NewCost = 0;1634 InstructionCost CostOfRedOperand0 = 0;1635 InstructionCost CostOfRed0 = 0;1636 InstructionCost CostOfRedOperand1 = 0;1637 InstructionCost CostOfRed1 = 0;1638 analyzeCostOfVecReduction(II0, CostKind, TTI, CostOfRedOperand0, CostOfRed0);1639 analyzeCostOfVecReduction(II1, CostKind, TTI, CostOfRedOperand1, CostOfRed1);1640 OldCost = CostOfRed0 + CostOfRed1 + TTI.getInstructionCost(&I, CostKind);1641 NewCost =1642 CostOfRedOperand0 + CostOfRedOperand1 +1643 TTI.getArithmeticInstrCost(BinOpOpc, VTy, CostKind) +1644 TTI.getArithmeticReductionCost(ReductionOpc, VTy, std::nullopt, CostKind);1645 if (NewCost >= OldCost || !NewCost.isValid())1646 return false;1647 1648 LLVM_DEBUG(dbgs() << "Found two mergeable reductions: " << I1649 << "\n OldCost: " << OldCost << " vs NewCost: " << NewCost1650 << "\n");1651 Value *VectorBO;1652 if (BinOpOpc == Instruction::Or)1653 VectorBO = Builder.CreateOr(V0, V1, "",1654 cast<PossiblyDisjointInst>(I).isDisjoint());1655 else1656 VectorBO = Builder.CreateBinOp(BinOpOpc, V0, V1);1657 1658 Instruction *Rdx = Builder.CreateIntrinsic(ReductionIID, {VTy}, {VectorBO});1659 replaceValue(I, *Rdx);1660 return true;1661}1662 1663// Check if memory loc modified between two instrs in the same BB1664static bool isMemModifiedBetween(BasicBlock::iterator Begin,1665 BasicBlock::iterator End,1666 const MemoryLocation &Loc, AAResults &AA) {1667 unsigned NumScanned = 0;1668 return std::any_of(Begin, End, [&](const Instruction &Instr) {1669 return isModSet(AA.getModRefInfo(&Instr, Loc)) ||1670 ++NumScanned > MaxInstrsToScan;1671 });1672}1673 1674namespace {1675/// Helper class to indicate whether a vector index can be safely scalarized and1676/// if a freeze needs to be inserted.1677class ScalarizationResult {1678 enum class StatusTy { Unsafe, Safe, SafeWithFreeze };1679 1680 StatusTy Status;1681 Value *ToFreeze;1682 1683 ScalarizationResult(StatusTy Status, Value *ToFreeze = nullptr)1684 : Status(Status), ToFreeze(ToFreeze) {}1685 1686public:1687 ScalarizationResult(const ScalarizationResult &Other) = default;1688 ~ScalarizationResult() {1689 assert(!ToFreeze && "freeze() not called with ToFreeze being set");1690 }1691 1692 static ScalarizationResult unsafe() { return {StatusTy::Unsafe}; }1693 static ScalarizationResult safe() { return {StatusTy::Safe}; }1694 static ScalarizationResult safeWithFreeze(Value *ToFreeze) {1695 return {StatusTy::SafeWithFreeze, ToFreeze};1696 }1697 1698 /// Returns true if the index can be scalarize without requiring a freeze.1699 bool isSafe() const { return Status == StatusTy::Safe; }1700 /// Returns true if the index cannot be scalarized.1701 bool isUnsafe() const { return Status == StatusTy::Unsafe; }1702 /// Returns true if the index can be scalarize, but requires inserting a1703 /// freeze.1704 bool isSafeWithFreeze() const { return Status == StatusTy::SafeWithFreeze; }1705 1706 /// Reset the state of Unsafe and clear ToFreze if set.1707 void discard() {1708 ToFreeze = nullptr;1709 Status = StatusTy::Unsafe;1710 }1711 1712 /// Freeze the ToFreeze and update the use in \p User to use it.1713 void freeze(IRBuilderBase &Builder, Instruction &UserI) {1714 assert(isSafeWithFreeze() &&1715 "should only be used when freezing is required");1716 assert(is_contained(ToFreeze->users(), &UserI) &&1717 "UserI must be a user of ToFreeze");1718 IRBuilder<>::InsertPointGuard Guard(Builder);1719 Builder.SetInsertPoint(cast<Instruction>(&UserI));1720 Value *Frozen =1721 Builder.CreateFreeze(ToFreeze, ToFreeze->getName() + ".frozen");1722 for (Use &U : make_early_inc_range((UserI.operands())))1723 if (U.get() == ToFreeze)1724 U.set(Frozen);1725 1726 ToFreeze = nullptr;1727 }1728};1729} // namespace1730 1731/// Check if it is legal to scalarize a memory access to \p VecTy at index \p1732/// Idx. \p Idx must access a valid vector element.1733static ScalarizationResult canScalarizeAccess(VectorType *VecTy, Value *Idx,1734 Instruction *CtxI,1735 AssumptionCache &AC,1736 const DominatorTree &DT) {1737 // We do checks for both fixed vector types and scalable vector types.1738 // This is the number of elements of fixed vector types,1739 // or the minimum number of elements of scalable vector types.1740 uint64_t NumElements = VecTy->getElementCount().getKnownMinValue();1741 unsigned IntWidth = Idx->getType()->getScalarSizeInBits();1742 1743 if (auto *C = dyn_cast<ConstantInt>(Idx)) {1744 if (C->getValue().ult(NumElements))1745 return ScalarizationResult::safe();1746 return ScalarizationResult::unsafe();1747 }1748 1749 // Always unsafe if the index type can't handle all inbound values.1750 if (!llvm::isUIntN(IntWidth, NumElements))1751 return ScalarizationResult::unsafe();1752 1753 APInt Zero(IntWidth, 0);1754 APInt MaxElts(IntWidth, NumElements);1755 ConstantRange ValidIndices(Zero, MaxElts);1756 ConstantRange IdxRange(IntWidth, true);1757 1758 if (isGuaranteedNotToBePoison(Idx, &AC)) {1759 if (ValidIndices.contains(computeConstantRange(Idx, /* ForSigned */ false,1760 true, &AC, CtxI, &DT)))1761 return ScalarizationResult::safe();1762 return ScalarizationResult::unsafe();1763 }1764 1765 // If the index may be poison, check if we can insert a freeze before the1766 // range of the index is restricted.1767 Value *IdxBase;1768 ConstantInt *CI;1769 if (match(Idx, m_And(m_Value(IdxBase), m_ConstantInt(CI)))) {1770 IdxRange = IdxRange.binaryAnd(CI->getValue());1771 } else if (match(Idx, m_URem(m_Value(IdxBase), m_ConstantInt(CI)))) {1772 IdxRange = IdxRange.urem(CI->getValue());1773 }1774 1775 if (ValidIndices.contains(IdxRange))1776 return ScalarizationResult::safeWithFreeze(IdxBase);1777 return ScalarizationResult::unsafe();1778}1779 1780/// The memory operation on a vector of \p ScalarType had alignment of1781/// \p VectorAlignment. Compute the maximal, but conservatively correct,1782/// alignment that will be valid for the memory operation on a single scalar1783/// element of the same type with index \p Idx.1784static Align computeAlignmentAfterScalarization(Align VectorAlignment,1785 Type *ScalarType, Value *Idx,1786 const DataLayout &DL) {1787 if (auto *C = dyn_cast<ConstantInt>(Idx))1788 return commonAlignment(VectorAlignment,1789 C->getZExtValue() * DL.getTypeStoreSize(ScalarType));1790 return commonAlignment(VectorAlignment, DL.getTypeStoreSize(ScalarType));1791}1792 1793// Combine patterns like:1794// %0 = load <4 x i32>, <4 x i32>* %a1795// %1 = insertelement <4 x i32> %0, i32 %b, i32 11796// store <4 x i32> %1, <4 x i32>* %a1797// to:1798// %0 = bitcast <4 x i32>* %a to i32*1799// %1 = getelementptr inbounds i32, i32* %0, i64 0, i64 11800// store i32 %b, i32* %11801bool VectorCombine::foldSingleElementStore(Instruction &I) {1802 if (!TTI.allowVectorElementIndexingUsingGEP())1803 return false;1804 auto *SI = cast<StoreInst>(&I);1805 if (!SI->isSimple() || !isa<VectorType>(SI->getValueOperand()->getType()))1806 return false;1807 1808 // TODO: Combine more complicated patterns (multiple insert) by referencing1809 // TargetTransformInfo.1810 Instruction *Source;1811 Value *NewElement;1812 Value *Idx;1813 if (!match(SI->getValueOperand(),1814 m_InsertElt(m_Instruction(Source), m_Value(NewElement),1815 m_Value(Idx))))1816 return false;1817 1818 if (auto *Load = dyn_cast<LoadInst>(Source)) {1819 auto VecTy = cast<VectorType>(SI->getValueOperand()->getType());1820 Value *SrcAddr = Load->getPointerOperand()->stripPointerCasts();1821 // Don't optimize for atomic/volatile load or store. Ensure memory is not1822 // modified between, vector type matches store size, and index is inbounds.1823 if (!Load->isSimple() || Load->getParent() != SI->getParent() ||1824 !DL->typeSizeEqualsStoreSize(Load->getType()->getScalarType()) ||1825 SrcAddr != SI->getPointerOperand()->stripPointerCasts())1826 return false;1827 1828 auto ScalarizableIdx = canScalarizeAccess(VecTy, Idx, Load, AC, DT);1829 if (ScalarizableIdx.isUnsafe() ||1830 isMemModifiedBetween(Load->getIterator(), SI->getIterator(),1831 MemoryLocation::get(SI), AA))1832 return false;1833 1834 // Ensure we add the load back to the worklist BEFORE its users so they can1835 // erased in the correct order.1836 Worklist.push(Load);1837 1838 if (ScalarizableIdx.isSafeWithFreeze())1839 ScalarizableIdx.freeze(Builder, *cast<Instruction>(Idx));1840 Value *GEP = Builder.CreateInBoundsGEP(1841 SI->getValueOperand()->getType(), SI->getPointerOperand(),1842 {ConstantInt::get(Idx->getType(), 0), Idx});1843 StoreInst *NSI = Builder.CreateStore(NewElement, GEP);1844 NSI->copyMetadata(*SI);1845 Align ScalarOpAlignment = computeAlignmentAfterScalarization(1846 std::max(SI->getAlign(), Load->getAlign()), NewElement->getType(), Idx,1847 *DL);1848 NSI->setAlignment(ScalarOpAlignment);1849 replaceValue(I, *NSI);1850 eraseInstruction(I);1851 return true;1852 }1853 1854 return false;1855}1856 1857/// Try to scalarize vector loads feeding extractelement or bitcast1858/// instructions.1859bool VectorCombine::scalarizeLoad(Instruction &I) {1860 Value *Ptr;1861 if (!match(&I, m_Load(m_Value(Ptr))))1862 return false;1863 1864 auto *LI = cast<LoadInst>(&I);1865 auto *VecTy = cast<VectorType>(LI->getType());1866 if (LI->isVolatile() || !DL->typeSizeEqualsStoreSize(VecTy->getScalarType()))1867 return false;1868 1869 bool AllExtracts = true;1870 bool AllBitcasts = true;1871 Instruction *LastCheckedInst = LI;1872 unsigned NumInstChecked = 0;1873 1874 // Check what type of users we have (must either all be extracts or1875 // bitcasts) and ensure no memory modifications between the load and1876 // its users.1877 for (User *U : LI->users()) {1878 auto *UI = dyn_cast<Instruction>(U);1879 if (!UI || UI->getParent() != LI->getParent())1880 return false;1881 1882 // If any user is waiting to be erased, then bail out as this will1883 // distort the cost calculation and possibly lead to infinite loops.1884 if (UI->use_empty())1885 return false;1886 1887 if (!isa<ExtractElementInst>(UI))1888 AllExtracts = false;1889 if (!isa<BitCastInst>(UI))1890 AllBitcasts = false;1891 1892 // Check if any instruction between the load and the user may modify memory.1893 if (LastCheckedInst->comesBefore(UI)) {1894 for (Instruction &I :1895 make_range(std::next(LI->getIterator()), UI->getIterator())) {1896 // Bail out if we reached the check limit or the instruction may write1897 // to memory.1898 if (NumInstChecked == MaxInstrsToScan || I.mayWriteToMemory())1899 return false;1900 NumInstChecked++;1901 }1902 LastCheckedInst = UI;1903 }1904 }1905 1906 if (AllExtracts)1907 return scalarizeLoadExtract(LI, VecTy, Ptr);1908 if (AllBitcasts)1909 return scalarizeLoadBitcast(LI, VecTy, Ptr);1910 return false;1911}1912 1913/// Try to scalarize vector loads feeding extractelement instructions.1914bool VectorCombine::scalarizeLoadExtract(LoadInst *LI, VectorType *VecTy,1915 Value *Ptr) {1916 if (!TTI.allowVectorElementIndexingUsingGEP())1917 return false;1918 1919 DenseMap<ExtractElementInst *, ScalarizationResult> NeedFreeze;1920 auto FailureGuard = make_scope_exit([&]() {1921 // If the transform is aborted, discard the ScalarizationResults.1922 for (auto &Pair : NeedFreeze)1923 Pair.second.discard();1924 });1925 1926 InstructionCost OriginalCost =1927 TTI.getMemoryOpCost(Instruction::Load, VecTy, LI->getAlign(),1928 LI->getPointerAddressSpace(), CostKind);1929 InstructionCost ScalarizedCost = 0;1930 1931 for (User *U : LI->users()) {1932 auto *UI = cast<ExtractElementInst>(U);1933 1934 auto ScalarIdx =1935 canScalarizeAccess(VecTy, UI->getIndexOperand(), LI, AC, DT);1936 if (ScalarIdx.isUnsafe())1937 return false;1938 if (ScalarIdx.isSafeWithFreeze()) {1939 NeedFreeze.try_emplace(UI, ScalarIdx);1940 ScalarIdx.discard();1941 }1942 1943 auto *Index = dyn_cast<ConstantInt>(UI->getIndexOperand());1944 OriginalCost +=1945 TTI.getVectorInstrCost(Instruction::ExtractElement, VecTy, CostKind,1946 Index ? Index->getZExtValue() : -1);1947 ScalarizedCost +=1948 TTI.getMemoryOpCost(Instruction::Load, VecTy->getElementType(),1949 Align(1), LI->getPointerAddressSpace(), CostKind);1950 ScalarizedCost += TTI.getAddressComputationCost(LI->getPointerOperandType(),1951 nullptr, nullptr, CostKind);1952 }1953 1954 LLVM_DEBUG(dbgs() << "Found all extractions of a vector load: " << *LI1955 << "\n LoadExtractCost: " << OriginalCost1956 << " vs ScalarizedCost: " << ScalarizedCost << "\n");1957 1958 if (ScalarizedCost >= OriginalCost)1959 return false;1960 1961 // Ensure we add the load back to the worklist BEFORE its users so they can1962 // erased in the correct order.1963 Worklist.push(LI);1964 1965 Type *ElemType = VecTy->getElementType();1966 1967 // Replace extracts with narrow scalar loads.1968 for (User *U : LI->users()) {1969 auto *EI = cast<ExtractElementInst>(U);1970 Value *Idx = EI->getIndexOperand();1971 1972 // Insert 'freeze' for poison indexes.1973 auto It = NeedFreeze.find(EI);1974 if (It != NeedFreeze.end())1975 It->second.freeze(Builder, *cast<Instruction>(Idx));1976 1977 Builder.SetInsertPoint(EI);1978 Value *GEP =1979 Builder.CreateInBoundsGEP(VecTy, Ptr, {Builder.getInt32(0), Idx});1980 auto *NewLoad = cast<LoadInst>(1981 Builder.CreateLoad(ElemType, GEP, EI->getName() + ".scalar"));1982 1983 Align ScalarOpAlignment =1984 computeAlignmentAfterScalarization(LI->getAlign(), ElemType, Idx, *DL);1985 NewLoad->setAlignment(ScalarOpAlignment);1986 1987 if (auto *ConstIdx = dyn_cast<ConstantInt>(Idx)) {1988 size_t Offset = ConstIdx->getZExtValue() * DL->getTypeStoreSize(ElemType);1989 AAMDNodes OldAAMD = LI->getAAMetadata();1990 NewLoad->setAAMetadata(OldAAMD.adjustForAccess(Offset, ElemType, *DL));1991 }1992 1993 replaceValue(*EI, *NewLoad, false);1994 }1995 1996 FailureGuard.release();1997 return true;1998}1999 2000/// Try to scalarize vector loads feeding bitcast instructions.2001bool VectorCombine::scalarizeLoadBitcast(LoadInst *LI, VectorType *VecTy,2002 Value *Ptr) {2003 InstructionCost OriginalCost =2004 TTI.getMemoryOpCost(Instruction::Load, VecTy, LI->getAlign(),2005 LI->getPointerAddressSpace(), CostKind);2006 2007 Type *TargetScalarType = nullptr;2008 unsigned VecBitWidth = DL->getTypeSizeInBits(VecTy);2009 2010 for (User *U : LI->users()) {2011 auto *BC = cast<BitCastInst>(U);2012 2013 Type *DestTy = BC->getDestTy();2014 if (!DestTy->isIntegerTy() && !DestTy->isFloatingPointTy())2015 return false;2016 2017 unsigned DestBitWidth = DL->getTypeSizeInBits(DestTy);2018 if (DestBitWidth != VecBitWidth)2019 return false;2020 2021 // All bitcasts must target the same scalar type.2022 if (!TargetScalarType)2023 TargetScalarType = DestTy;2024 else if (TargetScalarType != DestTy)2025 return false;2026 2027 OriginalCost +=2028 TTI.getCastInstrCost(Instruction::BitCast, TargetScalarType, VecTy,2029 TTI.getCastContextHint(BC), CostKind, BC);2030 }2031 2032 if (!TargetScalarType)2033 return false;2034 2035 assert(!LI->user_empty() && "Unexpected load without bitcast users");2036 InstructionCost ScalarizedCost =2037 TTI.getMemoryOpCost(Instruction::Load, TargetScalarType, LI->getAlign(),2038 LI->getPointerAddressSpace(), CostKind);2039 2040 LLVM_DEBUG(dbgs() << "Found vector load feeding only bitcasts: " << *LI2041 << "\n OriginalCost: " << OriginalCost2042 << " vs ScalarizedCost: " << ScalarizedCost << "\n");2043 2044 if (ScalarizedCost >= OriginalCost)2045 return false;2046 2047 // Ensure we add the load back to the worklist BEFORE its users so they can2048 // erased in the correct order.2049 Worklist.push(LI);2050 2051 Builder.SetInsertPoint(LI);2052 auto *ScalarLoad =2053 Builder.CreateLoad(TargetScalarType, Ptr, LI->getName() + ".scalar");2054 ScalarLoad->setAlignment(LI->getAlign());2055 ScalarLoad->copyMetadata(*LI);2056 2057 // Replace all bitcast users with the scalar load.2058 for (User *U : LI->users()) {2059 auto *BC = cast<BitCastInst>(U);2060 replaceValue(*BC, *ScalarLoad, false);2061 }2062 2063 return true;2064}2065 2066bool VectorCombine::scalarizeExtExtract(Instruction &I) {2067 if (!TTI.allowVectorElementIndexingUsingGEP())2068 return false;2069 auto *Ext = dyn_cast<ZExtInst>(&I);2070 if (!Ext)2071 return false;2072 2073 // Try to convert a vector zext feeding only extracts to a set of scalar2074 // (Src << ExtIdx *Size) & (Size -1)2075 // if profitable .2076 auto *SrcTy = dyn_cast<FixedVectorType>(Ext->getOperand(0)->getType());2077 if (!SrcTy)2078 return false;2079 auto *DstTy = cast<FixedVectorType>(Ext->getType());2080 2081 Type *ScalarDstTy = DstTy->getElementType();2082 if (DL->getTypeSizeInBits(SrcTy) != DL->getTypeSizeInBits(ScalarDstTy))2083 return false;2084 2085 InstructionCost VectorCost =2086 TTI.getCastInstrCost(Instruction::ZExt, DstTy, SrcTy,2087 TTI::CastContextHint::None, CostKind, Ext);2088 unsigned ExtCnt = 0;2089 bool ExtLane0 = false;2090 for (User *U : Ext->users()) {2091 uint64_t Idx;2092 if (!match(U, m_ExtractElt(m_Value(), m_ConstantInt(Idx))))2093 return false;2094 if (cast<Instruction>(U)->use_empty())2095 continue;2096 ExtCnt += 1;2097 ExtLane0 |= !Idx;2098 VectorCost += TTI.getVectorInstrCost(Instruction::ExtractElement, DstTy,2099 CostKind, Idx, U);2100 }2101 2102 InstructionCost ScalarCost =2103 ExtCnt * TTI.getArithmeticInstrCost(2104 Instruction::And, ScalarDstTy, CostKind,2105 {TTI::OK_AnyValue, TTI::OP_None},2106 {TTI::OK_NonUniformConstantValue, TTI::OP_None}) +2107 (ExtCnt - ExtLane0) *2108 TTI.getArithmeticInstrCost(2109 Instruction::LShr, ScalarDstTy, CostKind,2110 {TTI::OK_AnyValue, TTI::OP_None},2111 {TTI::OK_NonUniformConstantValue, TTI::OP_None});2112 if (ScalarCost > VectorCost)2113 return false;2114 2115 Value *ScalarV = Ext->getOperand(0);2116 if (!isGuaranteedNotToBePoison(ScalarV, &AC, dyn_cast<Instruction>(ScalarV),2117 &DT)) {2118 // Check wether all lanes are extracted, all extracts trigger UB2119 // on poison, and the last extract (and hence all previous ones)2120 // are guaranteed to execute if Ext executes. If so, we do not2121 // need to insert a freeze.2122 SmallDenseSet<ConstantInt *, 8> ExtractedLanes;2123 bool AllExtractsTriggerUB = true;2124 ExtractElementInst *LastExtract = nullptr;2125 BasicBlock *ExtBB = Ext->getParent();2126 for (User *U : Ext->users()) {2127 auto *Extract = cast<ExtractElementInst>(U);2128 if (Extract->getParent() != ExtBB || !programUndefinedIfPoison(Extract)) {2129 AllExtractsTriggerUB = false;2130 break;2131 }2132 ExtractedLanes.insert(cast<ConstantInt>(Extract->getIndexOperand()));2133 if (!LastExtract || LastExtract->comesBefore(Extract))2134 LastExtract = Extract;2135 }2136 if (ExtractedLanes.size() != DstTy->getNumElements() ||2137 !AllExtractsTriggerUB ||2138 !isGuaranteedToTransferExecutionToSuccessor(Ext->getIterator(),2139 LastExtract->getIterator()))2140 ScalarV = Builder.CreateFreeze(ScalarV);2141 }2142 ScalarV = Builder.CreateBitCast(2143 ScalarV,2144 IntegerType::get(SrcTy->getContext(), DL->getTypeSizeInBits(SrcTy)));2145 uint64_t SrcEltSizeInBits = DL->getTypeSizeInBits(SrcTy->getElementType());2146 uint64_t EltBitMask = (1ull << SrcEltSizeInBits) - 1;2147 uint64_t TotalBits = DL->getTypeSizeInBits(SrcTy);2148 Type *PackedTy = IntegerType::get(SrcTy->getContext(), TotalBits);2149 Value *Mask = ConstantInt::get(PackedTy, EltBitMask);2150 for (User *U : Ext->users()) {2151 auto *Extract = cast<ExtractElementInst>(U);2152 uint64_t Idx =2153 cast<ConstantInt>(Extract->getIndexOperand())->getZExtValue();2154 uint64_t ShiftAmt =2155 DL->isBigEndian()2156 ? (TotalBits - SrcEltSizeInBits - Idx * SrcEltSizeInBits)2157 : (Idx * SrcEltSizeInBits);2158 Value *LShr = Builder.CreateLShr(ScalarV, ShiftAmt);2159 Value *And = Builder.CreateAnd(LShr, Mask);2160 U->replaceAllUsesWith(And);2161 }2162 return true;2163}2164 2165/// Try to fold "(or (zext (bitcast X)), (shl (zext (bitcast Y)), C))"2166/// to "(bitcast (concat X, Y))"2167/// where X/Y are bitcasted from i1 mask vectors.2168bool VectorCombine::foldConcatOfBoolMasks(Instruction &I) {2169 Type *Ty = I.getType();2170 if (!Ty->isIntegerTy())2171 return false;2172 2173 // TODO: Add big endian test coverage2174 if (DL->isBigEndian())2175 return false;2176 2177 // Restrict to disjoint cases so the mask vectors aren't overlapping.2178 Instruction *X, *Y;2179 if (!match(&I, m_DisjointOr(m_Instruction(X), m_Instruction(Y))))2180 return false;2181 2182 // Allow both sources to contain shl, to handle more generic pattern:2183 // "(or (shl (zext (bitcast X)), C1), (shl (zext (bitcast Y)), C2))"2184 Value *SrcX;2185 uint64_t ShAmtX = 0;2186 if (!match(X, m_OneUse(m_ZExt(m_OneUse(m_BitCast(m_Value(SrcX)))))) &&2187 !match(X, m_OneUse(2188 m_Shl(m_OneUse(m_ZExt(m_OneUse(m_BitCast(m_Value(SrcX))))),2189 m_ConstantInt(ShAmtX)))))2190 return false;2191 2192 Value *SrcY;2193 uint64_t ShAmtY = 0;2194 if (!match(Y, m_OneUse(m_ZExt(m_OneUse(m_BitCast(m_Value(SrcY)))))) &&2195 !match(Y, m_OneUse(2196 m_Shl(m_OneUse(m_ZExt(m_OneUse(m_BitCast(m_Value(SrcY))))),2197 m_ConstantInt(ShAmtY)))))2198 return false;2199 2200 // Canonicalize larger shift to the RHS.2201 if (ShAmtX > ShAmtY) {2202 std::swap(X, Y);2203 std::swap(SrcX, SrcY);2204 std::swap(ShAmtX, ShAmtY);2205 }2206 2207 // Ensure both sources are matching vXi1 bool mask types, and that the shift2208 // difference is the mask width so they can be easily concatenated together.2209 uint64_t ShAmtDiff = ShAmtY - ShAmtX;2210 unsigned NumSHL = (ShAmtX > 0) + (ShAmtY > 0);2211 unsigned BitWidth = Ty->getPrimitiveSizeInBits();2212 auto *MaskTy = dyn_cast<FixedVectorType>(SrcX->getType());2213 if (!MaskTy || SrcX->getType() != SrcY->getType() ||2214 !MaskTy->getElementType()->isIntegerTy(1) ||2215 MaskTy->getNumElements() != ShAmtDiff ||2216 MaskTy->getNumElements() > (BitWidth / 2))2217 return false;2218 2219 auto *ConcatTy = FixedVectorType::getDoubleElementsVectorType(MaskTy);2220 auto *ConcatIntTy =2221 Type::getIntNTy(Ty->getContext(), ConcatTy->getNumElements());2222 auto *MaskIntTy = Type::getIntNTy(Ty->getContext(), ShAmtDiff);2223 2224 SmallVector<int, 32> ConcatMask(ConcatTy->getNumElements());2225 std::iota(ConcatMask.begin(), ConcatMask.end(), 0);2226 2227 // TODO: Is it worth supporting multi use cases?2228 InstructionCost OldCost = 0;2229 OldCost += TTI.getArithmeticInstrCost(Instruction::Or, Ty, CostKind);2230 OldCost +=2231 NumSHL * TTI.getArithmeticInstrCost(Instruction::Shl, Ty, CostKind);2232 OldCost += 2 * TTI.getCastInstrCost(Instruction::ZExt, Ty, MaskIntTy,2233 TTI::CastContextHint::None, CostKind);2234 OldCost += 2 * TTI.getCastInstrCost(Instruction::BitCast, MaskIntTy, MaskTy,2235 TTI::CastContextHint::None, CostKind);2236 2237 InstructionCost NewCost = 0;2238 NewCost += TTI.getShuffleCost(TargetTransformInfo::SK_PermuteTwoSrc, ConcatTy,2239 MaskTy, ConcatMask, CostKind);2240 NewCost += TTI.getCastInstrCost(Instruction::BitCast, ConcatIntTy, ConcatTy,2241 TTI::CastContextHint::None, CostKind);2242 if (Ty != ConcatIntTy)2243 NewCost += TTI.getCastInstrCost(Instruction::ZExt, Ty, ConcatIntTy,2244 TTI::CastContextHint::None, CostKind);2245 if (ShAmtX > 0)2246 NewCost += TTI.getArithmeticInstrCost(Instruction::Shl, Ty, CostKind);2247 2248 LLVM_DEBUG(dbgs() << "Found a concatenation of bitcasted bool masks: " << I2249 << "\n OldCost: " << OldCost << " vs NewCost: " << NewCost2250 << "\n");2251 2252 if (NewCost > OldCost)2253 return false;2254 2255 // Build bool mask concatenation, bitcast back to scalar integer, and perform2256 // any residual zero-extension or shifting.2257 Value *Concat = Builder.CreateShuffleVector(SrcX, SrcY, ConcatMask);2258 Worklist.pushValue(Concat);2259 2260 Value *Result = Builder.CreateBitCast(Concat, ConcatIntTy);2261 2262 if (Ty != ConcatIntTy) {2263 Worklist.pushValue(Result);2264 Result = Builder.CreateZExt(Result, Ty);2265 }2266 2267 if (ShAmtX > 0) {2268 Worklist.pushValue(Result);2269 Result = Builder.CreateShl(Result, ShAmtX);2270 }2271 2272 replaceValue(I, *Result);2273 return true;2274}2275 2276/// Try to convert "shuffle (binop (shuffle, shuffle)), undef"2277/// --> "binop (shuffle), (shuffle)".2278bool VectorCombine::foldPermuteOfBinops(Instruction &I) {2279 BinaryOperator *BinOp;2280 ArrayRef<int> OuterMask;2281 if (!match(&I,2282 m_Shuffle(m_OneUse(m_BinOp(BinOp)), m_Undef(), m_Mask(OuterMask))))2283 return false;2284 2285 // Don't introduce poison into div/rem.2286 if (BinOp->isIntDivRem() && llvm::is_contained(OuterMask, PoisonMaskElem))2287 return false;2288 2289 Value *Op00, *Op01, *Op10, *Op11;2290 ArrayRef<int> Mask0, Mask1;2291 bool Match0 =2292 match(BinOp->getOperand(0),2293 m_OneUse(m_Shuffle(m_Value(Op00), m_Value(Op01), m_Mask(Mask0))));2294 bool Match1 =2295 match(BinOp->getOperand(1),2296 m_OneUse(m_Shuffle(m_Value(Op10), m_Value(Op11), m_Mask(Mask1))));2297 if (!Match0 && !Match1)2298 return false;2299 2300 Op00 = Match0 ? Op00 : BinOp->getOperand(0);2301 Op01 = Match0 ? Op01 : BinOp->getOperand(0);2302 Op10 = Match1 ? Op10 : BinOp->getOperand(1);2303 Op11 = Match1 ? Op11 : BinOp->getOperand(1);2304 2305 Instruction::BinaryOps Opcode = BinOp->getOpcode();2306 auto *ShuffleDstTy = dyn_cast<FixedVectorType>(I.getType());2307 auto *BinOpTy = dyn_cast<FixedVectorType>(BinOp->getType());2308 auto *Op0Ty = dyn_cast<FixedVectorType>(Op00->getType());2309 auto *Op1Ty = dyn_cast<FixedVectorType>(Op10->getType());2310 if (!ShuffleDstTy || !BinOpTy || !Op0Ty || !Op1Ty)2311 return false;2312 2313 unsigned NumSrcElts = BinOpTy->getNumElements();2314 2315 // Don't accept shuffles that reference the second operand in2316 // div/rem or if its an undef arg.2317 if ((BinOp->isIntDivRem() || !isa<PoisonValue>(I.getOperand(1))) &&2318 any_of(OuterMask, [NumSrcElts](int M) { return M >= (int)NumSrcElts; }))2319 return false;2320 2321 // Merge outer / inner (or identity if no match) shuffles.2322 SmallVector<int> NewMask0, NewMask1;2323 for (int M : OuterMask) {2324 if (M < 0 || M >= (int)NumSrcElts) {2325 NewMask0.push_back(PoisonMaskElem);2326 NewMask1.push_back(PoisonMaskElem);2327 } else {2328 NewMask0.push_back(Match0 ? Mask0[M] : M);2329 NewMask1.push_back(Match1 ? Mask1[M] : M);2330 }2331 }2332 2333 unsigned NumOpElts = Op0Ty->getNumElements();2334 bool IsIdentity0 = ShuffleDstTy == Op0Ty &&2335 all_of(NewMask0, [NumOpElts](int M) { return M < (int)NumOpElts; }) &&2336 ShuffleVectorInst::isIdentityMask(NewMask0, NumOpElts);2337 bool IsIdentity1 = ShuffleDstTy == Op1Ty &&2338 all_of(NewMask1, [NumOpElts](int M) { return M < (int)NumOpElts; }) &&2339 ShuffleVectorInst::isIdentityMask(NewMask1, NumOpElts);2340 2341 // Try to merge shuffles across the binop if the new shuffles are not costly.2342 InstructionCost OldCost =2343 TTI.getArithmeticInstrCost(Opcode, BinOpTy, CostKind) +2344 TTI.getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc, ShuffleDstTy,2345 BinOpTy, OuterMask, CostKind, 0, nullptr, {BinOp}, &I);2346 if (Match0)2347 OldCost += TTI.getShuffleCost(2348 TargetTransformInfo::SK_PermuteTwoSrc, BinOpTy, Op0Ty, Mask0, CostKind,2349 0, nullptr, {Op00, Op01}, cast<Instruction>(BinOp->getOperand(0)));2350 if (Match1)2351 OldCost += TTI.getShuffleCost(2352 TargetTransformInfo::SK_PermuteTwoSrc, BinOpTy, Op1Ty, Mask1, CostKind,2353 0, nullptr, {Op10, Op11}, cast<Instruction>(BinOp->getOperand(1)));2354 2355 InstructionCost NewCost =2356 TTI.getArithmeticInstrCost(Opcode, ShuffleDstTy, CostKind);2357 2358 if (!IsIdentity0)2359 NewCost +=2360 TTI.getShuffleCost(TargetTransformInfo::SK_PermuteTwoSrc, ShuffleDstTy,2361 Op0Ty, NewMask0, CostKind, 0, nullptr, {Op00, Op01});2362 if (!IsIdentity1)2363 NewCost +=2364 TTI.getShuffleCost(TargetTransformInfo::SK_PermuteTwoSrc, ShuffleDstTy,2365 Op1Ty, NewMask1, CostKind, 0, nullptr, {Op10, Op11});2366 2367 LLVM_DEBUG(dbgs() << "Found a shuffle feeding a shuffled binop: " << I2368 << "\n OldCost: " << OldCost << " vs NewCost: " << NewCost2369 << "\n");2370 2371 // If costs are equal, still fold as we reduce instruction count.2372 if (NewCost > OldCost)2373 return false;2374 2375 Value *LHS =2376 IsIdentity0 ? Op00 : Builder.CreateShuffleVector(Op00, Op01, NewMask0);2377 Value *RHS =2378 IsIdentity1 ? Op10 : Builder.CreateShuffleVector(Op10, Op11, NewMask1);2379 Value *NewBO = Builder.CreateBinOp(Opcode, LHS, RHS);2380 2381 // Intersect flags from the old binops.2382 if (auto *NewInst = dyn_cast<Instruction>(NewBO))2383 NewInst->copyIRFlags(BinOp);2384 2385 Worklist.pushValue(LHS);2386 Worklist.pushValue(RHS);2387 replaceValue(I, *NewBO);2388 return true;2389}2390 2391/// Try to convert "shuffle (binop), (binop)" into "binop (shuffle), (shuffle)".2392/// Try to convert "shuffle (cmpop), (cmpop)" into "cmpop (shuffle), (shuffle)".2393bool VectorCombine::foldShuffleOfBinops(Instruction &I) {2394 ArrayRef<int> OldMask;2395 Instruction *LHS, *RHS;2396 if (!match(&I, m_Shuffle(m_OneUse(m_Instruction(LHS)),2397 m_OneUse(m_Instruction(RHS)), m_Mask(OldMask))))2398 return false;2399 2400 // TODO: Add support for addlike etc.2401 if (LHS->getOpcode() != RHS->getOpcode())2402 return false;2403 2404 Value *X, *Y, *Z, *W;2405 bool IsCommutative = false;2406 CmpPredicate PredLHS = CmpInst::BAD_ICMP_PREDICATE;2407 CmpPredicate PredRHS = CmpInst::BAD_ICMP_PREDICATE;2408 if (match(LHS, m_BinOp(m_Value(X), m_Value(Y))) &&2409 match(RHS, m_BinOp(m_Value(Z), m_Value(W)))) {2410 auto *BO = cast<BinaryOperator>(LHS);2411 // Don't introduce poison into div/rem.2412 if (llvm::is_contained(OldMask, PoisonMaskElem) && BO->isIntDivRem())2413 return false;2414 IsCommutative = BinaryOperator::isCommutative(BO->getOpcode());2415 } else if (match(LHS, m_Cmp(PredLHS, m_Value(X), m_Value(Y))) &&2416 match(RHS, m_Cmp(PredRHS, m_Value(Z), m_Value(W))) &&2417 (CmpInst::Predicate)PredLHS == (CmpInst::Predicate)PredRHS) {2418 IsCommutative = cast<CmpInst>(LHS)->isCommutative();2419 } else2420 return false;2421 2422 auto *ShuffleDstTy = dyn_cast<FixedVectorType>(I.getType());2423 auto *BinResTy = dyn_cast<FixedVectorType>(LHS->getType());2424 auto *BinOpTy = dyn_cast<FixedVectorType>(X->getType());2425 if (!ShuffleDstTy || !BinResTy || !BinOpTy || X->getType() != Z->getType())2426 return false;2427 2428 unsigned NumSrcElts = BinOpTy->getNumElements();2429 2430 // If we have something like "add X, Y" and "add Z, X", swap ops to match.2431 if (IsCommutative && X != Z && Y != W && (X == W || Y == Z))2432 std::swap(X, Y);2433 2434 auto ConvertToUnary = [NumSrcElts](int &M) {2435 if (M >= (int)NumSrcElts)2436 M -= NumSrcElts;2437 };2438 2439 SmallVector<int> NewMask0(OldMask);2440 TargetTransformInfo::ShuffleKind SK0 = TargetTransformInfo::SK_PermuteTwoSrc;2441 if (X == Z) {2442 llvm::for_each(NewMask0, ConvertToUnary);2443 SK0 = TargetTransformInfo::SK_PermuteSingleSrc;2444 Z = PoisonValue::get(BinOpTy);2445 }2446 2447 SmallVector<int> NewMask1(OldMask);2448 TargetTransformInfo::ShuffleKind SK1 = TargetTransformInfo::SK_PermuteTwoSrc;2449 if (Y == W) {2450 llvm::for_each(NewMask1, ConvertToUnary);2451 SK1 = TargetTransformInfo::SK_PermuteSingleSrc;2452 W = PoisonValue::get(BinOpTy);2453 }2454 2455 // Try to replace a binop with a shuffle if the shuffle is not costly.2456 InstructionCost OldCost =2457 TTI.getInstructionCost(LHS, CostKind) +2458 TTI.getInstructionCost(RHS, CostKind) +2459 TTI.getShuffleCost(TargetTransformInfo::SK_PermuteTwoSrc, ShuffleDstTy,2460 BinResTy, OldMask, CostKind, 0, nullptr, {LHS, RHS},2461 &I);2462 2463 // Handle shuffle(binop(shuffle(x),y),binop(z,shuffle(w))) style patterns2464 // where one use shuffles have gotten split across the binop/cmp. These2465 // often allow a major reduction in total cost that wouldn't happen as2466 // individual folds.2467 auto MergeInner = [&](Value *&Op, int Offset, MutableArrayRef<int> Mask,2468 TTI::TargetCostKind CostKind) -> bool {2469 Value *InnerOp;2470 ArrayRef<int> InnerMask;2471 if (match(Op, m_OneUse(m_Shuffle(m_Value(InnerOp), m_Undef(),2472 m_Mask(InnerMask)))) &&2473 InnerOp->getType() == Op->getType() &&2474 all_of(InnerMask,2475 [NumSrcElts](int M) { return M < (int)NumSrcElts; })) {2476 for (int &M : Mask)2477 if (Offset <= M && M < (int)(Offset + NumSrcElts)) {2478 M = InnerMask[M - Offset];2479 M = 0 <= M ? M + Offset : M;2480 }2481 OldCost += TTI.getInstructionCost(cast<Instruction>(Op), CostKind);2482 Op = InnerOp;2483 return true;2484 }2485 return false;2486 };2487 bool ReducedInstCount = false;2488 ReducedInstCount |= MergeInner(X, 0, NewMask0, CostKind);2489 ReducedInstCount |= MergeInner(Y, 0, NewMask1, CostKind);2490 ReducedInstCount |= MergeInner(Z, NumSrcElts, NewMask0, CostKind);2491 ReducedInstCount |= MergeInner(W, NumSrcElts, NewMask1, CostKind);2492 2493 auto *ShuffleCmpTy =2494 FixedVectorType::get(BinOpTy->getElementType(), ShuffleDstTy);2495 InstructionCost NewCost =2496 TTI.getShuffleCost(SK0, ShuffleCmpTy, BinOpTy, NewMask0, CostKind, 0,2497 nullptr, {X, Z}) +2498 TTI.getShuffleCost(SK1, ShuffleCmpTy, BinOpTy, NewMask1, CostKind, 0,2499 nullptr, {Y, W});2500 2501 if (PredLHS == CmpInst::BAD_ICMP_PREDICATE) {2502 NewCost +=2503 TTI.getArithmeticInstrCost(LHS->getOpcode(), ShuffleDstTy, CostKind);2504 } else {2505 NewCost += TTI.getCmpSelInstrCost(LHS->getOpcode(), ShuffleCmpTy,2506 ShuffleDstTy, PredLHS, CostKind);2507 }2508 2509 LLVM_DEBUG(dbgs() << "Found a shuffle feeding two binops: " << I2510 << "\n OldCost: " << OldCost << " vs NewCost: " << NewCost2511 << "\n");2512 2513 // If either shuffle will constant fold away, then fold for the same cost as2514 // we will reduce the instruction count.2515 ReducedInstCount |= (isa<Constant>(X) && isa<Constant>(Z)) ||2516 (isa<Constant>(Y) && isa<Constant>(W));2517 if (ReducedInstCount ? (NewCost > OldCost) : (NewCost >= OldCost))2518 return false;2519 2520 Value *Shuf0 = Builder.CreateShuffleVector(X, Z, NewMask0);2521 Value *Shuf1 = Builder.CreateShuffleVector(Y, W, NewMask1);2522 Value *NewBO = PredLHS == CmpInst::BAD_ICMP_PREDICATE2523 ? Builder.CreateBinOp(2524 cast<BinaryOperator>(LHS)->getOpcode(), Shuf0, Shuf1)2525 : Builder.CreateCmp(PredLHS, Shuf0, Shuf1);2526 2527 // Intersect flags from the old binops.2528 if (auto *NewInst = dyn_cast<Instruction>(NewBO)) {2529 NewInst->copyIRFlags(LHS);2530 NewInst->andIRFlags(RHS);2531 }2532 2533 Worklist.pushValue(Shuf0);2534 Worklist.pushValue(Shuf1);2535 replaceValue(I, *NewBO);2536 return true;2537}2538 2539/// Try to convert,2540/// (shuffle(select(c1,t1,f1)), (select(c2,t2,f2)), m) into2541/// (select (shuffle c1,c2,m), (shuffle t1,t2,m), (shuffle f1,f2,m))2542bool VectorCombine::foldShuffleOfSelects(Instruction &I) {2543 ArrayRef<int> Mask;2544 Value *C1, *T1, *F1, *C2, *T2, *F2;2545 if (!match(&I, m_Shuffle(2546 m_OneUse(m_Select(m_Value(C1), m_Value(T1), m_Value(F1))),2547 m_OneUse(m_Select(m_Value(C2), m_Value(T2), m_Value(F2))),2548 m_Mask(Mask))))2549 return false;2550 2551 auto *C1VecTy = dyn_cast<FixedVectorType>(C1->getType());2552 auto *C2VecTy = dyn_cast<FixedVectorType>(C2->getType());2553 if (!C1VecTy || !C2VecTy || C1VecTy != C2VecTy)2554 return false;2555 2556 auto *SI0FOp = dyn_cast<FPMathOperator>(I.getOperand(0));2557 auto *SI1FOp = dyn_cast<FPMathOperator>(I.getOperand(1));2558 // SelectInsts must have the same FMF.2559 if (((SI0FOp == nullptr) != (SI1FOp == nullptr)) ||2560 ((SI0FOp != nullptr) &&2561 (SI0FOp->getFastMathFlags() != SI1FOp->getFastMathFlags())))2562 return false;2563 2564 auto *SrcVecTy = cast<FixedVectorType>(T1->getType());2565 auto *DstVecTy = cast<FixedVectorType>(I.getType());2566 auto SK = TargetTransformInfo::SK_PermuteTwoSrc;2567 auto SelOp = Instruction::Select;2568 InstructionCost OldCost = TTI.getCmpSelInstrCost(2569 SelOp, SrcVecTy, C1VecTy, CmpInst::BAD_ICMP_PREDICATE, CostKind);2570 OldCost += TTI.getCmpSelInstrCost(SelOp, SrcVecTy, C2VecTy,2571 CmpInst::BAD_ICMP_PREDICATE, CostKind);2572 OldCost +=2573 TTI.getShuffleCost(SK, DstVecTy, SrcVecTy, Mask, CostKind, 0, nullptr,2574 {I.getOperand(0), I.getOperand(1)}, &I);2575 2576 InstructionCost NewCost = TTI.getShuffleCost(2577 SK, FixedVectorType::get(C1VecTy->getScalarType(), Mask.size()), C1VecTy,2578 Mask, CostKind, 0, nullptr, {C1, C2});2579 NewCost += TTI.getShuffleCost(SK, DstVecTy, SrcVecTy, Mask, CostKind, 0,2580 nullptr, {T1, T2});2581 NewCost += TTI.getShuffleCost(SK, DstVecTy, SrcVecTy, Mask, CostKind, 0,2582 nullptr, {F1, F2});2583 auto *C1C2ShuffledVecTy = cast<FixedVectorType>(2584 toVectorTy(Type::getInt1Ty(I.getContext()), DstVecTy->getNumElements()));2585 NewCost += TTI.getCmpSelInstrCost(SelOp, DstVecTy, C1C2ShuffledVecTy,2586 CmpInst::BAD_ICMP_PREDICATE, CostKind);2587 2588 LLVM_DEBUG(dbgs() << "Found a shuffle feeding two selects: " << I2589 << "\n OldCost: " << OldCost << " vs NewCost: " << NewCost2590 << "\n");2591 if (NewCost > OldCost)2592 return false;2593 2594 Value *ShuffleCmp = Builder.CreateShuffleVector(C1, C2, Mask);2595 Value *ShuffleTrue = Builder.CreateShuffleVector(T1, T2, Mask);2596 Value *ShuffleFalse = Builder.CreateShuffleVector(F1, F2, Mask);2597 Value *NewSel;2598 // We presuppose that the SelectInsts have the same FMF.2599 if (SI0FOp)2600 NewSel = Builder.CreateSelectFMF(ShuffleCmp, ShuffleTrue, ShuffleFalse,2601 SI0FOp->getFastMathFlags());2602 else2603 NewSel = Builder.CreateSelect(ShuffleCmp, ShuffleTrue, ShuffleFalse);2604 2605 Worklist.pushValue(ShuffleCmp);2606 Worklist.pushValue(ShuffleTrue);2607 Worklist.pushValue(ShuffleFalse);2608 replaceValue(I, *NewSel);2609 return true;2610}2611 2612/// Try to convert "shuffle (castop), (castop)" with a shared castop operand2613/// into "castop (shuffle)".2614bool VectorCombine::foldShuffleOfCastops(Instruction &I) {2615 Value *V0, *V1;2616 ArrayRef<int> OldMask;2617 if (!match(&I, m_Shuffle(m_Value(V0), m_Value(V1), m_Mask(OldMask))))2618 return false;2619 2620 // Check whether this is a binary shuffle.2621 bool IsBinaryShuffle = !isa<UndefValue>(V1);2622 2623 auto *C0 = dyn_cast<CastInst>(V0);2624 auto *C1 = dyn_cast<CastInst>(V1);2625 if (!C0 || (IsBinaryShuffle && !C1))2626 return false;2627 2628 Instruction::CastOps Opcode = C0->getOpcode();2629 2630 // If this is allowed, foldShuffleOfCastops can get stuck in a loop2631 // with foldBitcastOfShuffle. Reject in favor of foldBitcastOfShuffle.2632 if (!IsBinaryShuffle && Opcode == Instruction::BitCast)2633 return false;2634 2635 if (IsBinaryShuffle) {2636 if (C0->getSrcTy() != C1->getSrcTy())2637 return false;2638 // Handle shuffle(zext_nneg(x), sext(y)) -> sext(shuffle(x,y)) folds.2639 if (Opcode != C1->getOpcode()) {2640 if (match(C0, m_SExtLike(m_Value())) && match(C1, m_SExtLike(m_Value())))2641 Opcode = Instruction::SExt;2642 else2643 return false;2644 }2645 }2646 2647 auto *ShuffleDstTy = dyn_cast<FixedVectorType>(I.getType());2648 auto *CastDstTy = dyn_cast<FixedVectorType>(C0->getDestTy());2649 auto *CastSrcTy = dyn_cast<FixedVectorType>(C0->getSrcTy());2650 if (!ShuffleDstTy || !CastDstTy || !CastSrcTy)2651 return false;2652 2653 unsigned NumSrcElts = CastSrcTy->getNumElements();2654 unsigned NumDstElts = CastDstTy->getNumElements();2655 assert((NumDstElts == NumSrcElts || Opcode == Instruction::BitCast) &&2656 "Only bitcasts expected to alter src/dst element counts");2657 2658 // Check for bitcasting of unscalable vector types.2659 // e.g. <32 x i40> -> <40 x i32>2660 if (NumDstElts != NumSrcElts && (NumSrcElts % NumDstElts) != 0 &&2661 (NumDstElts % NumSrcElts) != 0)2662 return false;2663 2664 SmallVector<int, 16> NewMask;2665 if (NumSrcElts >= NumDstElts) {2666 // The bitcast is from wide to narrow/equal elements. The shuffle mask can2667 // always be expanded to the equivalent form choosing narrower elements.2668 assert(NumSrcElts % NumDstElts == 0 && "Unexpected shuffle mask");2669 unsigned ScaleFactor = NumSrcElts / NumDstElts;2670 narrowShuffleMaskElts(ScaleFactor, OldMask, NewMask);2671 } else {2672 // The bitcast is from narrow elements to wide elements. The shuffle mask2673 // must choose consecutive elements to allow casting first.2674 assert(NumDstElts % NumSrcElts == 0 && "Unexpected shuffle mask");2675 unsigned ScaleFactor = NumDstElts / NumSrcElts;2676 if (!widenShuffleMaskElts(ScaleFactor, OldMask, NewMask))2677 return false;2678 }2679 2680 auto *NewShuffleDstTy =2681 FixedVectorType::get(CastSrcTy->getScalarType(), NewMask.size());2682 2683 // Try to replace a castop with a shuffle if the shuffle is not costly.2684 InstructionCost CostC0 =2685 TTI.getCastInstrCost(C0->getOpcode(), CastDstTy, CastSrcTy,2686 TTI::CastContextHint::None, CostKind);2687 2688 TargetTransformInfo::ShuffleKind ShuffleKind;2689 if (IsBinaryShuffle)2690 ShuffleKind = TargetTransformInfo::SK_PermuteTwoSrc;2691 else2692 ShuffleKind = TargetTransformInfo::SK_PermuteSingleSrc;2693 2694 InstructionCost OldCost = CostC0;2695 OldCost += TTI.getShuffleCost(ShuffleKind, ShuffleDstTy, CastDstTy, OldMask,2696 CostKind, 0, nullptr, {}, &I);2697 2698 InstructionCost NewCost = TTI.getShuffleCost(ShuffleKind, NewShuffleDstTy,2699 CastSrcTy, NewMask, CostKind);2700 NewCost += TTI.getCastInstrCost(Opcode, ShuffleDstTy, NewShuffleDstTy,2701 TTI::CastContextHint::None, CostKind);2702 if (!C0->hasOneUse())2703 NewCost += CostC0;2704 if (IsBinaryShuffle) {2705 InstructionCost CostC1 =2706 TTI.getCastInstrCost(C1->getOpcode(), CastDstTy, CastSrcTy,2707 TTI::CastContextHint::None, CostKind);2708 OldCost += CostC1;2709 if (!C1->hasOneUse())2710 NewCost += CostC1;2711 }2712 2713 LLVM_DEBUG(dbgs() << "Found a shuffle feeding two casts: " << I2714 << "\n OldCost: " << OldCost << " vs NewCost: " << NewCost2715 << "\n");2716 if (NewCost > OldCost)2717 return false;2718 2719 Value *Shuf;2720 if (IsBinaryShuffle)2721 Shuf = Builder.CreateShuffleVector(C0->getOperand(0), C1->getOperand(0),2722 NewMask);2723 else2724 Shuf = Builder.CreateShuffleVector(C0->getOperand(0), NewMask);2725 2726 Value *Cast = Builder.CreateCast(Opcode, Shuf, ShuffleDstTy);2727 2728 // Intersect flags from the old casts.2729 if (auto *NewInst = dyn_cast<Instruction>(Cast)) {2730 NewInst->copyIRFlags(C0);2731 if (IsBinaryShuffle)2732 NewInst->andIRFlags(C1);2733 }2734 2735 Worklist.pushValue(Shuf);2736 replaceValue(I, *Cast);2737 return true;2738}2739 2740/// Try to convert any of:2741/// "shuffle (shuffle x, y), (shuffle y, x)"2742/// "shuffle (shuffle x, undef), (shuffle y, undef)"2743/// "shuffle (shuffle x, undef), y"2744/// "shuffle x, (shuffle y, undef)"2745/// into "shuffle x, y".2746bool VectorCombine::foldShuffleOfShuffles(Instruction &I) {2747 ArrayRef<int> OuterMask;2748 Value *OuterV0, *OuterV1;2749 if (!match(&I,2750 m_Shuffle(m_Value(OuterV0), m_Value(OuterV1), m_Mask(OuterMask))))2751 return false;2752 2753 ArrayRef<int> InnerMask0, InnerMask1;2754 Value *X0, *X1, *Y0, *Y1;2755 bool Match0 =2756 match(OuterV0, m_Shuffle(m_Value(X0), m_Value(Y0), m_Mask(InnerMask0)));2757 bool Match1 =2758 match(OuterV1, m_Shuffle(m_Value(X1), m_Value(Y1), m_Mask(InnerMask1)));2759 if (!Match0 && !Match1)2760 return false;2761 2762 // If the outer shuffle is a permute, then create a fake inner all-poison2763 // shuffle. This is easier than accounting for length-changing shuffles below.2764 SmallVector<int, 16> PoisonMask1;2765 if (!Match1 && isa<PoisonValue>(OuterV1)) {2766 X1 = X0;2767 Y1 = Y0;2768 PoisonMask1.append(InnerMask0.size(), PoisonMaskElem);2769 InnerMask1 = PoisonMask1;2770 Match1 = true; // fake match2771 }2772 2773 X0 = Match0 ? X0 : OuterV0;2774 Y0 = Match0 ? Y0 : OuterV0;2775 X1 = Match1 ? X1 : OuterV1;2776 Y1 = Match1 ? Y1 : OuterV1;2777 auto *ShuffleDstTy = dyn_cast<FixedVectorType>(I.getType());2778 auto *ShuffleSrcTy = dyn_cast<FixedVectorType>(X0->getType());2779 auto *ShuffleImmTy = dyn_cast<FixedVectorType>(OuterV0->getType());2780 if (!ShuffleDstTy || !ShuffleSrcTy || !ShuffleImmTy ||2781 X0->getType() != X1->getType())2782 return false;2783 2784 unsigned NumSrcElts = ShuffleSrcTy->getNumElements();2785 unsigned NumImmElts = ShuffleImmTy->getNumElements();2786 2787 // Attempt to merge shuffles, matching upto 2 source operands.2788 // Replace index to a poison arg with PoisonMaskElem.2789 // Bail if either inner masks reference an undef arg.2790 SmallVector<int, 16> NewMask(OuterMask);2791 Value *NewX = nullptr, *NewY = nullptr;2792 for (int &M : NewMask) {2793 Value *Src = nullptr;2794 if (0 <= M && M < (int)NumImmElts) {2795 Src = OuterV0;2796 if (Match0) {2797 M = InnerMask0[M];2798 Src = M >= (int)NumSrcElts ? Y0 : X0;2799 M = M >= (int)NumSrcElts ? (M - NumSrcElts) : M;2800 }2801 } else if (M >= (int)NumImmElts) {2802 Src = OuterV1;2803 M -= NumImmElts;2804 if (Match1) {2805 M = InnerMask1[M];2806 Src = M >= (int)NumSrcElts ? Y1 : X1;2807 M = M >= (int)NumSrcElts ? (M - NumSrcElts) : M;2808 }2809 }2810 if (Src && M != PoisonMaskElem) {2811 assert(0 <= M && M < (int)NumSrcElts && "Unexpected shuffle mask index");2812 if (isa<UndefValue>(Src)) {2813 // We've referenced an undef element - if its poison, update the shuffle2814 // mask, else bail.2815 if (!isa<PoisonValue>(Src))2816 return false;2817 M = PoisonMaskElem;2818 continue;2819 }2820 if (!NewX || NewX == Src) {2821 NewX = Src;2822 continue;2823 }2824 if (!NewY || NewY == Src) {2825 M += NumSrcElts;2826 NewY = Src;2827 continue;2828 }2829 return false;2830 }2831 }2832 2833 if (!NewX)2834 return PoisonValue::get(ShuffleDstTy);2835 if (!NewY)2836 NewY = PoisonValue::get(ShuffleSrcTy);2837 2838 // Have we folded to an Identity shuffle?2839 if (ShuffleVectorInst::isIdentityMask(NewMask, NumSrcElts)) {2840 replaceValue(I, *NewX);2841 return true;2842 }2843 2844 // Try to merge the shuffles if the new shuffle is not costly.2845 InstructionCost InnerCost0 = 0;2846 if (Match0)2847 InnerCost0 = TTI.getInstructionCost(cast<User>(OuterV0), CostKind);2848 2849 InstructionCost InnerCost1 = 0;2850 if (Match1)2851 InnerCost1 = TTI.getInstructionCost(cast<User>(OuterV1), CostKind);2852 2853 InstructionCost OuterCost = TTI.getInstructionCost(&I, CostKind);2854 2855 InstructionCost OldCost = InnerCost0 + InnerCost1 + OuterCost;2856 2857 bool IsUnary = all_of(NewMask, [&](int M) { return M < (int)NumSrcElts; });2858 TargetTransformInfo::ShuffleKind SK =2859 IsUnary ? TargetTransformInfo::SK_PermuteSingleSrc2860 : TargetTransformInfo::SK_PermuteTwoSrc;2861 InstructionCost NewCost =2862 TTI.getShuffleCost(SK, ShuffleDstTy, ShuffleSrcTy, NewMask, CostKind, 0,2863 nullptr, {NewX, NewY});2864 if (!OuterV0->hasOneUse())2865 NewCost += InnerCost0;2866 if (!OuterV1->hasOneUse())2867 NewCost += InnerCost1;2868 2869 LLVM_DEBUG(dbgs() << "Found a shuffle feeding two shuffles: " << I2870 << "\n OldCost: " << OldCost << " vs NewCost: " << NewCost2871 << "\n");2872 if (NewCost > OldCost)2873 return false;2874 2875 Value *Shuf = Builder.CreateShuffleVector(NewX, NewY, NewMask);2876 replaceValue(I, *Shuf);2877 return true;2878}2879 2880/// Try to convert2881/// "shuffle (intrinsic), (intrinsic)" into "intrinsic (shuffle), (shuffle)".2882bool VectorCombine::foldShuffleOfIntrinsics(Instruction &I) {2883 Value *V0, *V1;2884 ArrayRef<int> OldMask;2885 if (!match(&I, m_Shuffle(m_OneUse(m_Value(V0)), m_OneUse(m_Value(V1)),2886 m_Mask(OldMask))))2887 return false;2888 2889 auto *II0 = dyn_cast<IntrinsicInst>(V0);2890 auto *II1 = dyn_cast<IntrinsicInst>(V1);2891 if (!II0 || !II1)2892 return false;2893 2894 Intrinsic::ID IID = II0->getIntrinsicID();2895 if (IID != II1->getIntrinsicID())2896 return false;2897 2898 auto *ShuffleDstTy = dyn_cast<FixedVectorType>(I.getType());2899 auto *II0Ty = dyn_cast<FixedVectorType>(II0->getType());2900 if (!ShuffleDstTy || !II0Ty)2901 return false;2902 2903 if (!isTriviallyVectorizable(IID))2904 return false;2905 2906 for (unsigned I = 0, E = II0->arg_size(); I != E; ++I)2907 if (isVectorIntrinsicWithScalarOpAtArg(IID, I, &TTI) &&2908 II0->getArgOperand(I) != II1->getArgOperand(I))2909 return false;2910 2911 InstructionCost OldCost =2912 TTI.getIntrinsicInstrCost(IntrinsicCostAttributes(IID, *II0), CostKind) +2913 TTI.getIntrinsicInstrCost(IntrinsicCostAttributes(IID, *II1), CostKind) +2914 TTI.getShuffleCost(TargetTransformInfo::SK_PermuteTwoSrc, ShuffleDstTy,2915 II0Ty, OldMask, CostKind, 0, nullptr, {II0, II1}, &I);2916 2917 SmallVector<Type *> NewArgsTy;2918 InstructionCost NewCost = 0;2919 for (unsigned I = 0, E = II0->arg_size(); I != E; ++I) {2920 if (isVectorIntrinsicWithScalarOpAtArg(IID, I, &TTI)) {2921 NewArgsTy.push_back(II0->getArgOperand(I)->getType());2922 } else {2923 auto *VecTy = cast<FixedVectorType>(II0->getArgOperand(I)->getType());2924 auto *ArgTy = FixedVectorType::get(VecTy->getElementType(),2925 ShuffleDstTy->getNumElements());2926 NewArgsTy.push_back(ArgTy);2927 NewCost += TTI.getShuffleCost(TargetTransformInfo::SK_PermuteTwoSrc,2928 ArgTy, VecTy, OldMask, CostKind);2929 }2930 }2931 IntrinsicCostAttributes NewAttr(IID, ShuffleDstTy, NewArgsTy);2932 NewCost += TTI.getIntrinsicInstrCost(NewAttr, CostKind);2933 2934 LLVM_DEBUG(dbgs() << "Found a shuffle feeding two intrinsics: " << I2935 << "\n OldCost: " << OldCost << " vs NewCost: " << NewCost2936 << "\n");2937 2938 if (NewCost > OldCost)2939 return false;2940 2941 SmallVector<Value *> NewArgs;2942 for (unsigned I = 0, E = II0->arg_size(); I != E; ++I)2943 if (isVectorIntrinsicWithScalarOpAtArg(IID, I, &TTI)) {2944 NewArgs.push_back(II0->getArgOperand(I));2945 } else {2946 Value *Shuf = Builder.CreateShuffleVector(II0->getArgOperand(I),2947 II1->getArgOperand(I), OldMask);2948 NewArgs.push_back(Shuf);2949 Worklist.pushValue(Shuf);2950 }2951 Value *NewIntrinsic = Builder.CreateIntrinsic(ShuffleDstTy, IID, NewArgs);2952 2953 // Intersect flags from the old intrinsics.2954 if (auto *NewInst = dyn_cast<Instruction>(NewIntrinsic)) {2955 NewInst->copyIRFlags(II0);2956 NewInst->andIRFlags(II1);2957 }2958 2959 replaceValue(I, *NewIntrinsic);2960 return true;2961}2962 2963using InstLane = std::pair<Use *, int>;2964 2965static InstLane lookThroughShuffles(Use *U, int Lane) {2966 while (auto *SV = dyn_cast<ShuffleVectorInst>(U->get())) {2967 unsigned NumElts =2968 cast<FixedVectorType>(SV->getOperand(0)->getType())->getNumElements();2969 int M = SV->getMaskValue(Lane);2970 if (M < 0)2971 return {nullptr, PoisonMaskElem};2972 if (static_cast<unsigned>(M) < NumElts) {2973 U = &SV->getOperandUse(0);2974 Lane = M;2975 } else {2976 U = &SV->getOperandUse(1);2977 Lane = M - NumElts;2978 }2979 }2980 return InstLane{U, Lane};2981}2982 2983static SmallVector<InstLane>2984generateInstLaneVectorFromOperand(ArrayRef<InstLane> Item, int Op) {2985 SmallVector<InstLane> NItem;2986 for (InstLane IL : Item) {2987 auto [U, Lane] = IL;2988 InstLane OpLane =2989 U ? lookThroughShuffles(&cast<Instruction>(U->get())->getOperandUse(Op),2990 Lane)2991 : InstLane{nullptr, PoisonMaskElem};2992 NItem.emplace_back(OpLane);2993 }2994 return NItem;2995}2996 2997/// Detect concat of multiple values into a vector2998static bool isFreeConcat(ArrayRef<InstLane> Item, TTI::TargetCostKind CostKind,2999 const TargetTransformInfo &TTI) {3000 auto *Ty = cast<FixedVectorType>(Item.front().first->get()->getType());3001 unsigned NumElts = Ty->getNumElements();3002 if (Item.size() == NumElts || NumElts == 1 || Item.size() % NumElts != 0)3003 return false;3004 3005 // Check that the concat is free, usually meaning that the type will be split3006 // during legalization.3007 SmallVector<int, 16> ConcatMask(NumElts * 2);3008 std::iota(ConcatMask.begin(), ConcatMask.end(), 0);3009 if (TTI.getShuffleCost(TTI::SK_PermuteTwoSrc,3010 FixedVectorType::get(Ty->getScalarType(), NumElts * 2),3011 Ty, ConcatMask, CostKind) != 0)3012 return false;3013 3014 unsigned NumSlices = Item.size() / NumElts;3015 // Currently we generate a tree of shuffles for the concats, which limits us3016 // to a power2.3017 if (!isPowerOf2_32(NumSlices))3018 return false;3019 for (unsigned Slice = 0; Slice < NumSlices; ++Slice) {3020 Use *SliceV = Item[Slice * NumElts].first;3021 if (!SliceV || SliceV->get()->getType() != Ty)3022 return false;3023 for (unsigned Elt = 0; Elt < NumElts; ++Elt) {3024 auto [V, Lane] = Item[Slice * NumElts + Elt];3025 if (Lane != static_cast<int>(Elt) || SliceV->get() != V->get())3026 return false;3027 }3028 }3029 return true;3030}3031 3032static Value *generateNewInstTree(ArrayRef<InstLane> Item, FixedVectorType *Ty,3033 const SmallPtrSet<Use *, 4> &IdentityLeafs,3034 const SmallPtrSet<Use *, 4> &SplatLeafs,3035 const SmallPtrSet<Use *, 4> &ConcatLeafs,3036 IRBuilderBase &Builder,3037 const TargetTransformInfo *TTI) {3038 auto [FrontU, FrontLane] = Item.front();3039 3040 if (IdentityLeafs.contains(FrontU)) {3041 return FrontU->get();3042 }3043 if (SplatLeafs.contains(FrontU)) {3044 SmallVector<int, 16> Mask(Ty->getNumElements(), FrontLane);3045 return Builder.CreateShuffleVector(FrontU->get(), Mask);3046 }3047 if (ConcatLeafs.contains(FrontU)) {3048 unsigned NumElts =3049 cast<FixedVectorType>(FrontU->get()->getType())->getNumElements();3050 SmallVector<Value *> Values(Item.size() / NumElts, nullptr);3051 for (unsigned S = 0; S < Values.size(); ++S)3052 Values[S] = Item[S * NumElts].first->get();3053 3054 while (Values.size() > 1) {3055 NumElts *= 2;3056 SmallVector<int, 16> Mask(NumElts, 0);3057 std::iota(Mask.begin(), Mask.end(), 0);3058 SmallVector<Value *> NewValues(Values.size() / 2, nullptr);3059 for (unsigned S = 0; S < NewValues.size(); ++S)3060 NewValues[S] =3061 Builder.CreateShuffleVector(Values[S * 2], Values[S * 2 + 1], Mask);3062 Values = NewValues;3063 }3064 return Values[0];3065 }3066 3067 auto *I = cast<Instruction>(FrontU->get());3068 auto *II = dyn_cast<IntrinsicInst>(I);3069 unsigned NumOps = I->getNumOperands() - (II ? 1 : 0);3070 SmallVector<Value *> Ops(NumOps);3071 for (unsigned Idx = 0; Idx < NumOps; Idx++) {3072 if (II &&3073 isVectorIntrinsicWithScalarOpAtArg(II->getIntrinsicID(), Idx, TTI)) {3074 Ops[Idx] = II->getOperand(Idx);3075 continue;3076 }3077 Ops[Idx] = generateNewInstTree(generateInstLaneVectorFromOperand(Item, Idx),3078 Ty, IdentityLeafs, SplatLeafs, ConcatLeafs,3079 Builder, TTI);3080 }3081 3082 SmallVector<Value *, 8> ValueList;3083 for (const auto &Lane : Item)3084 if (Lane.first)3085 ValueList.push_back(Lane.first->get());3086 3087 Type *DstTy =3088 FixedVectorType::get(I->getType()->getScalarType(), Ty->getNumElements());3089 if (auto *BI = dyn_cast<BinaryOperator>(I)) {3090 auto *Value = Builder.CreateBinOp((Instruction::BinaryOps)BI->getOpcode(),3091 Ops[0], Ops[1]);3092 propagateIRFlags(Value, ValueList);3093 return Value;3094 }3095 if (auto *CI = dyn_cast<CmpInst>(I)) {3096 auto *Value = Builder.CreateCmp(CI->getPredicate(), Ops[0], Ops[1]);3097 propagateIRFlags(Value, ValueList);3098 return Value;3099 }3100 if (auto *SI = dyn_cast<SelectInst>(I)) {3101 auto *Value = Builder.CreateSelect(Ops[0], Ops[1], Ops[2], "", SI);3102 propagateIRFlags(Value, ValueList);3103 return Value;3104 }3105 if (auto *CI = dyn_cast<CastInst>(I)) {3106 auto *Value = Builder.CreateCast(CI->getOpcode(), Ops[0], DstTy);3107 propagateIRFlags(Value, ValueList);3108 return Value;3109 }3110 if (II) {3111 auto *Value = Builder.CreateIntrinsic(DstTy, II->getIntrinsicID(), Ops);3112 propagateIRFlags(Value, ValueList);3113 return Value;3114 }3115 assert(isa<UnaryInstruction>(I) && "Unexpected instruction type in Generate");3116 auto *Value =3117 Builder.CreateUnOp((Instruction::UnaryOps)I->getOpcode(), Ops[0]);3118 propagateIRFlags(Value, ValueList);3119 return Value;3120}3121 3122// Starting from a shuffle, look up through operands tracking the shuffled index3123// of each lane. If we can simplify away the shuffles to identities then3124// do so.3125bool VectorCombine::foldShuffleToIdentity(Instruction &I) {3126 auto *Ty = dyn_cast<FixedVectorType>(I.getType());3127 if (!Ty || I.use_empty())3128 return false;3129 3130 SmallVector<InstLane> Start(Ty->getNumElements());3131 for (unsigned M = 0, E = Ty->getNumElements(); M < E; ++M)3132 Start[M] = lookThroughShuffles(&*I.use_begin(), M);3133 3134 SmallVector<SmallVector<InstLane>> Worklist;3135 Worklist.push_back(Start);3136 SmallPtrSet<Use *, 4> IdentityLeafs, SplatLeafs, ConcatLeafs;3137 unsigned NumVisited = 0;3138 3139 while (!Worklist.empty()) {3140 if (++NumVisited > MaxInstrsToScan)3141 return false;3142 3143 SmallVector<InstLane> Item = Worklist.pop_back_val();3144 auto [FrontU, FrontLane] = Item.front();3145 3146 // If we found an undef first lane then bail out to keep things simple.3147 if (!FrontU)3148 return false;3149 3150 // Helper to peek through bitcasts to the same value.3151 auto IsEquiv = [&](Value *X, Value *Y) {3152 return X->getType() == Y->getType() &&3153 peekThroughBitcasts(X) == peekThroughBitcasts(Y);3154 };3155 3156 // Look for an identity value.3157 if (FrontLane == 0 &&3158 cast<FixedVectorType>(FrontU->get()->getType())->getNumElements() ==3159 Ty->getNumElements() &&3160 all_of(drop_begin(enumerate(Item)), [IsEquiv, Item](const auto &E) {3161 Value *FrontV = Item.front().first->get();3162 return !E.value().first || (IsEquiv(E.value().first->get(), FrontV) &&3163 E.value().second == (int)E.index());3164 })) {3165 IdentityLeafs.insert(FrontU);3166 continue;3167 }3168 // Look for constants, for the moment only supporting constant splats.3169 if (auto *C = dyn_cast<Constant>(FrontU);3170 C && C->getSplatValue() &&3171 all_of(drop_begin(Item), [Item](InstLane &IL) {3172 Value *FrontV = Item.front().first->get();3173 Use *U = IL.first;3174 return !U || (isa<Constant>(U->get()) &&3175 cast<Constant>(U->get())->getSplatValue() ==3176 cast<Constant>(FrontV)->getSplatValue());3177 })) {3178 SplatLeafs.insert(FrontU);3179 continue;3180 }3181 // Look for a splat value.3182 if (all_of(drop_begin(Item), [Item](InstLane &IL) {3183 auto [FrontU, FrontLane] = Item.front();3184 auto [U, Lane] = IL;3185 return !U || (U->get() == FrontU->get() && Lane == FrontLane);3186 })) {3187 SplatLeafs.insert(FrontU);3188 continue;3189 }3190 3191 // We need each element to be the same type of value, and check that each3192 // element has a single use.3193 auto CheckLaneIsEquivalentToFirst = [Item](InstLane IL) {3194 Value *FrontV = Item.front().first->get();3195 if (!IL.first)3196 return true;3197 Value *V = IL.first->get();3198 if (auto *I = dyn_cast<Instruction>(V); I && !I->hasOneUser())3199 return false;3200 if (V->getValueID() != FrontV->getValueID())3201 return false;3202 if (auto *CI = dyn_cast<CmpInst>(V))3203 if (CI->getPredicate() != cast<CmpInst>(FrontV)->getPredicate())3204 return false;3205 if (auto *CI = dyn_cast<CastInst>(V))3206 if (CI->getSrcTy()->getScalarType() !=3207 cast<CastInst>(FrontV)->getSrcTy()->getScalarType())3208 return false;3209 if (auto *SI = dyn_cast<SelectInst>(V))3210 if (!isa<VectorType>(SI->getOperand(0)->getType()) ||3211 SI->getOperand(0)->getType() !=3212 cast<SelectInst>(FrontV)->getOperand(0)->getType())3213 return false;3214 if (isa<CallInst>(V) && !isa<IntrinsicInst>(V))3215 return false;3216 auto *II = dyn_cast<IntrinsicInst>(V);3217 return !II || (isa<IntrinsicInst>(FrontV) &&3218 II->getIntrinsicID() ==3219 cast<IntrinsicInst>(FrontV)->getIntrinsicID() &&3220 !II->hasOperandBundles());3221 };3222 if (all_of(drop_begin(Item), CheckLaneIsEquivalentToFirst)) {3223 // Check the operator is one that we support.3224 if (isa<BinaryOperator, CmpInst>(FrontU)) {3225 // We exclude div/rem in case they hit UB from poison lanes.3226 if (auto *BO = dyn_cast<BinaryOperator>(FrontU);3227 BO && BO->isIntDivRem())3228 return false;3229 Worklist.push_back(generateInstLaneVectorFromOperand(Item, 0));3230 Worklist.push_back(generateInstLaneVectorFromOperand(Item, 1));3231 continue;3232 } else if (isa<UnaryOperator, TruncInst, ZExtInst, SExtInst, FPToSIInst,3233 FPToUIInst, SIToFPInst, UIToFPInst>(FrontU)) {3234 Worklist.push_back(generateInstLaneVectorFromOperand(Item, 0));3235 continue;3236 } else if (auto *BitCast = dyn_cast<BitCastInst>(FrontU)) {3237 // TODO: Handle vector widening/narrowing bitcasts.3238 auto *DstTy = dyn_cast<FixedVectorType>(BitCast->getDestTy());3239 auto *SrcTy = dyn_cast<FixedVectorType>(BitCast->getSrcTy());3240 if (DstTy && SrcTy &&3241 SrcTy->getNumElements() == DstTy->getNumElements()) {3242 Worklist.push_back(generateInstLaneVectorFromOperand(Item, 0));3243 continue;3244 }3245 } else if (isa<SelectInst>(FrontU)) {3246 Worklist.push_back(generateInstLaneVectorFromOperand(Item, 0));3247 Worklist.push_back(generateInstLaneVectorFromOperand(Item, 1));3248 Worklist.push_back(generateInstLaneVectorFromOperand(Item, 2));3249 continue;3250 } else if (auto *II = dyn_cast<IntrinsicInst>(FrontU);3251 II && isTriviallyVectorizable(II->getIntrinsicID()) &&3252 !II->hasOperandBundles()) {3253 for (unsigned Op = 0, E = II->getNumOperands() - 1; Op < E; Op++) {3254 if (isVectorIntrinsicWithScalarOpAtArg(II->getIntrinsicID(), Op,3255 &TTI)) {3256 if (!all_of(drop_begin(Item), [Item, Op](InstLane &IL) {3257 Value *FrontV = Item.front().first->get();3258 Use *U = IL.first;3259 return !U || (cast<Instruction>(U->get())->getOperand(Op) ==3260 cast<Instruction>(FrontV)->getOperand(Op));3261 }))3262 return false;3263 continue;3264 }3265 Worklist.push_back(generateInstLaneVectorFromOperand(Item, Op));3266 }3267 continue;3268 }3269 }3270 3271 if (isFreeConcat(Item, CostKind, TTI)) {3272 ConcatLeafs.insert(FrontU);3273 continue;3274 }3275 3276 return false;3277 }3278 3279 if (NumVisited <= 1)3280 return false;3281 3282 LLVM_DEBUG(dbgs() << "Found a superfluous identity shuffle: " << I << "\n");3283 3284 // If we got this far, we know the shuffles are superfluous and can be3285 // removed. Scan through again and generate the new tree of instructions.3286 Builder.SetInsertPoint(&I);3287 Value *V = generateNewInstTree(Start, Ty, IdentityLeafs, SplatLeafs,3288 ConcatLeafs, Builder, &TTI);3289 replaceValue(I, *V);3290 return true;3291}3292 3293/// Given a commutative reduction, the order of the input lanes does not alter3294/// the results. We can use this to remove certain shuffles feeding the3295/// reduction, removing the need to shuffle at all.3296bool VectorCombine::foldShuffleFromReductions(Instruction &I) {3297 auto *II = dyn_cast<IntrinsicInst>(&I);3298 if (!II)3299 return false;3300 switch (II->getIntrinsicID()) {3301 case Intrinsic::vector_reduce_add:3302 case Intrinsic::vector_reduce_mul:3303 case Intrinsic::vector_reduce_and:3304 case Intrinsic::vector_reduce_or:3305 case Intrinsic::vector_reduce_xor:3306 case Intrinsic::vector_reduce_smin:3307 case Intrinsic::vector_reduce_smax:3308 case Intrinsic::vector_reduce_umin:3309 case Intrinsic::vector_reduce_umax:3310 break;3311 default:3312 return false;3313 }3314 3315 // Find all the inputs when looking through operations that do not alter the3316 // lane order (binops, for example). Currently we look for a single shuffle,3317 // and can ignore splat values.3318 std::queue<Value *> Worklist;3319 SmallPtrSet<Value *, 4> Visited;3320 ShuffleVectorInst *Shuffle = nullptr;3321 if (auto *Op = dyn_cast<Instruction>(I.getOperand(0)))3322 Worklist.push(Op);3323 3324 while (!Worklist.empty()) {3325 Value *CV = Worklist.front();3326 Worklist.pop();3327 if (Visited.contains(CV))3328 continue;3329 3330 // Splats don't change the order, so can be safely ignored.3331 if (isSplatValue(CV))3332 continue;3333 3334 Visited.insert(CV);3335 3336 if (auto *CI = dyn_cast<Instruction>(CV)) {3337 if (CI->isBinaryOp()) {3338 for (auto *Op : CI->operand_values())3339 Worklist.push(Op);3340 continue;3341 } else if (auto *SV = dyn_cast<ShuffleVectorInst>(CI)) {3342 if (Shuffle && Shuffle != SV)3343 return false;3344 Shuffle = SV;3345 continue;3346 }3347 }3348 3349 // Anything else is currently an unknown node.3350 return false;3351 }3352 3353 if (!Shuffle)3354 return false;3355 3356 // Check all uses of the binary ops and shuffles are also included in the3357 // lane-invariant operations (Visited should be the list of lanewise3358 // instructions, including the shuffle that we found).3359 for (auto *V : Visited)3360 for (auto *U : V->users())3361 if (!Visited.contains(U) && U != &I)3362 return false;3363 3364 FixedVectorType *VecType =3365 dyn_cast<FixedVectorType>(II->getOperand(0)->getType());3366 if (!VecType)3367 return false;3368 FixedVectorType *ShuffleInputType =3369 dyn_cast<FixedVectorType>(Shuffle->getOperand(0)->getType());3370 if (!ShuffleInputType)3371 return false;3372 unsigned NumInputElts = ShuffleInputType->getNumElements();3373 3374 // Find the mask from sorting the lanes into order. This is most likely to3375 // become a identity or concat mask. Undef elements are pushed to the end.3376 SmallVector<int> ConcatMask;3377 Shuffle->getShuffleMask(ConcatMask);3378 sort(ConcatMask, [](int X, int Y) { return (unsigned)X < (unsigned)Y; });3379 bool UsesSecondVec =3380 any_of(ConcatMask, [&](int M) { return M >= (int)NumInputElts; });3381 3382 InstructionCost OldCost = TTI.getShuffleCost(3383 UsesSecondVec ? TTI::SK_PermuteTwoSrc : TTI::SK_PermuteSingleSrc, VecType,3384 ShuffleInputType, Shuffle->getShuffleMask(), CostKind);3385 InstructionCost NewCost = TTI.getShuffleCost(3386 UsesSecondVec ? TTI::SK_PermuteTwoSrc : TTI::SK_PermuteSingleSrc, VecType,3387 ShuffleInputType, ConcatMask, CostKind);3388 3389 LLVM_DEBUG(dbgs() << "Found a reduction feeding from a shuffle: " << *Shuffle3390 << "\n");3391 LLVM_DEBUG(dbgs() << " OldCost: " << OldCost << " vs NewCost: " << NewCost3392 << "\n");3393 bool MadeChanges = false;3394 if (NewCost < OldCost) {3395 Builder.SetInsertPoint(Shuffle);3396 Value *NewShuffle = Builder.CreateShuffleVector(3397 Shuffle->getOperand(0), Shuffle->getOperand(1), ConcatMask);3398 LLVM_DEBUG(dbgs() << "Created new shuffle: " << *NewShuffle << "\n");3399 replaceValue(*Shuffle, *NewShuffle);3400 return true;3401 }3402 3403 // See if we can re-use foldSelectShuffle, getting it to reduce the size of3404 // the shuffle into a nicer order, as it can ignore the order of the shuffles.3405 MadeChanges |= foldSelectShuffle(*Shuffle, true);3406 return MadeChanges;3407}3408 3409/// For a given chain of patterns of the following form:3410///3411/// ```3412/// %1 = shufflevector <n x ty1> %0, <n x ty1> poison <n x ty2> mask3413///3414/// %2 = tail call <n x ty1> llvm.<umin/umax/smin/smax>(<n x ty1> %0, <n x3415/// ty1> %1)3416/// OR3417/// %2 = add/mul/or/and/xor <n x ty1> %0, %13418///3419/// %3 = shufflevector <n x ty1> %2, <n x ty1> poison <n x ty2> mask3420/// ...3421/// ...3422/// %(i - 1) = tail call <n x ty1> llvm.<umin/umax/smin/smax>(<n x ty1> %(i -3423/// 3), <n x ty1> %(i - 2)3424/// OR3425/// %(i - 1) = add/mul/or/and/xor <n x ty1> %(i - 3), %(i - 2)3426///3427/// %(i) = extractelement <n x ty1> %(i - 1), 03428/// ```3429///3430/// Where:3431/// `mask` follows a partition pattern:3432///3433/// Ex:3434/// [n = 8, p = poison]3435///3436/// 4 5 6 7 | p p p p3437/// 2 3 | p p p p p p3438/// 1 | p p p p p p p3439///3440/// For powers of 2, there's a consistent pattern, but for other cases3441/// the parity of the current half value at each step decides the3442/// next partition half (see `ExpectedParityMask` for more logical details3443/// in generalising this).3444///3445/// Ex:3446/// [n = 6]3447///3448/// 3 4 5 | p p p3449/// 1 2 | p p p p3450/// 1 | p p p p p3451bool VectorCombine::foldShuffleChainsToReduce(Instruction &I) {3452 // Going bottom-up for the pattern.3453 std::queue<Value *> InstWorklist;3454 InstructionCost OrigCost = 0;3455 3456 // Common instruction operation after each shuffle op.3457 std::optional<unsigned int> CommonCallOp = std::nullopt;3458 std::optional<Instruction::BinaryOps> CommonBinOp = std::nullopt;3459 3460 bool IsFirstCallOrBinInst = true;3461 bool ShouldBeCallOrBinInst = true;3462 3463 // This stores the last used instructions for shuffle/common op.3464 //3465 // PrevVecV[0] / PrevVecV[1] store the last two simultaneous3466 // instructions from either shuffle/common op.3467 SmallVector<Value *, 2> PrevVecV(2, nullptr);3468 3469 Value *VecOpEE;3470 if (!match(&I, m_ExtractElt(m_Value(VecOpEE), m_Zero())))3471 return false;3472 3473 auto *FVT = dyn_cast<FixedVectorType>(VecOpEE->getType());3474 if (!FVT)3475 return false;3476 3477 int64_t VecSize = FVT->getNumElements();3478 if (VecSize < 2)3479 return false;3480 3481 // Number of levels would be ~log2(n), considering we always partition3482 // by half for this fold pattern.3483 unsigned int NumLevels = Log2_64_Ceil(VecSize), VisitedCnt = 0;3484 int64_t ShuffleMaskHalf = 1, ExpectedParityMask = 0;3485 3486 // This is how we generalise for all element sizes.3487 // At each step, if vector size is odd, we need non-poison3488 // values to cover the dominant half so we don't miss out on any element.3489 //3490 // This mask will help us retrieve this as we go from bottom to top:3491 //3492 // Mask Set -> N = N * 2 - 13493 // Mask Unset -> N = N * 23494 for (int Cur = VecSize, Mask = NumLevels - 1; Cur > 1;3495 Cur = (Cur + 1) / 2, --Mask) {3496 if (Cur & 1)3497 ExpectedParityMask |= (1ll << Mask);3498 }3499 3500 InstWorklist.push(VecOpEE);3501 3502 while (!InstWorklist.empty()) {3503 Value *CI = InstWorklist.front();3504 InstWorklist.pop();3505 3506 if (auto *II = dyn_cast<IntrinsicInst>(CI)) {3507 if (!ShouldBeCallOrBinInst)3508 return false;3509 3510 if (!IsFirstCallOrBinInst &&3511 any_of(PrevVecV, [](Value *VecV) { return VecV == nullptr; }))3512 return false;3513 3514 // For the first found call/bin op, the vector has to come from the3515 // extract element op.3516 if (II != (IsFirstCallOrBinInst ? VecOpEE : PrevVecV[0]))3517 return false;3518 IsFirstCallOrBinInst = false;3519 3520 if (!CommonCallOp)3521 CommonCallOp = II->getIntrinsicID();3522 if (II->getIntrinsicID() != *CommonCallOp)3523 return false;3524 3525 switch (II->getIntrinsicID()) {3526 case Intrinsic::umin:3527 case Intrinsic::umax:3528 case Intrinsic::smin:3529 case Intrinsic::smax: {3530 auto *Op0 = II->getOperand(0);3531 auto *Op1 = II->getOperand(1);3532 PrevVecV[0] = Op0;3533 PrevVecV[1] = Op1;3534 break;3535 }3536 default:3537 return false;3538 }3539 ShouldBeCallOrBinInst ^= 1;3540 3541 IntrinsicCostAttributes ICA(3542 *CommonCallOp, II->getType(),3543 {PrevVecV[0]->getType(), PrevVecV[1]->getType()});3544 OrigCost += TTI.getIntrinsicInstrCost(ICA, CostKind);3545 3546 // We may need a swap here since it can be (a, b) or (b, a)3547 // and accordingly change as we go up.3548 if (!isa<ShuffleVectorInst>(PrevVecV[1]))3549 std::swap(PrevVecV[0], PrevVecV[1]);3550 InstWorklist.push(PrevVecV[1]);3551 InstWorklist.push(PrevVecV[0]);3552 } else if (auto *BinOp = dyn_cast<BinaryOperator>(CI)) {3553 // Similar logic for bin ops.3554 3555 if (!ShouldBeCallOrBinInst)3556 return false;3557 3558 if (!IsFirstCallOrBinInst &&3559 any_of(PrevVecV, [](Value *VecV) { return VecV == nullptr; }))3560 return false;3561 3562 if (BinOp != (IsFirstCallOrBinInst ? VecOpEE : PrevVecV[0]))3563 return false;3564 IsFirstCallOrBinInst = false;3565 3566 if (!CommonBinOp)3567 CommonBinOp = BinOp->getOpcode();3568 3569 if (BinOp->getOpcode() != *CommonBinOp)3570 return false;3571 3572 switch (*CommonBinOp) {3573 case BinaryOperator::Add:3574 case BinaryOperator::Mul:3575 case BinaryOperator::Or:3576 case BinaryOperator::And:3577 case BinaryOperator::Xor: {3578 auto *Op0 = BinOp->getOperand(0);3579 auto *Op1 = BinOp->getOperand(1);3580 PrevVecV[0] = Op0;3581 PrevVecV[1] = Op1;3582 break;3583 }3584 default:3585 return false;3586 }3587 ShouldBeCallOrBinInst ^= 1;3588 3589 OrigCost +=3590 TTI.getArithmeticInstrCost(*CommonBinOp, BinOp->getType(), CostKind);3591 3592 if (!isa<ShuffleVectorInst>(PrevVecV[1]))3593 std::swap(PrevVecV[0], PrevVecV[1]);3594 InstWorklist.push(PrevVecV[1]);3595 InstWorklist.push(PrevVecV[0]);3596 } else if (auto *SVInst = dyn_cast<ShuffleVectorInst>(CI)) {3597 // We shouldn't have any null values in the previous vectors,3598 // is so, there was a mismatch in pattern.3599 if (ShouldBeCallOrBinInst ||3600 any_of(PrevVecV, [](Value *VecV) { return VecV == nullptr; }))3601 return false;3602 3603 if (SVInst != PrevVecV[1])3604 return false;3605 3606 ArrayRef<int> CurMask;3607 if (!match(SVInst, m_Shuffle(m_Specific(PrevVecV[0]), m_Poison(),3608 m_Mask(CurMask))))3609 return false;3610 3611 // Subtract the parity mask when checking the condition.3612 for (int Mask = 0, MaskSize = CurMask.size(); Mask != MaskSize; ++Mask) {3613 if (Mask < ShuffleMaskHalf &&3614 CurMask[Mask] != ShuffleMaskHalf + Mask - (ExpectedParityMask & 1))3615 return false;3616 if (Mask >= ShuffleMaskHalf && CurMask[Mask] != -1)3617 return false;3618 }3619 3620 // Update mask values.3621 ShuffleMaskHalf *= 2;3622 ShuffleMaskHalf -= (ExpectedParityMask & 1);3623 ExpectedParityMask >>= 1;3624 3625 OrigCost += TTI.getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc,3626 SVInst->getType(), SVInst->getType(),3627 CurMask, CostKind);3628 3629 VisitedCnt += 1;3630 if (!ExpectedParityMask && VisitedCnt == NumLevels)3631 break;3632 3633 ShouldBeCallOrBinInst ^= 1;3634 } else {3635 return false;3636 }3637 }3638 3639 // Pattern should end with a shuffle op.3640 if (ShouldBeCallOrBinInst)3641 return false;3642 3643 assert(VecSize != -1 && "Expected Match for Vector Size");3644 3645 Value *FinalVecV = PrevVecV[0];3646 if (!FinalVecV)3647 return false;3648 3649 auto *FinalVecVTy = cast<FixedVectorType>(FinalVecV->getType());3650 3651 Intrinsic::ID ReducedOp =3652 (CommonCallOp ? getMinMaxReductionIntrinsicID(*CommonCallOp)3653 : getReductionForBinop(*CommonBinOp));3654 if (!ReducedOp)3655 return false;3656 3657 IntrinsicCostAttributes ICA(ReducedOp, FinalVecVTy, {FinalVecV});3658 InstructionCost NewCost = TTI.getIntrinsicInstrCost(ICA, CostKind);3659 3660 if (NewCost >= OrigCost)3661 return false;3662 3663 auto *ReducedResult =3664 Builder.CreateIntrinsic(ReducedOp, {FinalVecV->getType()}, {FinalVecV});3665 replaceValue(I, *ReducedResult);3666 3667 return true;3668}3669 3670/// Determine if its more efficient to fold:3671/// reduce(trunc(x)) -> trunc(reduce(x)).3672/// reduce(sext(x)) -> sext(reduce(x)).3673/// reduce(zext(x)) -> zext(reduce(x)).3674bool VectorCombine::foldCastFromReductions(Instruction &I) {3675 auto *II = dyn_cast<IntrinsicInst>(&I);3676 if (!II)3677 return false;3678 3679 bool TruncOnly = false;3680 Intrinsic::ID IID = II->getIntrinsicID();3681 switch (IID) {3682 case Intrinsic::vector_reduce_add:3683 case Intrinsic::vector_reduce_mul:3684 TruncOnly = true;3685 break;3686 case Intrinsic::vector_reduce_and:3687 case Intrinsic::vector_reduce_or:3688 case Intrinsic::vector_reduce_xor:3689 break;3690 default:3691 return false;3692 }3693 3694 unsigned ReductionOpc = getArithmeticReductionInstruction(IID);3695 Value *ReductionSrc = I.getOperand(0);3696 3697 Value *Src;3698 if (!match(ReductionSrc, m_OneUse(m_Trunc(m_Value(Src)))) &&3699 (TruncOnly || !match(ReductionSrc, m_OneUse(m_ZExtOrSExt(m_Value(Src))))))3700 return false;3701 3702 auto CastOpc =3703 (Instruction::CastOps)cast<Instruction>(ReductionSrc)->getOpcode();3704 3705 auto *SrcTy = cast<VectorType>(Src->getType());3706 auto *ReductionSrcTy = cast<VectorType>(ReductionSrc->getType());3707 Type *ResultTy = I.getType();3708 3709 InstructionCost OldCost = TTI.getArithmeticReductionCost(3710 ReductionOpc, ReductionSrcTy, std::nullopt, CostKind);3711 OldCost += TTI.getCastInstrCost(CastOpc, ReductionSrcTy, SrcTy,3712 TTI::CastContextHint::None, CostKind,3713 cast<CastInst>(ReductionSrc));3714 InstructionCost NewCost =3715 TTI.getArithmeticReductionCost(ReductionOpc, SrcTy, std::nullopt,3716 CostKind) +3717 TTI.getCastInstrCost(CastOpc, ResultTy, ReductionSrcTy->getScalarType(),3718 TTI::CastContextHint::None, CostKind);3719 3720 if (OldCost <= NewCost || !NewCost.isValid())3721 return false;3722 3723 Value *NewReduction = Builder.CreateIntrinsic(SrcTy->getScalarType(),3724 II->getIntrinsicID(), {Src});3725 Value *NewCast = Builder.CreateCast(CastOpc, NewReduction, ResultTy);3726 replaceValue(I, *NewCast);3727 return true;3728}3729 3730/// Returns true if this ShuffleVectorInst eventually feeds into a3731/// vector reduction intrinsic (e.g., vector_reduce_add) by only following3732/// chains of shuffles and binary operators (in any combination/order).3733/// The search does not go deeper than the given Depth.3734static bool feedsIntoVectorReduction(ShuffleVectorInst *SVI) {3735 constexpr unsigned MaxVisited = 32;3736 SmallPtrSet<Instruction *, 8> Visited;3737 SmallVector<Instruction *, 4> WorkList;3738 bool FoundReduction = false;3739 3740 WorkList.push_back(SVI);3741 while (!WorkList.empty()) {3742 Instruction *I = WorkList.pop_back_val();3743 for (User *U : I->users()) {3744 auto *UI = cast<Instruction>(U);3745 if (!UI || !Visited.insert(UI).second)3746 continue;3747 if (Visited.size() > MaxVisited)3748 return false;3749 if (auto *II = dyn_cast<IntrinsicInst>(UI)) {3750 // More than one reduction reached3751 if (FoundReduction)3752 return false;3753 switch (II->getIntrinsicID()) {3754 case Intrinsic::vector_reduce_add:3755 case Intrinsic::vector_reduce_mul:3756 case Intrinsic::vector_reduce_and:3757 case Intrinsic::vector_reduce_or:3758 case Intrinsic::vector_reduce_xor:3759 case Intrinsic::vector_reduce_smin:3760 case Intrinsic::vector_reduce_smax:3761 case Intrinsic::vector_reduce_umin:3762 case Intrinsic::vector_reduce_umax:3763 FoundReduction = true;3764 continue;3765 default:3766 return false;3767 }3768 }3769 3770 if (!isa<BinaryOperator>(UI) && !isa<ShuffleVectorInst>(UI))3771 return false;3772 3773 WorkList.emplace_back(UI);3774 }3775 }3776 return FoundReduction;3777}3778 3779/// This method looks for groups of shuffles acting on binops, of the form:3780/// %x = shuffle ...3781/// %y = shuffle ...3782/// %a = binop %x, %y3783/// %b = binop %x, %y3784/// shuffle %a, %b, selectmask3785/// We may, especially if the shuffle is wider than legal, be able to convert3786/// the shuffle to a form where only parts of a and b need to be computed. On3787/// architectures with no obvious "select" shuffle, this can reduce the total3788/// number of operations if the target reports them as cheaper.3789bool VectorCombine::foldSelectShuffle(Instruction &I, bool FromReduction) {3790 auto *SVI = cast<ShuffleVectorInst>(&I);3791 auto *VT = cast<FixedVectorType>(I.getType());3792 auto *Op0 = dyn_cast<Instruction>(SVI->getOperand(0));3793 auto *Op1 = dyn_cast<Instruction>(SVI->getOperand(1));3794 if (!Op0 || !Op1 || Op0 == Op1 || !Op0->isBinaryOp() || !Op1->isBinaryOp() ||3795 VT != Op0->getType())3796 return false;3797 3798 auto *SVI0A = dyn_cast<Instruction>(Op0->getOperand(0));3799 auto *SVI0B = dyn_cast<Instruction>(Op0->getOperand(1));3800 auto *SVI1A = dyn_cast<Instruction>(Op1->getOperand(0));3801 auto *SVI1B = dyn_cast<Instruction>(Op1->getOperand(1));3802 SmallPtrSet<Instruction *, 4> InputShuffles({SVI0A, SVI0B, SVI1A, SVI1B});3803 auto checkSVNonOpUses = [&](Instruction *I) {3804 if (!I || I->getOperand(0)->getType() != VT)3805 return true;3806 return any_of(I->users(), [&](User *U) {3807 return U != Op0 && U != Op1 &&3808 !(isa<ShuffleVectorInst>(U) &&3809 (InputShuffles.contains(cast<Instruction>(U)) ||3810 isInstructionTriviallyDead(cast<Instruction>(U))));3811 });3812 };3813 if (checkSVNonOpUses(SVI0A) || checkSVNonOpUses(SVI0B) ||3814 checkSVNonOpUses(SVI1A) || checkSVNonOpUses(SVI1B))3815 return false;3816 3817 // Collect all the uses that are shuffles that we can transform together. We3818 // may not have a single shuffle, but a group that can all be transformed3819 // together profitably.3820 SmallVector<ShuffleVectorInst *> Shuffles;3821 auto collectShuffles = [&](Instruction *I) {3822 for (auto *U : I->users()) {3823 auto *SV = dyn_cast<ShuffleVectorInst>(U);3824 if (!SV || SV->getType() != VT)3825 return false;3826 if ((SV->getOperand(0) != Op0 && SV->getOperand(0) != Op1) ||3827 (SV->getOperand(1) != Op0 && SV->getOperand(1) != Op1))3828 return false;3829 if (!llvm::is_contained(Shuffles, SV))3830 Shuffles.push_back(SV);3831 }3832 return true;3833 };3834 if (!collectShuffles(Op0) || !collectShuffles(Op1))3835 return false;3836 // From a reduction, we need to be processing a single shuffle, otherwise the3837 // other uses will not be lane-invariant.3838 if (FromReduction && Shuffles.size() > 1)3839 return false;3840 3841 // Add any shuffle uses for the shuffles we have found, to include them in our3842 // cost calculations.3843 if (!FromReduction) {3844 for (ShuffleVectorInst *SV : Shuffles) {3845 for (auto *U : SV->users()) {3846 ShuffleVectorInst *SSV = dyn_cast<ShuffleVectorInst>(U);3847 if (SSV && isa<UndefValue>(SSV->getOperand(1)) && SSV->getType() == VT)3848 Shuffles.push_back(SSV);3849 }3850 }3851 }3852 3853 // For each of the output shuffles, we try to sort all the first vector3854 // elements to the beginning, followed by the second array elements at the3855 // end. If the binops are legalized to smaller vectors, this may reduce total3856 // number of binops. We compute the ReconstructMask mask needed to convert3857 // back to the original lane order.3858 SmallVector<std::pair<int, int>> V1, V2;3859 SmallVector<SmallVector<int>> OrigReconstructMasks;3860 int MaxV1Elt = 0, MaxV2Elt = 0;3861 unsigned NumElts = VT->getNumElements();3862 for (ShuffleVectorInst *SVN : Shuffles) {3863 SmallVector<int> Mask;3864 SVN->getShuffleMask(Mask);3865 3866 // Check the operands are the same as the original, or reversed (in which3867 // case we need to commute the mask).3868 Value *SVOp0 = SVN->getOperand(0);3869 Value *SVOp1 = SVN->getOperand(1);3870 if (isa<UndefValue>(SVOp1)) {3871 auto *SSV = cast<ShuffleVectorInst>(SVOp0);3872 SVOp0 = SSV->getOperand(0);3873 SVOp1 = SSV->getOperand(1);3874 for (int &Elem : Mask) {3875 if (Elem >= static_cast<int>(SSV->getShuffleMask().size()))3876 return false;3877 Elem = Elem < 0 ? Elem : SSV->getMaskValue(Elem);3878 }3879 }3880 if (SVOp0 == Op1 && SVOp1 == Op0) {3881 std::swap(SVOp0, SVOp1);3882 ShuffleVectorInst::commuteShuffleMask(Mask, NumElts);3883 }3884 if (SVOp0 != Op0 || SVOp1 != Op1)3885 return false;3886 3887 // Calculate the reconstruction mask for this shuffle, as the mask needed to3888 // take the packed values from Op0/Op1 and reconstructing to the original3889 // order.3890 SmallVector<int> ReconstructMask;3891 for (unsigned I = 0; I < Mask.size(); I++) {3892 if (Mask[I] < 0) {3893 ReconstructMask.push_back(-1);3894 } else if (Mask[I] < static_cast<int>(NumElts)) {3895 MaxV1Elt = std::max(MaxV1Elt, Mask[I]);3896 auto It = find_if(V1, [&](const std::pair<int, int> &A) {3897 return Mask[I] == A.first;3898 });3899 if (It != V1.end())3900 ReconstructMask.push_back(It - V1.begin());3901 else {3902 ReconstructMask.push_back(V1.size());3903 V1.emplace_back(Mask[I], V1.size());3904 }3905 } else {3906 MaxV2Elt = std::max<int>(MaxV2Elt, Mask[I] - NumElts);3907 auto It = find_if(V2, [&](const std::pair<int, int> &A) {3908 return Mask[I] - static_cast<int>(NumElts) == A.first;3909 });3910 if (It != V2.end())3911 ReconstructMask.push_back(NumElts + It - V2.begin());3912 else {3913 ReconstructMask.push_back(NumElts + V2.size());3914 V2.emplace_back(Mask[I] - NumElts, NumElts + V2.size());3915 }3916 }3917 }3918 3919 // For reductions, we know that the lane ordering out doesn't alter the3920 // result. In-order can help simplify the shuffle away.3921 if (FromReduction)3922 sort(ReconstructMask);3923 OrigReconstructMasks.push_back(std::move(ReconstructMask));3924 }3925 3926 // If the Maximum element used from V1 and V2 are not larger than the new3927 // vectors, the vectors are already packes and performing the optimization3928 // again will likely not help any further. This also prevents us from getting3929 // stuck in a cycle in case the costs do not also rule it out.3930 if (V1.empty() || V2.empty() ||3931 (MaxV1Elt == static_cast<int>(V1.size()) - 1 &&3932 MaxV2Elt == static_cast<int>(V2.size()) - 1))3933 return false;3934 3935 // GetBaseMaskValue takes one of the inputs, which may either be a shuffle, a3936 // shuffle of another shuffle, or not a shuffle (that is treated like a3937 // identity shuffle).3938 auto GetBaseMaskValue = [&](Instruction *I, int M) {3939 auto *SV = dyn_cast<ShuffleVectorInst>(I);3940 if (!SV)3941 return M;3942 if (isa<UndefValue>(SV->getOperand(1)))3943 if (auto *SSV = dyn_cast<ShuffleVectorInst>(SV->getOperand(0)))3944 if (InputShuffles.contains(SSV))3945 return SSV->getMaskValue(SV->getMaskValue(M));3946 return SV->getMaskValue(M);3947 };3948 3949 // Attempt to sort the inputs my ascending mask values to make simpler input3950 // shuffles and push complex shuffles down to the uses. We sort on the first3951 // of the two input shuffle orders, to try and get at least one input into a3952 // nice order.3953 auto SortBase = [&](Instruction *A, std::pair<int, int> X,3954 std::pair<int, int> Y) {3955 int MXA = GetBaseMaskValue(A, X.first);3956 int MYA = GetBaseMaskValue(A, Y.first);3957 return MXA < MYA;3958 };3959 stable_sort(V1, [&](std::pair<int, int> A, std::pair<int, int> B) {3960 return SortBase(SVI0A, A, B);3961 });3962 stable_sort(V2, [&](std::pair<int, int> A, std::pair<int, int> B) {3963 return SortBase(SVI1A, A, B);3964 });3965 // Calculate our ReconstructMasks from the OrigReconstructMasks and the3966 // modified order of the input shuffles.3967 SmallVector<SmallVector<int>> ReconstructMasks;3968 for (const auto &Mask : OrigReconstructMasks) {3969 SmallVector<int> ReconstructMask;3970 for (int M : Mask) {3971 auto FindIndex = [](const SmallVector<std::pair<int, int>> &V, int M) {3972 auto It = find_if(V, [M](auto A) { return A.second == M; });3973 assert(It != V.end() && "Expected all entries in Mask");3974 return std::distance(V.begin(), It);3975 };3976 if (M < 0)3977 ReconstructMask.push_back(-1);3978 else if (M < static_cast<int>(NumElts)) {3979 ReconstructMask.push_back(FindIndex(V1, M));3980 } else {3981 ReconstructMask.push_back(NumElts + FindIndex(V2, M));3982 }3983 }3984 ReconstructMasks.push_back(std::move(ReconstructMask));3985 }3986 3987 // Calculate the masks needed for the new input shuffles, which get padded3988 // with undef3989 SmallVector<int> V1A, V1B, V2A, V2B;3990 for (unsigned I = 0; I < V1.size(); I++) {3991 V1A.push_back(GetBaseMaskValue(SVI0A, V1[I].first));3992 V1B.push_back(GetBaseMaskValue(SVI0B, V1[I].first));3993 }3994 for (unsigned I = 0; I < V2.size(); I++) {3995 V2A.push_back(GetBaseMaskValue(SVI1A, V2[I].first));3996 V2B.push_back(GetBaseMaskValue(SVI1B, V2[I].first));3997 }3998 while (V1A.size() < NumElts) {3999 V1A.push_back(PoisonMaskElem);4000 V1B.push_back(PoisonMaskElem);4001 }4002 while (V2A.size() < NumElts) {4003 V2A.push_back(PoisonMaskElem);4004 V2B.push_back(PoisonMaskElem);4005 }4006 4007 auto AddShuffleCost = [&](InstructionCost C, Instruction *I) {4008 auto *SV = dyn_cast<ShuffleVectorInst>(I);4009 if (!SV)4010 return C;4011 return C + TTI.getShuffleCost(isa<UndefValue>(SV->getOperand(1))4012 ? TTI::SK_PermuteSingleSrc4013 : TTI::SK_PermuteTwoSrc,4014 VT, VT, SV->getShuffleMask(), CostKind);4015 };4016 auto AddShuffleMaskCost = [&](InstructionCost C, ArrayRef<int> Mask) {4017 return C +4018 TTI.getShuffleCost(TTI::SK_PermuteTwoSrc, VT, VT, Mask, CostKind);4019 };4020 4021 unsigned ElementSize = VT->getElementType()->getPrimitiveSizeInBits();4022 unsigned MaxVectorSize =4023 TTI.getRegisterBitWidth(TargetTransformInfo::RGK_FixedWidthVector);4024 unsigned MaxElementsInVector = MaxVectorSize / ElementSize;4025 if (MaxElementsInVector == 0)4026 return false;4027 // When there are multiple shufflevector operations on the same input,4028 // especially when the vector length is larger than the register size,4029 // identical shuffle patterns may occur across different groups of elements.4030 // To avoid overestimating the cost by counting these repeated shuffles more4031 // than once, we only account for unique shuffle patterns. This adjustment4032 // prevents inflated costs in the cost model for wide vectors split into4033 // several register-sized groups.4034 std::set<SmallVector<int, 4>> UniqueShuffles;4035 auto AddShuffleMaskAdjustedCost = [&](InstructionCost C, ArrayRef<int> Mask) {4036 // Compute the cost for performing the shuffle over the full vector.4037 auto ShuffleCost =4038 TTI.getShuffleCost(TTI::SK_PermuteTwoSrc, VT, VT, Mask, CostKind);4039 unsigned NumFullVectors = Mask.size() / MaxElementsInVector;4040 if (NumFullVectors < 2)4041 return C + ShuffleCost;4042 SmallVector<int, 4> SubShuffle(MaxElementsInVector);4043 unsigned NumUniqueGroups = 0;4044 unsigned NumGroups = Mask.size() / MaxElementsInVector;4045 // For each group of MaxElementsInVector contiguous elements,4046 // collect their shuffle pattern and insert into the set of unique patterns.4047 for (unsigned I = 0; I < NumFullVectors; ++I) {4048 for (unsigned J = 0; J < MaxElementsInVector; ++J)4049 SubShuffle[J] = Mask[MaxElementsInVector * I + J];4050 if (UniqueShuffles.insert(SubShuffle).second)4051 NumUniqueGroups += 1;4052 }4053 return C + ShuffleCost * NumUniqueGroups / NumGroups;4054 };4055 auto AddShuffleAdjustedCost = [&](InstructionCost C, Instruction *I) {4056 auto *SV = dyn_cast<ShuffleVectorInst>(I);4057 if (!SV)4058 return C;4059 SmallVector<int, 16> Mask;4060 SV->getShuffleMask(Mask);4061 return AddShuffleMaskAdjustedCost(C, Mask);4062 };4063 // Check that input consists of ShuffleVectors applied to the same input4064 auto AllShufflesHaveSameOperands =4065 [](SmallPtrSetImpl<Instruction *> &InputShuffles) {4066 if (InputShuffles.size() < 2)4067 return false;4068 ShuffleVectorInst *FirstSV =4069 dyn_cast<ShuffleVectorInst>(*InputShuffles.begin());4070 if (!FirstSV)4071 return false;4072 4073 Value *In0 = FirstSV->getOperand(0), *In1 = FirstSV->getOperand(1);4074 return std::all_of(4075 std::next(InputShuffles.begin()), InputShuffles.end(),4076 [&](Instruction *I) {4077 ShuffleVectorInst *SV = dyn_cast<ShuffleVectorInst>(I);4078 return SV && SV->getOperand(0) == In0 && SV->getOperand(1) == In1;4079 });4080 };4081 4082 // Get the costs of the shuffles + binops before and after with the new4083 // shuffle masks.4084 InstructionCost CostBefore =4085 TTI.getArithmeticInstrCost(Op0->getOpcode(), VT, CostKind) +4086 TTI.getArithmeticInstrCost(Op1->getOpcode(), VT, CostKind);4087 CostBefore += std::accumulate(Shuffles.begin(), Shuffles.end(),4088 InstructionCost(0), AddShuffleCost);4089 if (AllShufflesHaveSameOperands(InputShuffles)) {4090 UniqueShuffles.clear();4091 CostBefore += std::accumulate(InputShuffles.begin(), InputShuffles.end(),4092 InstructionCost(0), AddShuffleAdjustedCost);4093 } else {4094 CostBefore += std::accumulate(InputShuffles.begin(), InputShuffles.end(),4095 InstructionCost(0), AddShuffleCost);4096 }4097 4098 // The new binops will be unused for lanes past the used shuffle lengths.4099 // These types attempt to get the correct cost for that from the target.4100 FixedVectorType *Op0SmallVT =4101 FixedVectorType::get(VT->getScalarType(), V1.size());4102 FixedVectorType *Op1SmallVT =4103 FixedVectorType::get(VT->getScalarType(), V2.size());4104 InstructionCost CostAfter =4105 TTI.getArithmeticInstrCost(Op0->getOpcode(), Op0SmallVT, CostKind) +4106 TTI.getArithmeticInstrCost(Op1->getOpcode(), Op1SmallVT, CostKind);4107 UniqueShuffles.clear();4108 CostAfter += std::accumulate(ReconstructMasks.begin(), ReconstructMasks.end(),4109 InstructionCost(0), AddShuffleMaskAdjustedCost);4110 std::set<SmallVector<int>> OutputShuffleMasks({V1A, V1B, V2A, V2B});4111 CostAfter +=4112 std::accumulate(OutputShuffleMasks.begin(), OutputShuffleMasks.end(),4113 InstructionCost(0), AddShuffleMaskCost);4114 4115 LLVM_DEBUG(dbgs() << "Found a binop select shuffle pattern: " << I << "\n");4116 LLVM_DEBUG(dbgs() << " CostBefore: " << CostBefore4117 << " vs CostAfter: " << CostAfter << "\n");4118 if (CostBefore < CostAfter ||4119 (CostBefore == CostAfter && !feedsIntoVectorReduction(SVI)))4120 return false;4121 4122 // The cost model has passed, create the new instructions.4123 auto GetShuffleOperand = [&](Instruction *I, unsigned Op) -> Value * {4124 auto *SV = dyn_cast<ShuffleVectorInst>(I);4125 if (!SV)4126 return I;4127 if (isa<UndefValue>(SV->getOperand(1)))4128 if (auto *SSV = dyn_cast<ShuffleVectorInst>(SV->getOperand(0)))4129 if (InputShuffles.contains(SSV))4130 return SSV->getOperand(Op);4131 return SV->getOperand(Op);4132 };4133 Builder.SetInsertPoint(*SVI0A->getInsertionPointAfterDef());4134 Value *NSV0A = Builder.CreateShuffleVector(GetShuffleOperand(SVI0A, 0),4135 GetShuffleOperand(SVI0A, 1), V1A);4136 Builder.SetInsertPoint(*SVI0B->getInsertionPointAfterDef());4137 Value *NSV0B = Builder.CreateShuffleVector(GetShuffleOperand(SVI0B, 0),4138 GetShuffleOperand(SVI0B, 1), V1B);4139 Builder.SetInsertPoint(*SVI1A->getInsertionPointAfterDef());4140 Value *NSV1A = Builder.CreateShuffleVector(GetShuffleOperand(SVI1A, 0),4141 GetShuffleOperand(SVI1A, 1), V2A);4142 Builder.SetInsertPoint(*SVI1B->getInsertionPointAfterDef());4143 Value *NSV1B = Builder.CreateShuffleVector(GetShuffleOperand(SVI1B, 0),4144 GetShuffleOperand(SVI1B, 1), V2B);4145 Builder.SetInsertPoint(Op0);4146 Value *NOp0 = Builder.CreateBinOp((Instruction::BinaryOps)Op0->getOpcode(),4147 NSV0A, NSV0B);4148 if (auto *I = dyn_cast<Instruction>(NOp0))4149 I->copyIRFlags(Op0, true);4150 Builder.SetInsertPoint(Op1);4151 Value *NOp1 = Builder.CreateBinOp((Instruction::BinaryOps)Op1->getOpcode(),4152 NSV1A, NSV1B);4153 if (auto *I = dyn_cast<Instruction>(NOp1))4154 I->copyIRFlags(Op1, true);4155 4156 for (int S = 0, E = ReconstructMasks.size(); S != E; S++) {4157 Builder.SetInsertPoint(Shuffles[S]);4158 Value *NSV = Builder.CreateShuffleVector(NOp0, NOp1, ReconstructMasks[S]);4159 replaceValue(*Shuffles[S], *NSV, false);4160 }4161 4162 Worklist.pushValue(NSV0A);4163 Worklist.pushValue(NSV0B);4164 Worklist.pushValue(NSV1A);4165 Worklist.pushValue(NSV1B);4166 return true;4167}4168 4169/// Check if instruction depends on ZExt and this ZExt can be moved after the4170/// instruction. Move ZExt if it is profitable. For example:4171/// logic(zext(x),y) -> zext(logic(x,trunc(y)))4172/// lshr((zext(x),y) -> zext(lshr(x,trunc(y)))4173/// Cost model calculations takes into account if zext(x) has other users and4174/// whether it can be propagated through them too.4175bool VectorCombine::shrinkType(Instruction &I) {4176 Value *ZExted, *OtherOperand;4177 if (!match(&I, m_c_BitwiseLogic(m_ZExt(m_Value(ZExted)),4178 m_Value(OtherOperand))) &&4179 !match(&I, m_LShr(m_ZExt(m_Value(ZExted)), m_Value(OtherOperand))))4180 return false;4181 4182 Value *ZExtOperand = I.getOperand(I.getOperand(0) == OtherOperand ? 1 : 0);4183 4184 auto *BigTy = cast<FixedVectorType>(I.getType());4185 auto *SmallTy = cast<FixedVectorType>(ZExted->getType());4186 unsigned BW = SmallTy->getElementType()->getPrimitiveSizeInBits();4187 4188 if (I.getOpcode() == Instruction::LShr) {4189 // Check that the shift amount is less than the number of bits in the4190 // smaller type. Otherwise, the smaller lshr will return a poison value.4191 KnownBits ShAmtKB = computeKnownBits(I.getOperand(1), *DL);4192 if (ShAmtKB.getMaxValue().uge(BW))4193 return false;4194 } else {4195 // Check that the expression overall uses at most the same number of bits as4196 // ZExted4197 KnownBits KB = computeKnownBits(&I, *DL);4198 if (KB.countMaxActiveBits() > BW)4199 return false;4200 }4201 4202 // Calculate costs of leaving current IR as it is and moving ZExt operation4203 // later, along with adding truncates if needed4204 InstructionCost ZExtCost = TTI.getCastInstrCost(4205 Instruction::ZExt, BigTy, SmallTy,4206 TargetTransformInfo::CastContextHint::None, CostKind);4207 InstructionCost CurrentCost = ZExtCost;4208 InstructionCost ShrinkCost = 0;4209 4210 // Calculate total cost and check that we can propagate through all ZExt users4211 for (User *U : ZExtOperand->users()) {4212 auto *UI = cast<Instruction>(U);4213 if (UI == &I) {4214 CurrentCost +=4215 TTI.getArithmeticInstrCost(UI->getOpcode(), BigTy, CostKind);4216 ShrinkCost +=4217 TTI.getArithmeticInstrCost(UI->getOpcode(), SmallTy, CostKind);4218 ShrinkCost += ZExtCost;4219 continue;4220 }4221 4222 if (!Instruction::isBinaryOp(UI->getOpcode()))4223 return false;4224 4225 // Check if we can propagate ZExt through its other users4226 KnownBits KB = computeKnownBits(UI, *DL);4227 if (KB.countMaxActiveBits() > BW)4228 return false;4229 4230 CurrentCost += TTI.getArithmeticInstrCost(UI->getOpcode(), BigTy, CostKind);4231 ShrinkCost +=4232 TTI.getArithmeticInstrCost(UI->getOpcode(), SmallTy, CostKind);4233 ShrinkCost += ZExtCost;4234 }4235 4236 // If the other instruction operand is not a constant, we'll need to4237 // generate a truncate instruction. So we have to adjust cost4238 if (!isa<Constant>(OtherOperand))4239 ShrinkCost += TTI.getCastInstrCost(4240 Instruction::Trunc, SmallTy, BigTy,4241 TargetTransformInfo::CastContextHint::None, CostKind);4242 4243 // If the cost of shrinking types and leaving the IR is the same, we'll lean4244 // towards modifying the IR because shrinking opens opportunities for other4245 // shrinking optimisations.4246 if (ShrinkCost > CurrentCost)4247 return false;4248 4249 Builder.SetInsertPoint(&I);4250 Value *Op0 = ZExted;4251 Value *Op1 = Builder.CreateTrunc(OtherOperand, SmallTy);4252 // Keep the order of operands the same4253 if (I.getOperand(0) == OtherOperand)4254 std::swap(Op0, Op1);4255 Value *NewBinOp =4256 Builder.CreateBinOp((Instruction::BinaryOps)I.getOpcode(), Op0, Op1);4257 cast<Instruction>(NewBinOp)->copyIRFlags(&I);4258 cast<Instruction>(NewBinOp)->copyMetadata(I);4259 Value *NewZExtr = Builder.CreateZExt(NewBinOp, BigTy);4260 replaceValue(I, *NewZExtr);4261 return true;4262}4263 4264/// insert (DstVec, (extract SrcVec, ExtIdx), InsIdx) -->4265/// shuffle (DstVec, SrcVec, Mask)4266bool VectorCombine::foldInsExtVectorToShuffle(Instruction &I) {4267 Value *DstVec, *SrcVec;4268 uint64_t ExtIdx, InsIdx;4269 if (!match(&I,4270 m_InsertElt(m_Value(DstVec),4271 m_ExtractElt(m_Value(SrcVec), m_ConstantInt(ExtIdx)),4272 m_ConstantInt(InsIdx))))4273 return false;4274 4275 auto *DstVecTy = dyn_cast<FixedVectorType>(I.getType());4276 auto *SrcVecTy = dyn_cast<FixedVectorType>(SrcVec->getType());4277 // We can try combining vectors with different element sizes.4278 if (!DstVecTy || !SrcVecTy ||4279 SrcVecTy->getElementType() != DstVecTy->getElementType())4280 return false;4281 4282 unsigned NumDstElts = DstVecTy->getNumElements();4283 unsigned NumSrcElts = SrcVecTy->getNumElements();4284 if (InsIdx >= NumDstElts || ExtIdx >= NumSrcElts || NumDstElts == 1)4285 return false;4286 4287 // Insertion into poison is a cheaper single operand shuffle.4288 TargetTransformInfo::ShuffleKind SK;4289 SmallVector<int> Mask(NumDstElts, PoisonMaskElem);4290 4291 bool NeedExpOrNarrow = NumSrcElts != NumDstElts;4292 bool IsExtIdxInBounds = ExtIdx < NumDstElts;4293 bool NeedDstSrcSwap = isa<PoisonValue>(DstVec) && !isa<UndefValue>(SrcVec);4294 if (NeedDstSrcSwap) {4295 SK = TargetTransformInfo::SK_PermuteSingleSrc;4296 if (!IsExtIdxInBounds && NeedExpOrNarrow)4297 Mask[InsIdx] = 0;4298 else4299 Mask[InsIdx] = ExtIdx;4300 std::swap(DstVec, SrcVec);4301 } else {4302 SK = TargetTransformInfo::SK_PermuteTwoSrc;4303 std::iota(Mask.begin(), Mask.end(), 0);4304 if (!IsExtIdxInBounds && NeedExpOrNarrow)4305 Mask[InsIdx] = NumDstElts;4306 else4307 Mask[InsIdx] = ExtIdx + NumDstElts;4308 }4309 4310 // Cost4311 auto *Ins = cast<InsertElementInst>(&I);4312 auto *Ext = cast<ExtractElementInst>(I.getOperand(1));4313 InstructionCost InsCost =4314 TTI.getVectorInstrCost(*Ins, DstVecTy, CostKind, InsIdx);4315 InstructionCost ExtCost =4316 TTI.getVectorInstrCost(*Ext, DstVecTy, CostKind, ExtIdx);4317 InstructionCost OldCost = ExtCost + InsCost;4318 4319 InstructionCost NewCost = 0;4320 SmallVector<int> ExtToVecMask;4321 if (!NeedExpOrNarrow) {4322 // Ignore 'free' identity insertion shuffle.4323 // TODO: getShuffleCost should return TCC_Free for Identity shuffles.4324 if (!ShuffleVectorInst::isIdentityMask(Mask, NumSrcElts))4325 NewCost += TTI.getShuffleCost(SK, DstVecTy, DstVecTy, Mask, CostKind, 0,4326 nullptr, {DstVec, SrcVec});4327 } else {4328 // When creating length-changing-vector, always create with a Mask whose4329 // first element has an ExtIdx, so that the first element of the vector4330 // being created is always the target to be extracted.4331 ExtToVecMask.assign(NumDstElts, PoisonMaskElem);4332 if (IsExtIdxInBounds)4333 ExtToVecMask[ExtIdx] = ExtIdx;4334 else4335 ExtToVecMask[0] = ExtIdx;4336 // Add cost for expanding or narrowing4337 NewCost = TTI.getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc,4338 DstVecTy, SrcVecTy, ExtToVecMask, CostKind);4339 NewCost += TTI.getShuffleCost(SK, DstVecTy, DstVecTy, Mask, CostKind);4340 }4341 4342 if (!Ext->hasOneUse())4343 NewCost += ExtCost;4344 4345 LLVM_DEBUG(dbgs() << "Found a insert/extract shuffle-like pair: " << I4346 << "\n OldCost: " << OldCost << " vs NewCost: " << NewCost4347 << "\n");4348 4349 if (OldCost < NewCost)4350 return false;4351 4352 if (NeedExpOrNarrow) {4353 if (!NeedDstSrcSwap)4354 SrcVec = Builder.CreateShuffleVector(SrcVec, ExtToVecMask);4355 else4356 DstVec = Builder.CreateShuffleVector(DstVec, ExtToVecMask);4357 }4358 4359 // Canonicalize undef param to RHS to help further folds.4360 if (isa<UndefValue>(DstVec) && !isa<UndefValue>(SrcVec)) {4361 ShuffleVectorInst::commuteShuffleMask(Mask, NumDstElts);4362 std::swap(DstVec, SrcVec);4363 }4364 4365 Value *Shuf = Builder.CreateShuffleVector(DstVec, SrcVec, Mask);4366 replaceValue(I, *Shuf);4367 4368 return true;4369}4370 4371/// If we're interleaving 2 constant splats, for instance `<vscale x 8 x i32>4372/// <splat of 666>` and `<vscale x 8 x i32> <splat of 777>`, we can create a4373/// larger splat `<vscale x 8 x i64> <splat of ((777 << 32) | 666)>` first4374/// before casting it back into `<vscale x 16 x i32>`.4375bool VectorCombine::foldInterleaveIntrinsics(Instruction &I) {4376 const APInt *SplatVal0, *SplatVal1;4377 if (!match(&I, m_Intrinsic<Intrinsic::vector_interleave2>(4378 m_APInt(SplatVal0), m_APInt(SplatVal1))))4379 return false;4380 4381 LLVM_DEBUG(dbgs() << "VC: Folding interleave2 with two splats: " << I4382 << "\n");4383 4384 auto *VTy =4385 cast<VectorType>(cast<IntrinsicInst>(I).getArgOperand(0)->getType());4386 auto *ExtVTy = VectorType::getExtendedElementVectorType(VTy);4387 unsigned Width = VTy->getElementType()->getIntegerBitWidth();4388 4389 // Just in case the cost of interleave2 intrinsic and bitcast are both4390 // invalid, in which case we want to bail out, we use <= rather4391 // than < here. Even they both have valid and equal costs, it's probably4392 // not a good idea to emit a high-cost constant splat.4393 if (TTI.getInstructionCost(&I, CostKind) <=4394 TTI.getCastInstrCost(Instruction::BitCast, I.getType(), ExtVTy,4395 TTI::CastContextHint::None, CostKind)) {4396 LLVM_DEBUG(dbgs() << "VC: The cost to cast from " << *ExtVTy << " to "4397 << *I.getType() << " is too high.\n");4398 return false;4399 }4400 4401 APInt NewSplatVal = SplatVal1->zext(Width * 2);4402 NewSplatVal <<= Width;4403 NewSplatVal |= SplatVal0->zext(Width * 2);4404 auto *NewSplat = ConstantVector::getSplat(4405 ExtVTy->getElementCount(), ConstantInt::get(F.getContext(), NewSplatVal));4406 4407 IRBuilder<> Builder(&I);4408 replaceValue(I, *Builder.CreateBitCast(NewSplat, I.getType()));4409 return true;4410}4411 4412// Attempt to shrink loads that are only used by shufflevector instructions.4413bool VectorCombine::shrinkLoadForShuffles(Instruction &I) {4414 auto *OldLoad = dyn_cast<LoadInst>(&I);4415 if (!OldLoad || !OldLoad->isSimple())4416 return false;4417 4418 auto *OldLoadTy = dyn_cast<FixedVectorType>(OldLoad->getType());4419 if (!OldLoadTy)4420 return false;4421 4422 unsigned const OldNumElements = OldLoadTy->getNumElements();4423 4424 // Search all uses of load. If all uses are shufflevector instructions, and4425 // the second operands are all poison values, find the minimum and maximum4426 // indices of the vector elements referenced by all shuffle masks.4427 // Otherwise return `std::nullopt`.4428 using IndexRange = std::pair<int, int>;4429 auto GetIndexRangeInShuffles = [&]() -> std::optional<IndexRange> {4430 IndexRange OutputRange = IndexRange(OldNumElements, -1);4431 for (llvm::Use &Use : I.uses()) {4432 // Ensure all uses match the required pattern.4433 User *Shuffle = Use.getUser();4434 ArrayRef<int> Mask;4435 4436 if (!match(Shuffle,4437 m_Shuffle(m_Specific(OldLoad), m_Undef(), m_Mask(Mask))))4438 return std::nullopt;4439 4440 // Ignore shufflevector instructions that have no uses.4441 if (Shuffle->use_empty())4442 continue;4443 4444 // Find the min and max indices used by the shufflevector instruction.4445 for (int Index : Mask) {4446 if (Index >= 0 && Index < static_cast<int>(OldNumElements)) {4447 OutputRange.first = std::min(Index, OutputRange.first);4448 OutputRange.second = std::max(Index, OutputRange.second);4449 }4450 }4451 }4452 4453 if (OutputRange.second < OutputRange.first)4454 return std::nullopt;4455 4456 return OutputRange;4457 };4458 4459 // Get the range of vector elements used by shufflevector instructions.4460 if (std::optional<IndexRange> Indices = GetIndexRangeInShuffles()) {4461 unsigned const NewNumElements = Indices->second + 1u;4462 4463 // If the range of vector elements is smaller than the full load, attempt4464 // to create a smaller load.4465 if (NewNumElements < OldNumElements) {4466 IRBuilder Builder(&I);4467 Builder.SetCurrentDebugLocation(I.getDebugLoc());4468 4469 // Calculate costs of old and new ops.4470 Type *ElemTy = OldLoadTy->getElementType();4471 FixedVectorType *NewLoadTy = FixedVectorType::get(ElemTy, NewNumElements);4472 Value *PtrOp = OldLoad->getPointerOperand();4473 4474 InstructionCost OldCost = TTI.getMemoryOpCost(4475 Instruction::Load, OldLoad->getType(), OldLoad->getAlign(),4476 OldLoad->getPointerAddressSpace(), CostKind);4477 InstructionCost NewCost =4478 TTI.getMemoryOpCost(Instruction::Load, NewLoadTy, OldLoad->getAlign(),4479 OldLoad->getPointerAddressSpace(), CostKind);4480 4481 using UseEntry = std::pair<ShuffleVectorInst *, std::vector<int>>;4482 SmallVector<UseEntry, 4u> NewUses;4483 unsigned const MaxIndex = NewNumElements * 2u;4484 4485 for (llvm::Use &Use : I.uses()) {4486 auto *Shuffle = cast<ShuffleVectorInst>(Use.getUser());4487 ArrayRef<int> OldMask = Shuffle->getShuffleMask();4488 4489 // Create entry for new use.4490 NewUses.push_back({Shuffle, OldMask});4491 4492 // Validate mask indices.4493 for (int Index : OldMask) {4494 if (Index >= static_cast<int>(MaxIndex))4495 return false;4496 }4497 4498 // Update costs.4499 OldCost +=4500 TTI.getShuffleCost(TTI::SK_PermuteSingleSrc, Shuffle->getType(),4501 OldLoadTy, OldMask, CostKind);4502 NewCost +=4503 TTI.getShuffleCost(TTI::SK_PermuteSingleSrc, Shuffle->getType(),4504 NewLoadTy, OldMask, CostKind);4505 }4506 4507 LLVM_DEBUG(4508 dbgs() << "Found a load used only by shufflevector instructions: "4509 << I << "\n OldCost: " << OldCost4510 << " vs NewCost: " << NewCost << "\n");4511 4512 if (OldCost < NewCost || !NewCost.isValid())4513 return false;4514 4515 // Create new load of smaller vector.4516 auto *NewLoad = cast<LoadInst>(4517 Builder.CreateAlignedLoad(NewLoadTy, PtrOp, OldLoad->getAlign()));4518 NewLoad->copyMetadata(I);4519 4520 // Replace all uses.4521 for (UseEntry &Use : NewUses) {4522 ShuffleVectorInst *Shuffle = Use.first;4523 std::vector<int> &NewMask = Use.second;4524 4525 Builder.SetInsertPoint(Shuffle);4526 Builder.SetCurrentDebugLocation(Shuffle->getDebugLoc());4527 Value *NewShuffle = Builder.CreateShuffleVector(4528 NewLoad, PoisonValue::get(NewLoadTy), NewMask);4529 4530 replaceValue(*Shuffle, *NewShuffle, false);4531 }4532 4533 return true;4534 }4535 }4536 return false;4537}4538 4539// Attempt to narrow a phi of shufflevector instructions where the two incoming4540// values have the same operands but different masks. If the two shuffle masks4541// are offsets of one another we can use one branch to rotate the incoming4542// vector and perform one larger shuffle after the phi.4543bool VectorCombine::shrinkPhiOfShuffles(Instruction &I) {4544 auto *Phi = dyn_cast<PHINode>(&I);4545 if (!Phi || Phi->getNumIncomingValues() != 2u)4546 return false;4547 4548 Value *Op = nullptr;4549 ArrayRef<int> Mask0;4550 ArrayRef<int> Mask1;4551 4552 if (!match(Phi->getOperand(0u),4553 m_OneUse(m_Shuffle(m_Value(Op), m_Poison(), m_Mask(Mask0)))) ||4554 !match(Phi->getOperand(1u),4555 m_OneUse(m_Shuffle(m_Specific(Op), m_Poison(), m_Mask(Mask1)))))4556 return false;4557 4558 auto *Shuf = cast<ShuffleVectorInst>(Phi->getOperand(0u));4559 4560 // Ensure result vectors are wider than the argument vector.4561 auto *InputVT = cast<FixedVectorType>(Op->getType());4562 auto *ResultVT = cast<FixedVectorType>(Shuf->getType());4563 auto const InputNumElements = InputVT->getNumElements();4564 4565 if (InputNumElements >= ResultVT->getNumElements())4566 return false;4567 4568 // Take the difference of the two shuffle masks at each index. Ignore poison4569 // values at the same index in both masks.4570 SmallVector<int, 16> NewMask;4571 NewMask.reserve(Mask0.size());4572 4573 for (auto [M0, M1] : zip(Mask0, Mask1)) {4574 if (M0 >= 0 && M1 >= 0)4575 NewMask.push_back(M0 - M1);4576 else if (M0 == -1 && M1 == -1)4577 continue;4578 else4579 return false;4580 }4581 4582 // Ensure all elements of the new mask are equal. If the difference between4583 // the incoming mask elements is the same, the two must be constant offsets4584 // of one another.4585 if (NewMask.empty() || !all_equal(NewMask))4586 return false;4587 4588 // Create new mask using difference of the two incoming masks.4589 int MaskOffset = NewMask[0u];4590 unsigned Index = (InputNumElements + MaskOffset) % InputNumElements;4591 NewMask.clear();4592 4593 for (unsigned I = 0u; I < InputNumElements; ++I) {4594 NewMask.push_back(Index);4595 Index = (Index + 1u) % InputNumElements;4596 }4597 4598 // Calculate costs for worst cases and compare.4599 auto const Kind = TTI::SK_PermuteSingleSrc;4600 auto OldCost =4601 std::max(TTI.getShuffleCost(Kind, ResultVT, InputVT, Mask0, CostKind),4602 TTI.getShuffleCost(Kind, ResultVT, InputVT, Mask1, CostKind));4603 auto NewCost = TTI.getShuffleCost(Kind, InputVT, InputVT, NewMask, CostKind) +4604 TTI.getShuffleCost(Kind, ResultVT, InputVT, Mask1, CostKind);4605 4606 LLVM_DEBUG(dbgs() << "Found a phi of mergeable shuffles: " << I4607 << "\n OldCost: " << OldCost << " vs NewCost: " << NewCost4608 << "\n");4609 4610 if (NewCost > OldCost)4611 return false;4612 4613 // Create new shuffles and narrowed phi.4614 auto Builder = IRBuilder(Shuf);4615 Builder.SetCurrentDebugLocation(Shuf->getDebugLoc());4616 auto *PoisonVal = PoisonValue::get(InputVT);4617 auto *NewShuf0 = Builder.CreateShuffleVector(Op, PoisonVal, NewMask);4618 Worklist.push(cast<Instruction>(NewShuf0));4619 4620 Builder.SetInsertPoint(Phi);4621 Builder.SetCurrentDebugLocation(Phi->getDebugLoc());4622 auto *NewPhi = Builder.CreatePHI(NewShuf0->getType(), 2u);4623 NewPhi->addIncoming(NewShuf0, Phi->getIncomingBlock(0u));4624 NewPhi->addIncoming(Op, Phi->getIncomingBlock(1u));4625 4626 Builder.SetInsertPoint(*NewPhi->getInsertionPointAfterDef());4627 PoisonVal = PoisonValue::get(NewPhi->getType());4628 auto *NewShuf1 = Builder.CreateShuffleVector(NewPhi, PoisonVal, Mask1);4629 4630 replaceValue(*Phi, *NewShuf1);4631 return true;4632}4633 4634/// This is the entry point for all transforms. Pass manager differences are4635/// handled in the callers of this function.4636bool VectorCombine::run() {4637 if (DisableVectorCombine)4638 return false;4639 4640 // Don't attempt vectorization if the target does not support vectors.4641 if (!TTI.getNumberOfRegisters(TTI.getRegisterClassForType(/*Vector*/ true)))4642 return false;4643 4644 LLVM_DEBUG(dbgs() << "\n\nVECTORCOMBINE on " << F.getName() << "\n");4645 4646 auto FoldInst = [this](Instruction &I) {4647 Builder.SetInsertPoint(&I);4648 bool IsVectorType = isa<VectorType>(I.getType());4649 bool IsFixedVectorType = isa<FixedVectorType>(I.getType());4650 auto Opcode = I.getOpcode();4651 4652 LLVM_DEBUG(dbgs() << "VC: Visiting: " << I << '\n');4653 4654 // These folds should be beneficial regardless of when this pass is run4655 // in the optimization pipeline.4656 // The type checking is for run-time efficiency. We can avoid wasting time4657 // dispatching to folding functions if there's no chance of matching.4658 if (IsFixedVectorType) {4659 switch (Opcode) {4660 case Instruction::InsertElement:4661 if (vectorizeLoadInsert(I))4662 return true;4663 break;4664 case Instruction::ShuffleVector:4665 if (widenSubvectorLoad(I))4666 return true;4667 break;4668 default:4669 break;4670 }4671 }4672 4673 // This transform works with scalable and fixed vectors4674 // TODO: Identify and allow other scalable transforms4675 if (IsVectorType) {4676 if (scalarizeOpOrCmp(I))4677 return true;4678 if (scalarizeLoad(I))4679 return true;4680 if (scalarizeExtExtract(I))4681 return true;4682 if (scalarizeVPIntrinsic(I))4683 return true;4684 if (foldInterleaveIntrinsics(I))4685 return true;4686 }4687 4688 if (Opcode == Instruction::Store)4689 if (foldSingleElementStore(I))4690 return true;4691 4692 // If this is an early pipeline invocation of this pass, we are done.4693 if (TryEarlyFoldsOnly)4694 return false;4695 4696 // Otherwise, try folds that improve codegen but may interfere with4697 // early IR canonicalizations.4698 // The type checking is for run-time efficiency. We can avoid wasting time4699 // dispatching to folding functions if there's no chance of matching.4700 if (IsFixedVectorType) {4701 switch (Opcode) {4702 case Instruction::InsertElement:4703 if (foldInsExtFNeg(I))4704 return true;4705 if (foldInsExtBinop(I))4706 return true;4707 if (foldInsExtVectorToShuffle(I))4708 return true;4709 break;4710 case Instruction::ShuffleVector:4711 if (foldPermuteOfBinops(I))4712 return true;4713 if (foldShuffleOfBinops(I))4714 return true;4715 if (foldShuffleOfSelects(I))4716 return true;4717 if (foldShuffleOfCastops(I))4718 return true;4719 if (foldShuffleOfShuffles(I))4720 return true;4721 if (foldShuffleOfIntrinsics(I))4722 return true;4723 if (foldSelectShuffle(I))4724 return true;4725 if (foldShuffleToIdentity(I))4726 return true;4727 break;4728 case Instruction::Load:4729 if (shrinkLoadForShuffles(I))4730 return true;4731 break;4732 case Instruction::BitCast:4733 if (foldBitcastShuffle(I))4734 return true;4735 break;4736 case Instruction::And:4737 case Instruction::Or:4738 case Instruction::Xor:4739 if (foldBitOpOfCastops(I))4740 return true;4741 if (foldBitOpOfCastConstant(I))4742 return true;4743 break;4744 case Instruction::PHI:4745 if (shrinkPhiOfShuffles(I))4746 return true;4747 break;4748 default:4749 if (shrinkType(I))4750 return true;4751 break;4752 }4753 } else {4754 switch (Opcode) {4755 case Instruction::Call:4756 if (foldShuffleFromReductions(I))4757 return true;4758 if (foldCastFromReductions(I))4759 return true;4760 break;4761 case Instruction::ExtractElement:4762 if (foldShuffleChainsToReduce(I))4763 return true;4764 break;4765 case Instruction::ICmp:4766 case Instruction::FCmp:4767 if (foldExtractExtract(I))4768 return true;4769 break;4770 case Instruction::Or:4771 if (foldConcatOfBoolMasks(I))4772 return true;4773 [[fallthrough]];4774 default:4775 if (Instruction::isBinaryOp(Opcode)) {4776 if (foldExtractExtract(I))4777 return true;4778 if (foldExtractedCmps(I))4779 return true;4780 if (foldBinopOfReductions(I))4781 return true;4782 }4783 break;4784 }4785 }4786 return false;4787 };4788 4789 bool MadeChange = false;4790 for (BasicBlock &BB : F) {4791 // Ignore unreachable basic blocks.4792 if (!DT.isReachableFromEntry(&BB))4793 continue;4794 // Use early increment range so that we can erase instructions in loop.4795 // make_early_inc_range is not applicable here, as the next iterator may4796 // be invalidated by RecursivelyDeleteTriviallyDeadInstructions.4797 // We manually maintain the next instruction and update it when it is about4798 // to be deleted.4799 Instruction *I = &BB.front();4800 while (I) {4801 NextInst = I->getNextNode();4802 if (!I->isDebugOrPseudoInst())4803 MadeChange |= FoldInst(*I);4804 I = NextInst;4805 }4806 }4807 4808 NextInst = nullptr;4809 4810 while (!Worklist.isEmpty()) {4811 Instruction *I = Worklist.removeOne();4812 if (!I)4813 continue;4814 4815 if (isInstructionTriviallyDead(I)) {4816 eraseInstruction(*I);4817 continue;4818 }4819 4820 MadeChange |= FoldInst(*I);4821 }4822 4823 return MadeChange;4824}4825 4826PreservedAnalyses VectorCombinePass::run(Function &F,4827 FunctionAnalysisManager &FAM) {4828 auto &AC = FAM.getResult<AssumptionAnalysis>(F);4829 TargetTransformInfo &TTI = FAM.getResult<TargetIRAnalysis>(F);4830 DominatorTree &DT = FAM.getResult<DominatorTreeAnalysis>(F);4831 AAResults &AA = FAM.getResult<AAManager>(F);4832 const DataLayout *DL = &F.getDataLayout();4833 VectorCombine Combiner(F, TTI, DT, AA, AC, DL, TTI::TCK_RecipThroughput,4834 TryEarlyFoldsOnly);4835 if (!Combiner.run())4836 return PreservedAnalyses::all();4837 PreservedAnalyses PA;4838 PA.preserveSet<CFGAnalyses>();4839 return PA;4840}4841