2528 lines · cpp
1//===- ComplexDeinterleavingPass.cpp --------------------------------------===//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// Identification:10// This step is responsible for finding the patterns that can be lowered to11// complex instructions, and building a graph to represent the complex12// structures. Starting from the "Converging Shuffle" (a shuffle that13// reinterleaves the complex components, with a mask of <0, 2, 1, 3>), the14// operands are evaluated and identified as "Composite Nodes" (collections of15// instructions that can potentially be lowered to a single complex16// instruction). This is performed by checking the real and imaginary components17// and tracking the data flow for each component while following the operand18// pairs. Validity of each node is expected to be done upon creation, and any19// validation errors should halt traversal and prevent further graph20// construction.21// Instead of relying on Shuffle operations, vector interleaving and22// deinterleaving can be represented by vector.interleave2 and23// vector.deinterleave2 intrinsics. Scalable vectors can be represented only by24// these intrinsics, whereas, fixed-width vectors are recognized for both25// shufflevector instruction and intrinsics.26//27// Replacement:28// This step traverses the graph built up by identification, delegating to the29// target to validate and generate the correct intrinsics, and plumbs them30// together connecting each end of the new intrinsics graph to the existing31// use-def chain. This step is assumed to finish successfully, as all32// information is expected to be correct by this point.33//34//35// Internal data structure:36// ComplexDeinterleavingGraph:37// Keeps references to all the valid CompositeNodes formed as part of the38// transformation, and every Instruction contained within said nodes. It also39// holds onto a reference to the root Instruction, and the root node that should40// replace it.41//42// ComplexDeinterleavingCompositeNode:43// A CompositeNode represents a single transformation point; each node should44// transform into a single complex instruction (ignoring vector splitting, which45// would generate more instructions per node). They are identified in a46// depth-first manner, traversing and identifying the operands of each47// instruction in the order they appear in the IR.48// Each node maintains a reference to its Real and Imaginary instructions,49// as well as any additional instructions that make up the identified operation50// (Internal instructions should only have uses within their containing node).51// A Node also contains the rotation and operation type that it represents.52// Operands contains pointers to other CompositeNodes, acting as the edges in53// the graph. ReplacementValue is the transformed Value* that has been emitted54// to the IR.55//56// Note: If the operation of a Node is Shuffle, only the Real, Imaginary, and57// ReplacementValue fields of that Node are relevant, where the ReplacementValue58// should be pre-populated.59//60//===----------------------------------------------------------------------===//61 62#include "llvm/CodeGen/ComplexDeinterleavingPass.h"63#include "llvm/ADT/AllocatorList.h"64#include "llvm/ADT/MapVector.h"65#include "llvm/ADT/Statistic.h"66#include "llvm/Analysis/TargetLibraryInfo.h"67#include "llvm/Analysis/TargetTransformInfo.h"68#include "llvm/CodeGen/TargetLowering.h"69#include "llvm/CodeGen/TargetSubtargetInfo.h"70#include "llvm/IR/IRBuilder.h"71#include "llvm/IR/Intrinsics.h"72#include "llvm/IR/PatternMatch.h"73#include "llvm/InitializePasses.h"74#include "llvm/Support/Allocator.h"75#include "llvm/Target/TargetMachine.h"76#include "llvm/Transforms/Utils/Local.h"77#include <algorithm>78 79using namespace llvm;80using namespace PatternMatch;81 82#define DEBUG_TYPE "complex-deinterleaving"83 84STATISTIC(NumComplexTransformations, "Amount of complex patterns transformed");85 86static cl::opt<bool> ComplexDeinterleavingEnabled(87 "enable-complex-deinterleaving",88 cl::desc("Enable generation of complex instructions"), cl::init(true),89 cl::Hidden);90 91/// Checks the given mask, and determines whether said mask is interleaving.92///93/// To be interleaving, a mask must alternate between `i` and `i + (Length /94/// 2)`, and must contain all numbers within the range of `[0..Length)` (e.g. a95/// 4x vector interleaving mask would be <0, 2, 1, 3>).96static bool isInterleavingMask(ArrayRef<int> Mask);97 98/// Checks the given mask, and determines whether said mask is deinterleaving.99///100/// To be deinterleaving, a mask must increment in steps of 2, and either start101/// with 0 or 1.102/// (e.g. an 8x vector deinterleaving mask would be either <0, 2, 4, 6> or103/// <1, 3, 5, 7>).104static bool isDeinterleavingMask(ArrayRef<int> Mask);105 106/// Returns true if the operation is a negation of V, and it works for both107/// integers and floats.108static bool isNeg(Value *V);109 110/// Returns the operand for negation operation.111static Value *getNegOperand(Value *V);112 113namespace {114struct ComplexValue {115 Value *Real = nullptr;116 Value *Imag = nullptr;117 118 bool operator==(const ComplexValue &Other) const {119 return Real == Other.Real && Imag == Other.Imag;120 }121};122hash_code hash_value(const ComplexValue &Arg) {123 return hash_combine(DenseMapInfo<Value *>::getHashValue(Arg.Real),124 DenseMapInfo<Value *>::getHashValue(Arg.Imag));125}126} // end namespace127typedef SmallVector<struct ComplexValue, 2> ComplexValues;128 129template <> struct llvm::DenseMapInfo<ComplexValue> {130 static inline ComplexValue getEmptyKey() {131 return {DenseMapInfo<Value *>::getEmptyKey(),132 DenseMapInfo<Value *>::getEmptyKey()};133 }134 static inline ComplexValue getTombstoneKey() {135 return {DenseMapInfo<Value *>::getTombstoneKey(),136 DenseMapInfo<Value *>::getTombstoneKey()};137 }138 static unsigned getHashValue(const ComplexValue &Val) {139 return hash_combine(DenseMapInfo<Value *>::getHashValue(Val.Real),140 DenseMapInfo<Value *>::getHashValue(Val.Imag));141 }142 static bool isEqual(const ComplexValue &LHS, const ComplexValue &RHS) {143 return LHS.Real == RHS.Real && LHS.Imag == RHS.Imag;144 }145};146 147namespace {148template <typename T, typename IterT>149std::optional<T> findCommonBetweenCollections(IterT A, IterT B) {150 auto Common = llvm::find_if(A, [B](T I) { return llvm::is_contained(B, I); });151 if (Common != A.end())152 return std::make_optional(*Common);153 return std::nullopt;154}155 156class ComplexDeinterleavingLegacyPass : public FunctionPass {157public:158 static char ID;159 160 ComplexDeinterleavingLegacyPass(const TargetMachine *TM = nullptr)161 : FunctionPass(ID), TM(TM) {162 initializeComplexDeinterleavingLegacyPassPass(163 *PassRegistry::getPassRegistry());164 }165 166 StringRef getPassName() const override {167 return "Complex Deinterleaving Pass";168 }169 170 bool runOnFunction(Function &F) override;171 void getAnalysisUsage(AnalysisUsage &AU) const override {172 AU.addRequired<TargetLibraryInfoWrapperPass>();173 AU.setPreservesCFG();174 }175 176private:177 const TargetMachine *TM;178};179 180class ComplexDeinterleavingGraph;181struct ComplexDeinterleavingCompositeNode {182 183 ComplexDeinterleavingCompositeNode(ComplexDeinterleavingOperation Op,184 Value *R, Value *I)185 : Operation(Op) {186 Vals.push_back({R, I});187 }188 189 ComplexDeinterleavingCompositeNode(ComplexDeinterleavingOperation Op,190 ComplexValues &Other)191 : Operation(Op), Vals(Other) {}192 193private:194 friend class ComplexDeinterleavingGraph;195 using CompositeNode = ComplexDeinterleavingCompositeNode;196 bool OperandsValid = true;197 198public:199 ComplexDeinterleavingOperation Operation;200 ComplexValues Vals;201 202 // This two members are required exclusively for generating203 // ComplexDeinterleavingOperation::Symmetric operations.204 unsigned Opcode;205 std::optional<FastMathFlags> Flags;206 207 ComplexDeinterleavingRotation Rotation =208 ComplexDeinterleavingRotation::Rotation_0;209 SmallVector<CompositeNode *> Operands;210 Value *ReplacementNode = nullptr;211 212 void addOperand(CompositeNode *Node) {213 if (!Node)214 OperandsValid = false;215 Operands.push_back(Node);216 }217 218 void dump() { dump(dbgs()); }219 void dump(raw_ostream &OS) {220 auto PrintValue = [&](Value *V) {221 if (V) {222 OS << "\"";223 V->print(OS, true);224 OS << "\"\n";225 } else226 OS << "nullptr\n";227 };228 auto PrintNodeRef = [&](CompositeNode *Ptr) {229 if (Ptr)230 OS << Ptr << "\n";231 else232 OS << "nullptr\n";233 };234 235 OS << "- CompositeNode: " << this << "\n";236 for (unsigned I = 0; I < Vals.size(); I++) {237 OS << " Real(" << I << ") : ";238 PrintValue(Vals[I].Real);239 OS << " Imag(" << I << ") : ";240 PrintValue(Vals[I].Imag);241 }242 OS << " ReplacementNode: ";243 PrintValue(ReplacementNode);244 OS << " Operation: " << (int)Operation << "\n";245 OS << " Rotation: " << ((int)Rotation * 90) << "\n";246 OS << " Operands: \n";247 for (const auto &Op : Operands) {248 OS << " - ";249 PrintNodeRef(Op);250 }251 }252 253 bool areOperandsValid() { return OperandsValid; }254};255 256class ComplexDeinterleavingGraph {257public:258 struct Product {259 Value *Multiplier;260 Value *Multiplicand;261 bool IsPositive;262 };263 264 using Addend = std::pair<Value *, bool>;265 using AddendList = BumpPtrList<Addend>;266 using CompositeNode = ComplexDeinterleavingCompositeNode::CompositeNode;267 268 // Helper struct for holding info about potential partial multiplication269 // candidates270 struct PartialMulCandidate {271 Value *Common;272 CompositeNode *Node;273 unsigned RealIdx;274 unsigned ImagIdx;275 bool IsNodeInverted;276 };277 278 explicit ComplexDeinterleavingGraph(const TargetLowering *TL,279 const TargetLibraryInfo *TLI,280 unsigned Factor)281 : TL(TL), TLI(TLI), Factor(Factor) {}282 283private:284 const TargetLowering *TL = nullptr;285 const TargetLibraryInfo *TLI = nullptr;286 unsigned Factor;287 SmallVector<CompositeNode *> CompositeNodes;288 DenseMap<ComplexValues, CompositeNode *> CachedResult;289 SpecificBumpPtrAllocator<ComplexDeinterleavingCompositeNode> Allocator;290 291 SmallPtrSet<Instruction *, 16> FinalInstructions;292 293 /// Root instructions are instructions from which complex computation starts294 DenseMap<Instruction *, CompositeNode *> RootToNode;295 296 /// Topologically sorted root instructions297 SmallVector<Instruction *, 1> OrderedRoots;298 299 /// When examining a basic block for complex deinterleaving, if it is a simple300 /// one-block loop, then the only incoming block is 'Incoming' and the301 /// 'BackEdge' block is the block itself."302 BasicBlock *BackEdge = nullptr;303 BasicBlock *Incoming = nullptr;304 305 /// ReductionInfo maps from %ReductionOp to %PHInode and Instruction306 /// %OutsideUser as it is shown in the IR:307 ///308 /// vector.body:309 /// %PHInode = phi <vector type> [ zeroinitializer, %entry ],310 /// [ %ReductionOp, %vector.body ]311 /// ...312 /// %ReductionOp = fadd i64 ...313 /// ...314 /// br i1 %condition, label %vector.body, %middle.block315 ///316 /// middle.block:317 /// %OutsideUser = llvm.vector.reduce.fadd(..., %ReductionOp)318 ///319 /// %OutsideUser can be `llvm.vector.reduce.fadd` or `fadd` preceding320 /// `llvm.vector.reduce.fadd` when unroll factor isn't one.321 MapVector<Instruction *, std::pair<PHINode *, Instruction *>> ReductionInfo;322 323 /// In the process of detecting a reduction, we consider a pair of324 /// %ReductionOP, which we refer to as real and imag (or vice versa), and325 /// traverse the use-tree to detect complex operations. As this is a reduction326 /// operation, it will eventually reach RealPHI and ImagPHI, which corresponds327 /// to the %ReductionOPs that we suspect to be complex.328 /// RealPHI and ImagPHI are used by the identifyPHINode method.329 PHINode *RealPHI = nullptr;330 PHINode *ImagPHI = nullptr;331 332 /// Set this flag to true if RealPHI and ImagPHI were reached during reduction333 /// detection.334 bool PHIsFound = false;335 336 /// OldToNewPHI maps the original real PHINode to a new, double-sized PHINode.337 /// The new PHINode corresponds to a vector of deinterleaved complex numbers.338 /// This mapping is populated during339 /// ComplexDeinterleavingOperation::ReductionPHI node replacement. It is then340 /// used in the ComplexDeinterleavingOperation::ReductionOperation node341 /// replacement process.342 DenseMap<PHINode *, PHINode *> OldToNewPHI;343 344 CompositeNode *prepareCompositeNode(ComplexDeinterleavingOperation Operation,345 Value *R, Value *I) {346 assert(((Operation != ComplexDeinterleavingOperation::ReductionPHI &&347 Operation != ComplexDeinterleavingOperation::ReductionOperation) ||348 (R && I)) &&349 "Reduction related nodes must have Real and Imaginary parts");350 return new (Allocator.Allocate())351 ComplexDeinterleavingCompositeNode(Operation, R, I);352 }353 354 CompositeNode *prepareCompositeNode(ComplexDeinterleavingOperation Operation,355 ComplexValues &Vals) {356#ifndef NDEBUG357 for (auto &V : Vals) {358 assert(359 ((Operation != ComplexDeinterleavingOperation::ReductionPHI &&360 Operation != ComplexDeinterleavingOperation::ReductionOperation) ||361 (V.Real && V.Imag)) &&362 "Reduction related nodes must have Real and Imaginary parts");363 }364#endif365 return new (Allocator.Allocate())366 ComplexDeinterleavingCompositeNode(Operation, Vals);367 }368 369 CompositeNode *submitCompositeNode(CompositeNode *Node) {370 CompositeNodes.push_back(Node);371 if (Node->Vals[0].Real)372 CachedResult[Node->Vals] = Node;373 return Node;374 }375 376 /// Identifies a complex partial multiply pattern and its rotation, based on377 /// the following patterns378 ///379 /// 0: r: cr + ar * br380 /// i: ci + ar * bi381 /// 90: r: cr - ai * bi382 /// i: ci + ai * br383 /// 180: r: cr - ar * br384 /// i: ci - ar * bi385 /// 270: r: cr + ai * bi386 /// i: ci - ai * br387 CompositeNode *identifyPartialMul(Instruction *Real, Instruction *Imag);388 389 /// Identify the other branch of a Partial Mul, taking the CommonOperandI that390 /// is partially known from identifyPartialMul, filling in the other half of391 /// the complex pair.392 CompositeNode *393 identifyNodeWithImplicitAdd(Instruction *I, Instruction *J,394 std::pair<Value *, Value *> &CommonOperandI);395 396 /// Identifies a complex add pattern and its rotation, based on the following397 /// patterns.398 ///399 /// 90: r: ar - bi400 /// i: ai + br401 /// 270: r: ar + bi402 /// i: ai - br403 CompositeNode *identifyAdd(Instruction *Real, Instruction *Imag);404 CompositeNode *identifySymmetricOperation(ComplexValues &Vals);405 CompositeNode *identifyPartialReduction(Value *R, Value *I);406 CompositeNode *identifyDotProduct(Value *Inst);407 408 CompositeNode *identifyNode(ComplexValues &Vals);409 410 CompositeNode *identifyNode(Value *R, Value *I) {411 ComplexValues Vals;412 Vals.push_back({R, I});413 return identifyNode(Vals);414 }415 416 /// Determine if a sum of complex numbers can be formed from \p RealAddends417 /// and \p ImagAddens. If \p Accumulator is not null, add the result to it.418 /// Return nullptr if it is not possible to construct a complex number.419 /// \p Flags are needed to generate symmetric Add and Sub operations.420 CompositeNode *identifyAdditions(AddendList &RealAddends,421 AddendList &ImagAddends,422 std::optional<FastMathFlags> Flags,423 CompositeNode *Accumulator);424 425 /// Extract one addend that have both real and imaginary parts positive.426 CompositeNode *extractPositiveAddend(AddendList &RealAddends,427 AddendList &ImagAddends);428 429 /// Determine if sum of multiplications of complex numbers can be formed from430 /// \p RealMuls and \p ImagMuls. If \p Accumulator is not null, add the result431 /// to it. Return nullptr if it is not possible to construct a complex number.432 CompositeNode *identifyMultiplications(SmallVectorImpl<Product> &RealMuls,433 SmallVectorImpl<Product> &ImagMuls,434 CompositeNode *Accumulator);435 436 /// Go through pairs of multiplication (one Real and one Imag) and find all437 /// possible candidates for partial multiplication and put them into \p438 /// Candidates. Returns true if all Product has pair with common operand439 bool collectPartialMuls(ArrayRef<Product> RealMuls,440 ArrayRef<Product> ImagMuls,441 SmallVectorImpl<PartialMulCandidate> &Candidates);442 443 /// If the code is compiled with -Ofast or expressions have `reassoc` flag,444 /// the order of complex computation operations may be significantly altered,445 /// and the real and imaginary parts may not be executed in parallel. This446 /// function takes this into consideration and employs a more general approach447 /// to identify complex computations. Initially, it gathers all the addends448 /// and multiplicands and then constructs a complex expression from them.449 CompositeNode *identifyReassocNodes(Instruction *I, Instruction *J);450 451 CompositeNode *identifyRoot(Instruction *I);452 453 /// Identifies the Deinterleave operation applied to a vector containing454 /// complex numbers. There are two ways to represent the Deinterleave455 /// operation:456 /// * Using two shufflevectors with even indices for /pReal instruction and457 /// odd indices for /pImag instructions (only for fixed-width vectors)458 /// * Using N extractvalue instructions applied to `vector.deinterleaveN`459 /// intrinsics (for both fixed and scalable vectors) where N is a multiple of460 /// 2.461 CompositeNode *identifyDeinterleave(ComplexValues &Vals);462 463 /// identifying the operation that represents a complex number repeated in a464 /// Splat vector. There are two possible types of splats: ConstantExpr with465 /// the opcode ShuffleVector and ShuffleVectorInstr. Both should have an466 /// initialization mask with all values set to zero.467 CompositeNode *identifySplat(ComplexValues &Vals);468 469 CompositeNode *identifyPHINode(Instruction *Real, Instruction *Imag);470 471 /// Identifies SelectInsts in a loop that has reduction with predication masks472 /// and/or predicated tail folding473 CompositeNode *identifySelectNode(Instruction *Real, Instruction *Imag);474 475 Value *replaceNode(IRBuilderBase &Builder, CompositeNode *Node);476 477 /// Complete IR modifications after producing new reduction operation:478 /// * Populate the PHINode generated for479 /// ComplexDeinterleavingOperation::ReductionPHI480 /// * Deinterleave the final value outside of the loop and repurpose original481 /// reduction users482 void processReductionOperation(Value *OperationReplacement,483 CompositeNode *Node);484 void processReductionSingle(Value *OperationReplacement, CompositeNode *Node);485 486public:487 void dump() { dump(dbgs()); }488 void dump(raw_ostream &OS) {489 for (const auto &Node : CompositeNodes)490 Node->dump(OS);491 }492 493 /// Returns false if the deinterleaving operation should be cancelled for the494 /// current graph.495 bool identifyNodes(Instruction *RootI);496 497 /// In case \pB is one-block loop, this function seeks potential reductions498 /// and populates ReductionInfo. Returns true if any reductions were499 /// identified.500 bool collectPotentialReductions(BasicBlock *B);501 502 void identifyReductionNodes();503 504 /// Check that every instruction, from the roots to the leaves, has internal505 /// uses.506 bool checkNodes();507 508 /// Perform the actual replacement of the underlying instruction graph.509 void replaceNodes();510};511 512class ComplexDeinterleaving {513public:514 ComplexDeinterleaving(const TargetLowering *tl, const TargetLibraryInfo *tli)515 : TL(tl), TLI(tli) {}516 bool runOnFunction(Function &F);517 518private:519 bool evaluateBasicBlock(BasicBlock *B, unsigned Factor);520 521 const TargetLowering *TL = nullptr;522 const TargetLibraryInfo *TLI = nullptr;523};524 525} // namespace526 527char ComplexDeinterleavingLegacyPass::ID = 0;528 529INITIALIZE_PASS_BEGIN(ComplexDeinterleavingLegacyPass, DEBUG_TYPE,530 "Complex Deinterleaving", false, false)531INITIALIZE_PASS_END(ComplexDeinterleavingLegacyPass, DEBUG_TYPE,532 "Complex Deinterleaving", false, false)533 534PreservedAnalyses ComplexDeinterleavingPass::run(Function &F,535 FunctionAnalysisManager &AM) {536 const TargetLowering *TL = TM->getSubtargetImpl(F)->getTargetLowering();537 auto &TLI = AM.getResult<llvm::TargetLibraryAnalysis>(F);538 if (!ComplexDeinterleaving(TL, &TLI).runOnFunction(F))539 return PreservedAnalyses::all();540 541 PreservedAnalyses PA;542 PA.preserve<FunctionAnalysisManagerModuleProxy>();543 return PA;544}545 546FunctionPass *llvm::createComplexDeinterleavingPass(const TargetMachine *TM) {547 return new ComplexDeinterleavingLegacyPass(TM);548}549 550bool ComplexDeinterleavingLegacyPass::runOnFunction(Function &F) {551 const auto *TL = TM->getSubtargetImpl(F)->getTargetLowering();552 auto TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);553 return ComplexDeinterleaving(TL, &TLI).runOnFunction(F);554}555 556bool ComplexDeinterleaving::runOnFunction(Function &F) {557 if (!ComplexDeinterleavingEnabled) {558 LLVM_DEBUG(559 dbgs() << "Complex deinterleaving has been explicitly disabled.\n");560 return false;561 }562 563 if (!TL->isComplexDeinterleavingSupported()) {564 LLVM_DEBUG(565 dbgs() << "Complex deinterleaving has been disabled, target does "566 "not support lowering of complex number operations.\n");567 return false;568 }569 570 bool Changed = false;571 for (auto &B : F)572 Changed |= evaluateBasicBlock(&B, 2);573 574 // TODO: Permit changes for both interleave factors in the same function.575 if (!Changed) {576 for (auto &B : F)577 Changed |= evaluateBasicBlock(&B, 4);578 }579 580 // TODO: We can also support interleave factors of 6 and 8 if needed.581 582 return Changed;583}584 585static bool isInterleavingMask(ArrayRef<int> Mask) {586 // If the size is not even, it's not an interleaving mask587 if ((Mask.size() & 1))588 return false;589 590 int HalfNumElements = Mask.size() / 2;591 for (int Idx = 0; Idx < HalfNumElements; ++Idx) {592 int MaskIdx = Idx * 2;593 if (Mask[MaskIdx] != Idx || Mask[MaskIdx + 1] != (Idx + HalfNumElements))594 return false;595 }596 597 return true;598}599 600static bool isDeinterleavingMask(ArrayRef<int> Mask) {601 int Offset = Mask[0];602 int HalfNumElements = Mask.size() / 2;603 604 for (int Idx = 1; Idx < HalfNumElements; ++Idx) {605 if (Mask[Idx] != (Idx * 2) + Offset)606 return false;607 }608 609 return true;610}611 612bool isNeg(Value *V) {613 return match(V, m_FNeg(m_Value())) || match(V, m_Neg(m_Value()));614}615 616Value *getNegOperand(Value *V) {617 assert(isNeg(V));618 auto *I = cast<Instruction>(V);619 if (I->getOpcode() == Instruction::FNeg)620 return I->getOperand(0);621 622 return I->getOperand(1);623}624 625bool ComplexDeinterleaving::evaluateBasicBlock(BasicBlock *B, unsigned Factor) {626 ComplexDeinterleavingGraph Graph(TL, TLI, Factor);627 if (Graph.collectPotentialReductions(B))628 Graph.identifyReductionNodes();629 630 for (auto &I : *B)631 Graph.identifyNodes(&I);632 633 if (Graph.checkNodes()) {634 Graph.replaceNodes();635 return true;636 }637 638 return false;639}640 641ComplexDeinterleavingGraph::CompositeNode *642ComplexDeinterleavingGraph::identifyNodeWithImplicitAdd(643 Instruction *Real, Instruction *Imag,644 std::pair<Value *, Value *> &PartialMatch) {645 LLVM_DEBUG(dbgs() << "identifyNodeWithImplicitAdd " << *Real << " / " << *Imag646 << "\n");647 648 if (!Real->hasOneUse() || !Imag->hasOneUse()) {649 LLVM_DEBUG(dbgs() << " - Mul operand has multiple uses.\n");650 return nullptr;651 }652 653 if ((Real->getOpcode() != Instruction::FMul &&654 Real->getOpcode() != Instruction::Mul) ||655 (Imag->getOpcode() != Instruction::FMul &&656 Imag->getOpcode() != Instruction::Mul)) {657 LLVM_DEBUG(658 dbgs() << " - Real or imaginary instruction is not fmul or mul\n");659 return nullptr;660 }661 662 Value *R0 = Real->getOperand(0);663 Value *R1 = Real->getOperand(1);664 Value *I0 = Imag->getOperand(0);665 Value *I1 = Imag->getOperand(1);666 667 // A +/+ has a rotation of 0. If any of the operands are fneg, we flip the668 // rotations and use the operand.669 unsigned Negs = 0;670 Value *Op;671 if (match(R0, m_Neg(m_Value(Op)))) {672 Negs |= 1;673 R0 = Op;674 } else if (match(R1, m_Neg(m_Value(Op)))) {675 Negs |= 1;676 R1 = Op;677 }678 679 if (isNeg(I0)) {680 Negs |= 2;681 Negs ^= 1;682 I0 = Op;683 } else if (match(I1, m_Neg(m_Value(Op)))) {684 Negs |= 2;685 Negs ^= 1;686 I1 = Op;687 }688 689 ComplexDeinterleavingRotation Rotation = (ComplexDeinterleavingRotation)Negs;690 691 Value *CommonOperand;692 Value *UncommonRealOp;693 Value *UncommonImagOp;694 695 if (R0 == I0 || R0 == I1) {696 CommonOperand = R0;697 UncommonRealOp = R1;698 } else if (R1 == I0 || R1 == I1) {699 CommonOperand = R1;700 UncommonRealOp = R0;701 } else {702 LLVM_DEBUG(dbgs() << " - No equal operand\n");703 return nullptr;704 }705 706 UncommonImagOp = (CommonOperand == I0) ? I1 : I0;707 if (Rotation == ComplexDeinterleavingRotation::Rotation_90 ||708 Rotation == ComplexDeinterleavingRotation::Rotation_270)709 std::swap(UncommonRealOp, UncommonImagOp);710 711 // Between identifyPartialMul and here we need to have found a complete valid712 // pair from the CommonOperand of each part.713 if (Rotation == ComplexDeinterleavingRotation::Rotation_0 ||714 Rotation == ComplexDeinterleavingRotation::Rotation_180)715 PartialMatch.first = CommonOperand;716 else717 PartialMatch.second = CommonOperand;718 719 if (!PartialMatch.first || !PartialMatch.second) {720 LLVM_DEBUG(dbgs() << " - Incomplete partial match\n");721 return nullptr;722 }723 724 CompositeNode *CommonNode =725 identifyNode(PartialMatch.first, PartialMatch.second);726 if (!CommonNode) {727 LLVM_DEBUG(dbgs() << " - No CommonNode identified\n");728 return nullptr;729 }730 731 CompositeNode *UncommonNode = identifyNode(UncommonRealOp, UncommonImagOp);732 if (!UncommonNode) {733 LLVM_DEBUG(dbgs() << " - No UncommonNode identified\n");734 return nullptr;735 }736 737 CompositeNode *Node = prepareCompositeNode(738 ComplexDeinterleavingOperation::CMulPartial, Real, Imag);739 Node->Rotation = Rotation;740 Node->addOperand(CommonNode);741 Node->addOperand(UncommonNode);742 return submitCompositeNode(Node);743}744 745ComplexDeinterleavingGraph::CompositeNode *746ComplexDeinterleavingGraph::identifyPartialMul(Instruction *Real,747 Instruction *Imag) {748 LLVM_DEBUG(dbgs() << "identifyPartialMul " << *Real << " / " << *Imag749 << "\n");750 751 // Determine rotation752 auto IsAdd = [](unsigned Op) {753 return Op == Instruction::FAdd || Op == Instruction::Add;754 };755 auto IsSub = [](unsigned Op) {756 return Op == Instruction::FSub || Op == Instruction::Sub;757 };758 ComplexDeinterleavingRotation Rotation;759 if (IsAdd(Real->getOpcode()) && IsAdd(Imag->getOpcode()))760 Rotation = ComplexDeinterleavingRotation::Rotation_0;761 else if (IsSub(Real->getOpcode()) && IsAdd(Imag->getOpcode()))762 Rotation = ComplexDeinterleavingRotation::Rotation_90;763 else if (IsSub(Real->getOpcode()) && IsSub(Imag->getOpcode()))764 Rotation = ComplexDeinterleavingRotation::Rotation_180;765 else if (IsAdd(Real->getOpcode()) && IsSub(Imag->getOpcode()))766 Rotation = ComplexDeinterleavingRotation::Rotation_270;767 else {768 LLVM_DEBUG(dbgs() << " - Unhandled rotation.\n");769 return nullptr;770 }771 772 if (isa<FPMathOperator>(Real) &&773 (!Real->getFastMathFlags().allowContract() ||774 !Imag->getFastMathFlags().allowContract())) {775 LLVM_DEBUG(dbgs() << " - Contract is missing from the FastMath flags.\n");776 return nullptr;777 }778 779 Value *CR = Real->getOperand(0);780 Instruction *RealMulI = dyn_cast<Instruction>(Real->getOperand(1));781 if (!RealMulI)782 return nullptr;783 Value *CI = Imag->getOperand(0);784 Instruction *ImagMulI = dyn_cast<Instruction>(Imag->getOperand(1));785 if (!ImagMulI)786 return nullptr;787 788 if (!RealMulI->hasOneUse() || !ImagMulI->hasOneUse()) {789 LLVM_DEBUG(dbgs() << " - Mul instruction has multiple uses\n");790 return nullptr;791 }792 793 Value *R0 = RealMulI->getOperand(0);794 Value *R1 = RealMulI->getOperand(1);795 Value *I0 = ImagMulI->getOperand(0);796 Value *I1 = ImagMulI->getOperand(1);797 798 Value *CommonOperand;799 Value *UncommonRealOp;800 Value *UncommonImagOp;801 802 if (R0 == I0 || R0 == I1) {803 CommonOperand = R0;804 UncommonRealOp = R1;805 } else if (R1 == I0 || R1 == I1) {806 CommonOperand = R1;807 UncommonRealOp = R0;808 } else {809 LLVM_DEBUG(dbgs() << " - No equal operand\n");810 return nullptr;811 }812 813 UncommonImagOp = (CommonOperand == I0) ? I1 : I0;814 if (Rotation == ComplexDeinterleavingRotation::Rotation_90 ||815 Rotation == ComplexDeinterleavingRotation::Rotation_270)816 std::swap(UncommonRealOp, UncommonImagOp);817 818 std::pair<Value *, Value *> PartialMatch(819 (Rotation == ComplexDeinterleavingRotation::Rotation_0 ||820 Rotation == ComplexDeinterleavingRotation::Rotation_180)821 ? CommonOperand822 : nullptr,823 (Rotation == ComplexDeinterleavingRotation::Rotation_90 ||824 Rotation == ComplexDeinterleavingRotation::Rotation_270)825 ? CommonOperand826 : nullptr);827 828 auto *CRInst = dyn_cast<Instruction>(CR);829 auto *CIInst = dyn_cast<Instruction>(CI);830 831 if (!CRInst || !CIInst) {832 LLVM_DEBUG(dbgs() << " - Common operands are not instructions.\n");833 return nullptr;834 }835 836 CompositeNode *CNode =837 identifyNodeWithImplicitAdd(CRInst, CIInst, PartialMatch);838 if (!CNode) {839 LLVM_DEBUG(dbgs() << " - No cnode identified\n");840 return nullptr;841 }842 843 CompositeNode *UncommonRes = identifyNode(UncommonRealOp, UncommonImagOp);844 if (!UncommonRes) {845 LLVM_DEBUG(dbgs() << " - No UncommonRes identified\n");846 return nullptr;847 }848 849 assert(PartialMatch.first && PartialMatch.second);850 CompositeNode *CommonRes =851 identifyNode(PartialMatch.first, PartialMatch.second);852 if (!CommonRes) {853 LLVM_DEBUG(dbgs() << " - No CommonRes identified\n");854 return nullptr;855 }856 857 CompositeNode *Node = prepareCompositeNode(858 ComplexDeinterleavingOperation::CMulPartial, Real, Imag);859 Node->Rotation = Rotation;860 Node->addOperand(CommonRes);861 Node->addOperand(UncommonRes);862 Node->addOperand(CNode);863 return submitCompositeNode(Node);864}865 866ComplexDeinterleavingGraph::CompositeNode *867ComplexDeinterleavingGraph::identifyAdd(Instruction *Real, Instruction *Imag) {868 LLVM_DEBUG(dbgs() << "identifyAdd " << *Real << " / " << *Imag << "\n");869 870 // Determine rotation871 ComplexDeinterleavingRotation Rotation;872 if ((Real->getOpcode() == Instruction::FSub &&873 Imag->getOpcode() == Instruction::FAdd) ||874 (Real->getOpcode() == Instruction::Sub &&875 Imag->getOpcode() == Instruction::Add))876 Rotation = ComplexDeinterleavingRotation::Rotation_90;877 else if ((Real->getOpcode() == Instruction::FAdd &&878 Imag->getOpcode() == Instruction::FSub) ||879 (Real->getOpcode() == Instruction::Add &&880 Imag->getOpcode() == Instruction::Sub))881 Rotation = ComplexDeinterleavingRotation::Rotation_270;882 else {883 LLVM_DEBUG(dbgs() << " - Unhandled case, rotation is not assigned.\n");884 return nullptr;885 }886 887 auto *AR = dyn_cast<Instruction>(Real->getOperand(0));888 auto *BI = dyn_cast<Instruction>(Real->getOperand(1));889 auto *AI = dyn_cast<Instruction>(Imag->getOperand(0));890 auto *BR = dyn_cast<Instruction>(Imag->getOperand(1));891 892 if (!AR || !AI || !BR || !BI) {893 LLVM_DEBUG(dbgs() << " - Not all operands are instructions.\n");894 return nullptr;895 }896 897 CompositeNode *ResA = identifyNode(AR, AI);898 if (!ResA) {899 LLVM_DEBUG(dbgs() << " - AR/AI is not identified as a composite node.\n");900 return nullptr;901 }902 CompositeNode *ResB = identifyNode(BR, BI);903 if (!ResB) {904 LLVM_DEBUG(dbgs() << " - BR/BI is not identified as a composite node.\n");905 return nullptr;906 }907 908 CompositeNode *Node =909 prepareCompositeNode(ComplexDeinterleavingOperation::CAdd, Real, Imag);910 Node->Rotation = Rotation;911 Node->addOperand(ResA);912 Node->addOperand(ResB);913 return submitCompositeNode(Node);914}915 916static bool isInstructionPairAdd(Instruction *A, Instruction *B) {917 unsigned OpcA = A->getOpcode();918 unsigned OpcB = B->getOpcode();919 920 return (OpcA == Instruction::FSub && OpcB == Instruction::FAdd) ||921 (OpcA == Instruction::FAdd && OpcB == Instruction::FSub) ||922 (OpcA == Instruction::Sub && OpcB == Instruction::Add) ||923 (OpcA == Instruction::Add && OpcB == Instruction::Sub);924}925 926static bool isInstructionPairMul(Instruction *A, Instruction *B) {927 auto Pattern =928 m_BinOp(m_FMul(m_Value(), m_Value()), m_FMul(m_Value(), m_Value()));929 930 return match(A, Pattern) && match(B, Pattern);931}932 933static bool isInstructionPotentiallySymmetric(Instruction *I) {934 switch (I->getOpcode()) {935 case Instruction::FAdd:936 case Instruction::FSub:937 case Instruction::FMul:938 case Instruction::FNeg:939 case Instruction::Add:940 case Instruction::Sub:941 case Instruction::Mul:942 return true;943 default:944 return false;945 }946}947 948ComplexDeinterleavingGraph::CompositeNode *949ComplexDeinterleavingGraph::identifySymmetricOperation(ComplexValues &Vals) {950 auto *FirstReal = cast<Instruction>(Vals[0].Real);951 unsigned FirstOpc = FirstReal->getOpcode();952 for (auto &V : Vals) {953 auto *Real = cast<Instruction>(V.Real);954 auto *Imag = cast<Instruction>(V.Imag);955 if (Real->getOpcode() != FirstOpc || Imag->getOpcode() != FirstOpc)956 return nullptr;957 958 if (!isInstructionPotentiallySymmetric(Real) ||959 !isInstructionPotentiallySymmetric(Imag))960 return nullptr;961 962 if (isa<FPMathOperator>(FirstReal))963 if (Real->getFastMathFlags() != FirstReal->getFastMathFlags() ||964 Imag->getFastMathFlags() != FirstReal->getFastMathFlags())965 return nullptr;966 }967 968 ComplexValues OpVals;969 for (auto &V : Vals) {970 auto *R0 = cast<Instruction>(V.Real)->getOperand(0);971 auto *I0 = cast<Instruction>(V.Imag)->getOperand(0);972 OpVals.push_back({R0, I0});973 }974 975 CompositeNode *Op0 = identifyNode(OpVals);976 CompositeNode *Op1 = nullptr;977 if (Op0 == nullptr)978 return nullptr;979 980 if (FirstReal->isBinaryOp()) {981 OpVals.clear();982 for (auto &V : Vals) {983 auto *R1 = cast<Instruction>(V.Real)->getOperand(1);984 auto *I1 = cast<Instruction>(V.Imag)->getOperand(1);985 OpVals.push_back({R1, I1});986 }987 Op1 = identifyNode(OpVals);988 if (Op1 == nullptr)989 return nullptr;990 }991 992 auto Node =993 prepareCompositeNode(ComplexDeinterleavingOperation::Symmetric, Vals);994 Node->Opcode = FirstReal->getOpcode();995 if (isa<FPMathOperator>(FirstReal))996 Node->Flags = FirstReal->getFastMathFlags();997 998 Node->addOperand(Op0);999 if (FirstReal->isBinaryOp())1000 Node->addOperand(Op1);1001 1002 return submitCompositeNode(Node);1003}1004 1005ComplexDeinterleavingGraph::CompositeNode *1006ComplexDeinterleavingGraph::identifyDotProduct(Value *V) {1007 if (!TL->isComplexDeinterleavingOperationSupported(1008 ComplexDeinterleavingOperation::CDot, V->getType())) {1009 LLVM_DEBUG(dbgs() << "Target doesn't support complex deinterleaving "1010 "operation CDot with the type "1011 << *V->getType() << "\n");1012 return nullptr;1013 }1014 1015 auto *Inst = cast<Instruction>(V);1016 auto *RealUser = cast<Instruction>(*Inst->user_begin());1017 1018 CompositeNode *CN =1019 prepareCompositeNode(ComplexDeinterleavingOperation::CDot, Inst, nullptr);1020 1021 CompositeNode *ANode = nullptr;1022 1023 const Intrinsic::ID PartialReduceInt = Intrinsic::vector_partial_reduce_add;1024 1025 Value *AReal = nullptr;1026 Value *AImag = nullptr;1027 Value *BReal = nullptr;1028 Value *BImag = nullptr;1029 Value *Phi = nullptr;1030 1031 auto UnwrapCast = [](Value *V) -> Value * {1032 if (auto *CI = dyn_cast<CastInst>(V))1033 return CI->getOperand(0);1034 return V;1035 };1036 1037 auto PatternRot0 = m_Intrinsic<PartialReduceInt>(1038 m_Intrinsic<PartialReduceInt>(m_Value(Phi),1039 m_Mul(m_Value(BReal), m_Value(AReal))),1040 m_Neg(m_Mul(m_Value(BImag), m_Value(AImag))));1041 1042 auto PatternRot270 = m_Intrinsic<PartialReduceInt>(1043 m_Intrinsic<PartialReduceInt>(1044 m_Value(Phi), m_Neg(m_Mul(m_Value(BReal), m_Value(AImag)))),1045 m_Mul(m_Value(BImag), m_Value(AReal)));1046 1047 if (match(Inst, PatternRot0)) {1048 CN->Rotation = ComplexDeinterleavingRotation::Rotation_0;1049 } else if (match(Inst, PatternRot270)) {1050 CN->Rotation = ComplexDeinterleavingRotation::Rotation_270;1051 } else {1052 Value *A0, *A1;1053 // The rotations 90 and 180 share the same operation pattern, so inspect the1054 // order of the operands, identifying where the real and imaginary1055 // components of A go, to discern between the aforementioned rotations.1056 auto PatternRot90Rot180 = m_Intrinsic<PartialReduceInt>(1057 m_Intrinsic<PartialReduceInt>(m_Value(Phi),1058 m_Mul(m_Value(BReal), m_Value(A0))),1059 m_Mul(m_Value(BImag), m_Value(A1)));1060 1061 if (!match(Inst, PatternRot90Rot180))1062 return nullptr;1063 1064 A0 = UnwrapCast(A0);1065 A1 = UnwrapCast(A1);1066 1067 // Test if A0 is real/A1 is imag1068 ANode = identifyNode(A0, A1);1069 if (!ANode) {1070 // Test if A0 is imag/A1 is real1071 ANode = identifyNode(A1, A0);1072 // Unable to identify operand components, thus unable to identify rotation1073 if (!ANode)1074 return nullptr;1075 CN->Rotation = ComplexDeinterleavingRotation::Rotation_90;1076 AReal = A1;1077 AImag = A0;1078 } else {1079 AReal = A0;1080 AImag = A1;1081 CN->Rotation = ComplexDeinterleavingRotation::Rotation_180;1082 }1083 }1084 1085 AReal = UnwrapCast(AReal);1086 AImag = UnwrapCast(AImag);1087 BReal = UnwrapCast(BReal);1088 BImag = UnwrapCast(BImag);1089 1090 VectorType *VTy = cast<VectorType>(V->getType());1091 Type *ExpectedOperandTy = VectorType::getSubdividedVectorType(VTy, 2);1092 if (AReal->getType() != ExpectedOperandTy)1093 return nullptr;1094 if (AImag->getType() != ExpectedOperandTy)1095 return nullptr;1096 if (BReal->getType() != ExpectedOperandTy)1097 return nullptr;1098 if (BImag->getType() != ExpectedOperandTy)1099 return nullptr;1100 1101 if (Phi->getType() != VTy && RealUser->getType() != VTy)1102 return nullptr;1103 1104 CompositeNode *Node = identifyNode(AReal, AImag);1105 1106 // In the case that a node was identified to figure out the rotation, ensure1107 // that trying to identify a node with AReal and AImag post-unwrap results in1108 // the same node1109 if (ANode && Node != ANode) {1110 LLVM_DEBUG(1111 dbgs()1112 << "Identified node is different from previously identified node. "1113 "Unable to confidently generate a complex operation node\n");1114 return nullptr;1115 }1116 1117 CN->addOperand(Node);1118 CN->addOperand(identifyNode(BReal, BImag));1119 CN->addOperand(identifyNode(Phi, RealUser));1120 1121 return submitCompositeNode(CN);1122}1123 1124ComplexDeinterleavingGraph::CompositeNode *1125ComplexDeinterleavingGraph::identifyPartialReduction(Value *R, Value *I) {1126 // Partial reductions don't support non-vector types, so check these first1127 if (!isa<VectorType>(R->getType()) || !isa<VectorType>(I->getType()))1128 return nullptr;1129 1130 if (!R->hasUseList() || !I->hasUseList())1131 return nullptr;1132 1133 auto CommonUser =1134 findCommonBetweenCollections<Value *>(R->users(), I->users());1135 if (!CommonUser)1136 return nullptr;1137 1138 auto *IInst = dyn_cast<IntrinsicInst>(*CommonUser);1139 if (!IInst || IInst->getIntrinsicID() != Intrinsic::vector_partial_reduce_add)1140 return nullptr;1141 1142 if (CompositeNode *CN = identifyDotProduct(IInst))1143 return CN;1144 1145 return nullptr;1146}1147 1148ComplexDeinterleavingGraph::CompositeNode *1149ComplexDeinterleavingGraph::identifyNode(ComplexValues &Vals) {1150 auto It = CachedResult.find(Vals);1151 if (It != CachedResult.end()) {1152 LLVM_DEBUG(dbgs() << " - Folding to existing node\n");1153 return It->second;1154 }1155 1156 if (Vals.size() == 1) {1157 assert(Factor == 2 && "Can only handle interleave factors of 2");1158 Value *R = Vals[0].Real;1159 Value *I = Vals[0].Imag;1160 if (CompositeNode *CN = identifyPartialReduction(R, I))1161 return CN;1162 bool IsReduction = RealPHI == R && (!ImagPHI || ImagPHI == I);1163 if (!IsReduction && R->getType() != I->getType())1164 return nullptr;1165 }1166 1167 if (CompositeNode *CN = identifySplat(Vals))1168 return CN;1169 1170 for (auto &V : Vals) {1171 auto *Real = dyn_cast<Instruction>(V.Real);1172 auto *Imag = dyn_cast<Instruction>(V.Imag);1173 if (!Real || !Imag)1174 return nullptr;1175 }1176 1177 if (CompositeNode *CN = identifyDeinterleave(Vals))1178 return CN;1179 1180 if (Vals.size() == 1) {1181 assert(Factor == 2 && "Can only handle interleave factors of 2");1182 auto *Real = dyn_cast<Instruction>(Vals[0].Real);1183 auto *Imag = dyn_cast<Instruction>(Vals[0].Imag);1184 if (CompositeNode *CN = identifyPHINode(Real, Imag))1185 return CN;1186 1187 if (CompositeNode *CN = identifySelectNode(Real, Imag))1188 return CN;1189 1190 auto *VTy = cast<VectorType>(Real->getType());1191 auto *NewVTy = VectorType::getDoubleElementsVectorType(VTy);1192 1193 bool HasCMulSupport = TL->isComplexDeinterleavingOperationSupported(1194 ComplexDeinterleavingOperation::CMulPartial, NewVTy);1195 bool HasCAddSupport = TL->isComplexDeinterleavingOperationSupported(1196 ComplexDeinterleavingOperation::CAdd, NewVTy);1197 1198 if (HasCMulSupport && isInstructionPairMul(Real, Imag)) {1199 if (CompositeNode *CN = identifyPartialMul(Real, Imag))1200 return CN;1201 }1202 1203 if (HasCAddSupport && isInstructionPairAdd(Real, Imag)) {1204 if (CompositeNode *CN = identifyAdd(Real, Imag))1205 return CN;1206 }1207 1208 if (HasCMulSupport && HasCAddSupport) {1209 if (CompositeNode *CN = identifyReassocNodes(Real, Imag)) {1210 return CN;1211 }1212 }1213 }1214 1215 if (CompositeNode *CN = identifySymmetricOperation(Vals))1216 return CN;1217 1218 LLVM_DEBUG(dbgs() << " - Not recognised as a valid pattern.\n");1219 CachedResult[Vals] = nullptr;1220 return nullptr;1221}1222 1223ComplexDeinterleavingGraph::CompositeNode *1224ComplexDeinterleavingGraph::identifyReassocNodes(Instruction *Real,1225 Instruction *Imag) {1226 auto IsOperationSupported = [](unsigned Opcode) -> bool {1227 return Opcode == Instruction::FAdd || Opcode == Instruction::FSub ||1228 Opcode == Instruction::FNeg || Opcode == Instruction::Add ||1229 Opcode == Instruction::Sub;1230 };1231 1232 if (!IsOperationSupported(Real->getOpcode()) ||1233 !IsOperationSupported(Imag->getOpcode()))1234 return nullptr;1235 1236 std::optional<FastMathFlags> Flags;1237 if (isa<FPMathOperator>(Real)) {1238 if (Real->getFastMathFlags() != Imag->getFastMathFlags()) {1239 LLVM_DEBUG(dbgs() << "The flags in Real and Imaginary instructions are "1240 "not identical\n");1241 return nullptr;1242 }1243 1244 Flags = Real->getFastMathFlags();1245 if (!Flags->allowReassoc()) {1246 LLVM_DEBUG(1247 dbgs()1248 << "the 'Reassoc' attribute is missing in the FastMath flags\n");1249 return nullptr;1250 }1251 }1252 1253 // Collect multiplications and addend instructions from the given instruction1254 // while traversing it operands. Additionally, verify that all instructions1255 // have the same fast math flags.1256 auto Collect = [&Flags](Instruction *Insn, SmallVectorImpl<Product> &Muls,1257 AddendList &Addends) -> bool {1258 SmallVector<PointerIntPair<Value *, 1, bool>> Worklist = {{Insn, true}};1259 SmallPtrSet<Value *, 8> Visited;1260 while (!Worklist.empty()) {1261 auto [V, IsPositive] = Worklist.pop_back_val();1262 if (!Visited.insert(V).second)1263 continue;1264 1265 Instruction *I = dyn_cast<Instruction>(V);1266 if (!I) {1267 Addends.emplace_back(V, IsPositive);1268 continue;1269 }1270 1271 // If an instruction has more than one user, it indicates that it either1272 // has an external user, which will be later checked by the checkNodes1273 // function, or it is a subexpression utilized by multiple expressions. In1274 // the latter case, we will attempt to separately identify the complex1275 // operation from here in order to create a shared1276 // ComplexDeinterleavingCompositeNode.1277 if (I != Insn && I->hasNUsesOrMore(2)) {1278 LLVM_DEBUG(dbgs() << "Found potential sub-expression: " << *I << "\n");1279 Addends.emplace_back(I, IsPositive);1280 continue;1281 }1282 switch (I->getOpcode()) {1283 case Instruction::FAdd:1284 case Instruction::Add:1285 Worklist.emplace_back(I->getOperand(1), IsPositive);1286 Worklist.emplace_back(I->getOperand(0), IsPositive);1287 break;1288 case Instruction::FSub:1289 Worklist.emplace_back(I->getOperand(1), !IsPositive);1290 Worklist.emplace_back(I->getOperand(0), IsPositive);1291 break;1292 case Instruction::Sub:1293 if (isNeg(I)) {1294 Worklist.emplace_back(getNegOperand(I), !IsPositive);1295 } else {1296 Worklist.emplace_back(I->getOperand(1), !IsPositive);1297 Worklist.emplace_back(I->getOperand(0), IsPositive);1298 }1299 break;1300 case Instruction::FMul:1301 case Instruction::Mul: {1302 Value *A, *B;1303 if (isNeg(I->getOperand(0))) {1304 A = getNegOperand(I->getOperand(0));1305 IsPositive = !IsPositive;1306 } else {1307 A = I->getOperand(0);1308 }1309 1310 if (isNeg(I->getOperand(1))) {1311 B = getNegOperand(I->getOperand(1));1312 IsPositive = !IsPositive;1313 } else {1314 B = I->getOperand(1);1315 }1316 Muls.push_back(Product{A, B, IsPositive});1317 break;1318 }1319 case Instruction::FNeg:1320 Worklist.emplace_back(I->getOperand(0), !IsPositive);1321 break;1322 default:1323 Addends.emplace_back(I, IsPositive);1324 continue;1325 }1326 1327 if (Flags && I->getFastMathFlags() != *Flags) {1328 LLVM_DEBUG(dbgs() << "The instruction's fast math flags are "1329 "inconsistent with the root instructions' flags: "1330 << *I << "\n");1331 return false;1332 }1333 }1334 return true;1335 };1336 1337 SmallVector<Product> RealMuls, ImagMuls;1338 AddendList RealAddends, ImagAddends;1339 if (!Collect(Real, RealMuls, RealAddends) ||1340 !Collect(Imag, ImagMuls, ImagAddends))1341 return nullptr;1342 1343 if (RealAddends.size() != ImagAddends.size())1344 return nullptr;1345 1346 CompositeNode *FinalNode = nullptr;1347 if (!RealMuls.empty() || !ImagMuls.empty()) {1348 // If there are multiplicands, extract positive addend and use it as an1349 // accumulator1350 FinalNode = extractPositiveAddend(RealAddends, ImagAddends);1351 FinalNode = identifyMultiplications(RealMuls, ImagMuls, FinalNode);1352 if (!FinalNode)1353 return nullptr;1354 }1355 1356 // Identify and process remaining additions1357 if (!RealAddends.empty() || !ImagAddends.empty()) {1358 FinalNode = identifyAdditions(RealAddends, ImagAddends, Flags, FinalNode);1359 if (!FinalNode)1360 return nullptr;1361 }1362 assert(FinalNode && "FinalNode can not be nullptr here");1363 assert(FinalNode->Vals.size() == 1);1364 // Set the Real and Imag fields of the final node and submit it1365 FinalNode->Vals[0].Real = Real;1366 FinalNode->Vals[0].Imag = Imag;1367 submitCompositeNode(FinalNode);1368 return FinalNode;1369}1370 1371bool ComplexDeinterleavingGraph::collectPartialMuls(1372 ArrayRef<Product> RealMuls, ArrayRef<Product> ImagMuls,1373 SmallVectorImpl<PartialMulCandidate> &PartialMulCandidates) {1374 // Helper function to extract a common operand from two products1375 auto FindCommonInstruction = [](const Product &Real,1376 const Product &Imag) -> Value * {1377 if (Real.Multiplicand == Imag.Multiplicand ||1378 Real.Multiplicand == Imag.Multiplier)1379 return Real.Multiplicand;1380 1381 if (Real.Multiplier == Imag.Multiplicand ||1382 Real.Multiplier == Imag.Multiplier)1383 return Real.Multiplier;1384 1385 return nullptr;1386 };1387 1388 // Iterating over real and imaginary multiplications to find common operands1389 // If a common operand is found, a partial multiplication candidate is created1390 // and added to the candidates vector The function returns false if no common1391 // operands are found for any product1392 for (unsigned i = 0; i < RealMuls.size(); ++i) {1393 bool FoundCommon = false;1394 for (unsigned j = 0; j < ImagMuls.size(); ++j) {1395 auto *Common = FindCommonInstruction(RealMuls[i], ImagMuls[j]);1396 if (!Common)1397 continue;1398 1399 auto *A = RealMuls[i].Multiplicand == Common ? RealMuls[i].Multiplier1400 : RealMuls[i].Multiplicand;1401 auto *B = ImagMuls[j].Multiplicand == Common ? ImagMuls[j].Multiplier1402 : ImagMuls[j].Multiplicand;1403 1404 auto Node = identifyNode(A, B);1405 if (Node) {1406 FoundCommon = true;1407 PartialMulCandidates.push_back({Common, Node, i, j, false});1408 }1409 1410 Node = identifyNode(B, A);1411 if (Node) {1412 FoundCommon = true;1413 PartialMulCandidates.push_back({Common, Node, i, j, true});1414 }1415 }1416 if (!FoundCommon)1417 return false;1418 }1419 return true;1420}1421 1422ComplexDeinterleavingGraph::CompositeNode *1423ComplexDeinterleavingGraph::identifyMultiplications(1424 SmallVectorImpl<Product> &RealMuls, SmallVectorImpl<Product> &ImagMuls,1425 CompositeNode *Accumulator = nullptr) {1426 if (RealMuls.size() != ImagMuls.size())1427 return nullptr;1428 1429 SmallVector<PartialMulCandidate> Info;1430 if (!collectPartialMuls(RealMuls, ImagMuls, Info))1431 return nullptr;1432 1433 // Map to store common instruction to node pointers1434 DenseMap<Value *, CompositeNode *> CommonToNode;1435 SmallVector<bool> Processed(Info.size(), false);1436 for (unsigned I = 0; I < Info.size(); ++I) {1437 if (Processed[I])1438 continue;1439 1440 PartialMulCandidate &InfoA = Info[I];1441 for (unsigned J = I + 1; J < Info.size(); ++J) {1442 if (Processed[J])1443 continue;1444 1445 PartialMulCandidate &InfoB = Info[J];1446 auto *InfoReal = &InfoA;1447 auto *InfoImag = &InfoB;1448 1449 auto NodeFromCommon = identifyNode(InfoReal->Common, InfoImag->Common);1450 if (!NodeFromCommon) {1451 std::swap(InfoReal, InfoImag);1452 NodeFromCommon = identifyNode(InfoReal->Common, InfoImag->Common);1453 }1454 if (!NodeFromCommon)1455 continue;1456 1457 CommonToNode[InfoReal->Common] = NodeFromCommon;1458 CommonToNode[InfoImag->Common] = NodeFromCommon;1459 Processed[I] = true;1460 Processed[J] = true;1461 }1462 }1463 1464 SmallVector<bool> ProcessedReal(RealMuls.size(), false);1465 SmallVector<bool> ProcessedImag(ImagMuls.size(), false);1466 CompositeNode *Result = Accumulator;1467 for (auto &PMI : Info) {1468 if (ProcessedReal[PMI.RealIdx] || ProcessedImag[PMI.ImagIdx])1469 continue;1470 1471 auto It = CommonToNode.find(PMI.Common);1472 // TODO: Process independent complex multiplications. Cases like this:1473 // A.real() * B where both A and B are complex numbers.1474 if (It == CommonToNode.end()) {1475 LLVM_DEBUG({1476 dbgs() << "Unprocessed independent partial multiplication:\n";1477 for (auto *Mul : {&RealMuls[PMI.RealIdx], &RealMuls[PMI.RealIdx]})1478 dbgs().indent(4) << (Mul->IsPositive ? "+" : "-") << *Mul->Multiplier1479 << " multiplied by " << *Mul->Multiplicand << "\n";1480 });1481 return nullptr;1482 }1483 1484 auto &RealMul = RealMuls[PMI.RealIdx];1485 auto &ImagMul = ImagMuls[PMI.ImagIdx];1486 1487 auto NodeA = It->second;1488 auto NodeB = PMI.Node;1489 auto IsMultiplicandReal = PMI.Common == NodeA->Vals[0].Real;1490 // The following table illustrates the relationship between multiplications1491 // and rotations. If we consider the multiplication (X + iY) * (U + iV), we1492 // can see:1493 //1494 // Rotation | Real | Imag |1495 // ---------+--------+--------+1496 // 0 | x * u | x * v |1497 // 90 | -y * v | y * u |1498 // 180 | -x * u | -x * v |1499 // 270 | y * v | -y * u |1500 //1501 // Check if the candidate can indeed be represented by partial1502 // multiplication1503 // TODO: Add support for multiplication by complex one1504 if ((IsMultiplicandReal && PMI.IsNodeInverted) ||1505 (!IsMultiplicandReal && !PMI.IsNodeInverted))1506 continue;1507 1508 // Determine the rotation based on the multiplications1509 ComplexDeinterleavingRotation Rotation;1510 if (IsMultiplicandReal) {1511 // Detect 0 and 180 degrees rotation1512 if (RealMul.IsPositive && ImagMul.IsPositive)1513 Rotation = llvm::ComplexDeinterleavingRotation::Rotation_0;1514 else if (!RealMul.IsPositive && !ImagMul.IsPositive)1515 Rotation = llvm::ComplexDeinterleavingRotation::Rotation_180;1516 else1517 continue;1518 1519 } else {1520 // Detect 90 and 270 degrees rotation1521 if (!RealMul.IsPositive && ImagMul.IsPositive)1522 Rotation = llvm::ComplexDeinterleavingRotation::Rotation_90;1523 else if (RealMul.IsPositive && !ImagMul.IsPositive)1524 Rotation = llvm::ComplexDeinterleavingRotation::Rotation_270;1525 else1526 continue;1527 }1528 1529 LLVM_DEBUG({1530 dbgs() << "Identified partial multiplication (X, Y) * (U, V):\n";1531 dbgs().indent(4) << "X: " << *NodeA->Vals[0].Real << "\n";1532 dbgs().indent(4) << "Y: " << *NodeA->Vals[0].Imag << "\n";1533 dbgs().indent(4) << "U: " << *NodeB->Vals[0].Real << "\n";1534 dbgs().indent(4) << "V: " << *NodeB->Vals[0].Imag << "\n";1535 dbgs().indent(4) << "Rotation - " << (int)Rotation * 90 << "\n";1536 });1537 1538 CompositeNode *NodeMul = prepareCompositeNode(1539 ComplexDeinterleavingOperation::CMulPartial, nullptr, nullptr);1540 NodeMul->Rotation = Rotation;1541 NodeMul->addOperand(NodeA);1542 NodeMul->addOperand(NodeB);1543 if (Result)1544 NodeMul->addOperand(Result);1545 submitCompositeNode(NodeMul);1546 Result = NodeMul;1547 ProcessedReal[PMI.RealIdx] = true;1548 ProcessedImag[PMI.ImagIdx] = true;1549 }1550 1551 // Ensure all products have been processed, if not return nullptr.1552 if (!all_of(ProcessedReal, [](bool V) { return V; }) ||1553 !all_of(ProcessedImag, [](bool V) { return V; })) {1554 1555 // Dump debug information about which partial multiplications are not1556 // processed.1557 LLVM_DEBUG({1558 dbgs() << "Unprocessed products (Real):\n";1559 for (size_t i = 0; i < ProcessedReal.size(); ++i) {1560 if (!ProcessedReal[i])1561 dbgs().indent(4) << (RealMuls[i].IsPositive ? "+" : "-")1562 << *RealMuls[i].Multiplier << " multiplied by "1563 << *RealMuls[i].Multiplicand << "\n";1564 }1565 dbgs() << "Unprocessed products (Imag):\n";1566 for (size_t i = 0; i < ProcessedImag.size(); ++i) {1567 if (!ProcessedImag[i])1568 dbgs().indent(4) << (ImagMuls[i].IsPositive ? "+" : "-")1569 << *ImagMuls[i].Multiplier << " multiplied by "1570 << *ImagMuls[i].Multiplicand << "\n";1571 }1572 });1573 return nullptr;1574 }1575 1576 return Result;1577}1578 1579ComplexDeinterleavingGraph::CompositeNode *1580ComplexDeinterleavingGraph::identifyAdditions(1581 AddendList &RealAddends, AddendList &ImagAddends,1582 std::optional<FastMathFlags> Flags, CompositeNode *Accumulator = nullptr) {1583 if (RealAddends.size() != ImagAddends.size())1584 return nullptr;1585 1586 CompositeNode *Result = nullptr;1587 // If we have accumulator use it as first addend1588 if (Accumulator)1589 Result = Accumulator;1590 // Otherwise find an element with both positive real and imaginary parts.1591 else1592 Result = extractPositiveAddend(RealAddends, ImagAddends);1593 1594 if (!Result)1595 return nullptr;1596 1597 while (!RealAddends.empty()) {1598 auto ItR = RealAddends.begin();1599 auto [R, IsPositiveR] = *ItR;1600 1601 bool FoundImag = false;1602 for (auto ItI = ImagAddends.begin(); ItI != ImagAddends.end(); ++ItI) {1603 auto [I, IsPositiveI] = *ItI;1604 ComplexDeinterleavingRotation Rotation;1605 if (IsPositiveR && IsPositiveI)1606 Rotation = ComplexDeinterleavingRotation::Rotation_0;1607 else if (!IsPositiveR && IsPositiveI)1608 Rotation = ComplexDeinterleavingRotation::Rotation_90;1609 else if (!IsPositiveR && !IsPositiveI)1610 Rotation = ComplexDeinterleavingRotation::Rotation_180;1611 else1612 Rotation = ComplexDeinterleavingRotation::Rotation_270;1613 1614 CompositeNode *AddNode = nullptr;1615 if (Rotation == ComplexDeinterleavingRotation::Rotation_0 ||1616 Rotation == ComplexDeinterleavingRotation::Rotation_180) {1617 AddNode = identifyNode(R, I);1618 } else {1619 AddNode = identifyNode(I, R);1620 }1621 if (AddNode) {1622 LLVM_DEBUG({1623 dbgs() << "Identified addition:\n";1624 dbgs().indent(4) << "X: " << *R << "\n";1625 dbgs().indent(4) << "Y: " << *I << "\n";1626 dbgs().indent(4) << "Rotation - " << (int)Rotation * 90 << "\n";1627 });1628 1629 CompositeNode *TmpNode = nullptr;1630 if (Rotation == llvm::ComplexDeinterleavingRotation::Rotation_0) {1631 TmpNode = prepareCompositeNode(1632 ComplexDeinterleavingOperation::Symmetric, nullptr, nullptr);1633 if (Flags) {1634 TmpNode->Opcode = Instruction::FAdd;1635 TmpNode->Flags = *Flags;1636 } else {1637 TmpNode->Opcode = Instruction::Add;1638 }1639 } else if (Rotation ==1640 llvm::ComplexDeinterleavingRotation::Rotation_180) {1641 TmpNode = prepareCompositeNode(1642 ComplexDeinterleavingOperation::Symmetric, nullptr, nullptr);1643 if (Flags) {1644 TmpNode->Opcode = Instruction::FSub;1645 TmpNode->Flags = *Flags;1646 } else {1647 TmpNode->Opcode = Instruction::Sub;1648 }1649 } else {1650 TmpNode = prepareCompositeNode(ComplexDeinterleavingOperation::CAdd,1651 nullptr, nullptr);1652 TmpNode->Rotation = Rotation;1653 }1654 1655 TmpNode->addOperand(Result);1656 TmpNode->addOperand(AddNode);1657 submitCompositeNode(TmpNode);1658 Result = TmpNode;1659 RealAddends.erase(ItR);1660 ImagAddends.erase(ItI);1661 FoundImag = true;1662 break;1663 }1664 }1665 if (!FoundImag)1666 return nullptr;1667 }1668 return Result;1669}1670 1671ComplexDeinterleavingGraph::CompositeNode *1672ComplexDeinterleavingGraph::extractPositiveAddend(AddendList &RealAddends,1673 AddendList &ImagAddends) {1674 for (auto ItR = RealAddends.begin(); ItR != RealAddends.end(); ++ItR) {1675 for (auto ItI = ImagAddends.begin(); ItI != ImagAddends.end(); ++ItI) {1676 auto [R, IsPositiveR] = *ItR;1677 auto [I, IsPositiveI] = *ItI;1678 if (IsPositiveR && IsPositiveI) {1679 auto Result = identifyNode(R, I);1680 if (Result) {1681 RealAddends.erase(ItR);1682 ImagAddends.erase(ItI);1683 return Result;1684 }1685 }1686 }1687 }1688 return nullptr;1689}1690 1691bool ComplexDeinterleavingGraph::identifyNodes(Instruction *RootI) {1692 // This potential root instruction might already have been recognized as1693 // reduction. Because RootToNode maps both Real and Imaginary parts to1694 // CompositeNode we should choose only one either Real or Imag instruction to1695 // use as an anchor for generating complex instruction.1696 auto It = RootToNode.find(RootI);1697 if (It != RootToNode.end()) {1698 auto RootNode = It->second;1699 assert(RootNode->Operation ==1700 ComplexDeinterleavingOperation::ReductionOperation ||1701 RootNode->Operation ==1702 ComplexDeinterleavingOperation::ReductionSingle);1703 assert(RootNode->Vals.size() == 1 &&1704 "Cannot handle reductions involving multiple complex values");1705 // Find out which part, Real or Imag, comes later, and only if we come to1706 // the latest part, add it to OrderedRoots.1707 auto *R = cast<Instruction>(RootNode->Vals[0].Real);1708 auto *I = RootNode->Vals[0].Imag ? cast<Instruction>(RootNode->Vals[0].Imag)1709 : nullptr;1710 1711 Instruction *ReplacementAnchor;1712 if (I)1713 ReplacementAnchor = R->comesBefore(I) ? I : R;1714 else1715 ReplacementAnchor = R;1716 1717 if (ReplacementAnchor != RootI)1718 return false;1719 OrderedRoots.push_back(RootI);1720 return true;1721 }1722 1723 auto RootNode = identifyRoot(RootI);1724 if (!RootNode)1725 return false;1726 1727 LLVM_DEBUG({1728 Function *F = RootI->getFunction();1729 BasicBlock *B = RootI->getParent();1730 dbgs() << "Complex deinterleaving graph for " << F->getName()1731 << "::" << B->getName() << ".\n";1732 dump(dbgs());1733 dbgs() << "\n";1734 });1735 RootToNode[RootI] = RootNode;1736 OrderedRoots.push_back(RootI);1737 return true;1738}1739 1740bool ComplexDeinterleavingGraph::collectPotentialReductions(BasicBlock *B) {1741 bool FoundPotentialReduction = false;1742 if (Factor != 2)1743 return false;1744 1745 auto *Br = dyn_cast<BranchInst>(B->getTerminator());1746 if (!Br || Br->getNumSuccessors() != 2)1747 return false;1748 1749 // Identify simple one-block loop1750 if (Br->getSuccessor(0) != B && Br->getSuccessor(1) != B)1751 return false;1752 1753 for (auto &PHI : B->phis()) {1754 if (PHI.getNumIncomingValues() != 2)1755 continue;1756 1757 if (!PHI.getType()->isVectorTy())1758 continue;1759 1760 auto *ReductionOp = dyn_cast<Instruction>(PHI.getIncomingValueForBlock(B));1761 if (!ReductionOp)1762 continue;1763 1764 // Check if final instruction is reduced outside of current block1765 Instruction *FinalReduction = nullptr;1766 auto NumUsers = 0u;1767 for (auto *U : ReductionOp->users()) {1768 ++NumUsers;1769 if (U == &PHI)1770 continue;1771 FinalReduction = dyn_cast<Instruction>(U);1772 }1773 1774 if (NumUsers != 2 || !FinalReduction || FinalReduction->getParent() == B ||1775 isa<PHINode>(FinalReduction))1776 continue;1777 1778 ReductionInfo[ReductionOp] = {&PHI, FinalReduction};1779 BackEdge = B;1780 auto BackEdgeIdx = PHI.getBasicBlockIndex(B);1781 auto IncomingIdx = BackEdgeIdx == 0 ? 1 : 0;1782 Incoming = PHI.getIncomingBlock(IncomingIdx);1783 FoundPotentialReduction = true;1784 1785 // If the initial value of PHINode is an Instruction, consider it a leaf1786 // value of a complex deinterleaving graph.1787 if (auto *InitPHI =1788 dyn_cast<Instruction>(PHI.getIncomingValueForBlock(Incoming)))1789 FinalInstructions.insert(InitPHI);1790 }1791 return FoundPotentialReduction;1792}1793 1794void ComplexDeinterleavingGraph::identifyReductionNodes() {1795 assert(Factor == 2 && "Cannot handle multiple complex values");1796 1797 SmallVector<bool> Processed(ReductionInfo.size(), false);1798 SmallVector<Instruction *> OperationInstruction;1799 for (auto &P : ReductionInfo)1800 OperationInstruction.push_back(P.first);1801 1802 // Identify a complex computation by evaluating two reduction operations that1803 // potentially could be involved1804 for (size_t i = 0; i < OperationInstruction.size(); ++i) {1805 if (Processed[i])1806 continue;1807 for (size_t j = i + 1; j < OperationInstruction.size(); ++j) {1808 if (Processed[j])1809 continue;1810 auto *Real = OperationInstruction[i];1811 auto *Imag = OperationInstruction[j];1812 if (Real->getType() != Imag->getType())1813 continue;1814 1815 RealPHI = ReductionInfo[Real].first;1816 ImagPHI = ReductionInfo[Imag].first;1817 PHIsFound = false;1818 auto Node = identifyNode(Real, Imag);1819 if (!Node) {1820 std::swap(Real, Imag);1821 std::swap(RealPHI, ImagPHI);1822 Node = identifyNode(Real, Imag);1823 }1824 1825 // If a node is identified and reduction PHINode is used in the chain of1826 // operations, mark its operation instructions as used to prevent1827 // re-identification and attach the node to the real part1828 if (Node && PHIsFound) {1829 LLVM_DEBUG(dbgs() << "Identified reduction starting from instructions: "1830 << *Real << " / " << *Imag << "\n");1831 Processed[i] = true;1832 Processed[j] = true;1833 auto RootNode = prepareCompositeNode(1834 ComplexDeinterleavingOperation::ReductionOperation, Real, Imag);1835 RootNode->addOperand(Node);1836 RootToNode[Real] = RootNode;1837 RootToNode[Imag] = RootNode;1838 submitCompositeNode(RootNode);1839 break;1840 }1841 }1842 1843 auto *Real = OperationInstruction[i];1844 // We want to check that we have 2 operands, but the function attributes1845 // being counted as operands bloats this value.1846 if (Processed[i] || Real->getNumOperands() < 2)1847 continue;1848 1849 // Can only combined integer reductions at the moment.1850 if (!ReductionInfo[Real].second->getType()->isIntegerTy())1851 continue;1852 1853 RealPHI = ReductionInfo[Real].first;1854 ImagPHI = nullptr;1855 PHIsFound = false;1856 auto Node = identifyNode(Real->getOperand(0), Real->getOperand(1));1857 if (Node && PHIsFound) {1858 LLVM_DEBUG(1859 dbgs() << "Identified single reduction starting from instruction: "1860 << *Real << "/" << *ReductionInfo[Real].second << "\n");1861 1862 // Reducing to a single vector is not supported, only permit reducing down1863 // to scalar values.1864 // Doing this here will leave the prior node in the graph,1865 // however with no uses the node will be unreachable by the replacement1866 // process. That along with the usage outside the graph should prevent the1867 // replacement process from kicking off at all for this graph.1868 // TODO Add support for reducing to a single vector value1869 if (ReductionInfo[Real].second->getType()->isVectorTy())1870 continue;1871 1872 Processed[i] = true;1873 auto RootNode = prepareCompositeNode(1874 ComplexDeinterleavingOperation::ReductionSingle, Real, nullptr);1875 RootNode->addOperand(Node);1876 RootToNode[Real] = RootNode;1877 submitCompositeNode(RootNode);1878 }1879 }1880 1881 RealPHI = nullptr;1882 ImagPHI = nullptr;1883}1884 1885bool ComplexDeinterleavingGraph::checkNodes() {1886 bool FoundDeinterleaveNode = false;1887 for (CompositeNode *N : CompositeNodes) {1888 if (!N->areOperandsValid())1889 return false;1890 1891 if (N->Operation == ComplexDeinterleavingOperation::Deinterleave)1892 FoundDeinterleaveNode = true;1893 }1894 1895 // We need a deinterleave node in order to guarantee that we're working with1896 // complex numbers.1897 if (!FoundDeinterleaveNode) {1898 LLVM_DEBUG(1899 dbgs() << "Couldn't find a deinterleave node within the graph, cannot "1900 "guarantee safety during graph transformation.\n");1901 return false;1902 }1903 1904 // Collect all instructions from roots to leaves1905 SmallPtrSet<Instruction *, 16> AllInstructions;1906 SmallVector<Instruction *, 8> Worklist;1907 for (auto &Pair : RootToNode)1908 Worklist.push_back(Pair.first);1909 1910 // Extract all instructions that are used by all XCMLA/XCADD/ADD/SUB/NEG1911 // chains1912 while (!Worklist.empty()) {1913 auto *I = Worklist.pop_back_val();1914 1915 if (!AllInstructions.insert(I).second)1916 continue;1917 1918 for (Value *Op : I->operands()) {1919 if (auto *OpI = dyn_cast<Instruction>(Op)) {1920 if (!FinalInstructions.count(I))1921 Worklist.emplace_back(OpI);1922 }1923 }1924 }1925 1926 // Find instructions that have users outside of chain1927 for (auto *I : AllInstructions) {1928 // Skip root nodes1929 if (RootToNode.count(I))1930 continue;1931 1932 for (User *U : I->users()) {1933 if (AllInstructions.count(cast<Instruction>(U)))1934 continue;1935 1936 // Found an instruction that is not used by XCMLA/XCADD chain1937 Worklist.emplace_back(I);1938 break;1939 }1940 }1941 1942 // If any instructions are found to be used outside, find and remove roots1943 // that somehow connect to those instructions.1944 SmallPtrSet<Instruction *, 16> Visited;1945 while (!Worklist.empty()) {1946 auto *I = Worklist.pop_back_val();1947 if (!Visited.insert(I).second)1948 continue;1949 1950 // Found an impacted root node. Removing it from the nodes to be1951 // deinterleaved1952 if (RootToNode.count(I)) {1953 LLVM_DEBUG(dbgs() << "Instruction " << *I1954 << " could be deinterleaved but its chain of complex "1955 "operations have an outside user\n");1956 RootToNode.erase(I);1957 }1958 1959 if (!AllInstructions.count(I) || FinalInstructions.count(I))1960 continue;1961 1962 for (User *U : I->users())1963 Worklist.emplace_back(cast<Instruction>(U));1964 1965 for (Value *Op : I->operands()) {1966 if (auto *OpI = dyn_cast<Instruction>(Op))1967 Worklist.emplace_back(OpI);1968 }1969 }1970 return !RootToNode.empty();1971}1972 1973ComplexDeinterleavingGraph::CompositeNode *1974ComplexDeinterleavingGraph::identifyRoot(Instruction *RootI) {1975 if (auto *Intrinsic = dyn_cast<IntrinsicInst>(RootI)) {1976 if (Intrinsic::getInterleaveIntrinsicID(Factor) !=1977 Intrinsic->getIntrinsicID())1978 return nullptr;1979 1980 ComplexValues Vals;1981 for (unsigned I = 0; I < Factor; I += 2) {1982 auto *Real = dyn_cast<Instruction>(Intrinsic->getOperand(I));1983 auto *Imag = dyn_cast<Instruction>(Intrinsic->getOperand(I + 1));1984 if (!Real || !Imag)1985 return nullptr;1986 Vals.push_back({Real, Imag});1987 }1988 1989 ComplexDeinterleavingGraph::CompositeNode *Node1 = identifyNode(Vals);1990 if (!Node1)1991 return nullptr;1992 return Node1;1993 }1994 1995 // TODO: We could also add support for fixed-width interleave factors of 41996 // and above, but currently for symmetric operations the interleaves and1997 // deinterleaves are already removed by VectorCombine. If we extend this to1998 // permit complex multiplications, reductions, etc. then we should also add1999 // support for fixed-width here.2000 if (Factor != 2)2001 return nullptr;2002 2003 auto *SVI = dyn_cast<ShuffleVectorInst>(RootI);2004 if (!SVI)2005 return nullptr;2006 2007 // Look for a shufflevector that takes separate vectors of the real and2008 // imaginary components and recombines them into a single vector.2009 if (!isInterleavingMask(SVI->getShuffleMask()))2010 return nullptr;2011 2012 Instruction *Real;2013 Instruction *Imag;2014 if (!match(RootI, m_Shuffle(m_Instruction(Real), m_Instruction(Imag))))2015 return nullptr;2016 2017 return identifyNode(Real, Imag);2018}2019 2020ComplexDeinterleavingGraph::CompositeNode *2021ComplexDeinterleavingGraph::identifyDeinterleave(ComplexValues &Vals) {2022 Instruction *II = nullptr;2023 2024 // Must be at least one complex value.2025 auto CheckExtract = [&](Value *V, unsigned ExpectedIdx,2026 Instruction *ExpectedInsn) -> ExtractValueInst * {2027 auto *EVI = dyn_cast<ExtractValueInst>(V);2028 if (!EVI || EVI->getNumIndices() != 1 ||2029 EVI->getIndices()[0] != ExpectedIdx ||2030 !isa<Instruction>(EVI->getAggregateOperand()) ||2031 (ExpectedInsn && ExpectedInsn != EVI->getAggregateOperand()))2032 return nullptr;2033 return EVI;2034 };2035 2036 for (unsigned Idx = 0; Idx < Vals.size(); Idx++) {2037 ExtractValueInst *RealEVI = CheckExtract(Vals[Idx].Real, Idx * 2, II);2038 if (RealEVI && Idx == 0)2039 II = cast<Instruction>(RealEVI->getAggregateOperand());2040 if (!RealEVI || !CheckExtract(Vals[Idx].Imag, (Idx * 2) + 1, II)) {2041 II = nullptr;2042 break;2043 }2044 }2045 2046 if (auto *IntrinsicII = dyn_cast_or_null<IntrinsicInst>(II)) {2047 if (IntrinsicII->getIntrinsicID() !=2048 Intrinsic::getDeinterleaveIntrinsicID(2 * Vals.size()))2049 return nullptr;2050 2051 // The remaining should match too.2052 CompositeNode *PlaceholderNode = prepareCompositeNode(2053 llvm::ComplexDeinterleavingOperation::Deinterleave, Vals);2054 PlaceholderNode->ReplacementNode = II->getOperand(0);2055 for (auto &V : Vals) {2056 FinalInstructions.insert(cast<Instruction>(V.Real));2057 FinalInstructions.insert(cast<Instruction>(V.Imag));2058 }2059 return submitCompositeNode(PlaceholderNode);2060 }2061 2062 if (Vals.size() != 1)2063 return nullptr;2064 2065 Value *Real = Vals[0].Real;2066 Value *Imag = Vals[0].Imag;2067 auto *RealShuffle = dyn_cast<ShuffleVectorInst>(Real);2068 auto *ImagShuffle = dyn_cast<ShuffleVectorInst>(Imag);2069 if (!RealShuffle || !ImagShuffle) {2070 if (RealShuffle || ImagShuffle)2071 LLVM_DEBUG(dbgs() << " - There's a shuffle where there shouldn't be.\n");2072 return nullptr;2073 }2074 2075 Value *RealOp1 = RealShuffle->getOperand(1);2076 if (!isa<UndefValue>(RealOp1) && !isa<ConstantAggregateZero>(RealOp1)) {2077 LLVM_DEBUG(dbgs() << " - RealOp1 is not undef or zero.\n");2078 return nullptr;2079 }2080 Value *ImagOp1 = ImagShuffle->getOperand(1);2081 if (!isa<UndefValue>(ImagOp1) && !isa<ConstantAggregateZero>(ImagOp1)) {2082 LLVM_DEBUG(dbgs() << " - ImagOp1 is not undef or zero.\n");2083 return nullptr;2084 }2085 2086 Value *RealOp0 = RealShuffle->getOperand(0);2087 Value *ImagOp0 = ImagShuffle->getOperand(0);2088 2089 if (RealOp0 != ImagOp0) {2090 LLVM_DEBUG(dbgs() << " - Shuffle operands are not equal.\n");2091 return nullptr;2092 }2093 2094 ArrayRef<int> RealMask = RealShuffle->getShuffleMask();2095 ArrayRef<int> ImagMask = ImagShuffle->getShuffleMask();2096 if (!isDeinterleavingMask(RealMask) || !isDeinterleavingMask(ImagMask)) {2097 LLVM_DEBUG(dbgs() << " - Masks are not deinterleaving.\n");2098 return nullptr;2099 }2100 2101 if (RealMask[0] != 0 || ImagMask[0] != 1) {2102 LLVM_DEBUG(dbgs() << " - Masks do not have the correct initial value.\n");2103 return nullptr;2104 }2105 2106 // Type checking, the shuffle type should be a vector type of the same2107 // scalar type, but half the size2108 auto CheckType = [&](ShuffleVectorInst *Shuffle) {2109 Value *Op = Shuffle->getOperand(0);2110 auto *ShuffleTy = cast<FixedVectorType>(Shuffle->getType());2111 auto *OpTy = cast<FixedVectorType>(Op->getType());2112 2113 if (OpTy->getScalarType() != ShuffleTy->getScalarType())2114 return false;2115 if ((ShuffleTy->getNumElements() * 2) != OpTy->getNumElements())2116 return false;2117 2118 return true;2119 };2120 2121 auto CheckDeinterleavingShuffle = [&](ShuffleVectorInst *Shuffle) -> bool {2122 if (!CheckType(Shuffle))2123 return false;2124 2125 ArrayRef<int> Mask = Shuffle->getShuffleMask();2126 int Last = *Mask.rbegin();2127 2128 Value *Op = Shuffle->getOperand(0);2129 auto *OpTy = cast<FixedVectorType>(Op->getType());2130 int NumElements = OpTy->getNumElements();2131 2132 // Ensure that the deinterleaving shuffle only pulls from the first2133 // shuffle operand.2134 return Last < NumElements;2135 };2136 2137 if (RealShuffle->getType() != ImagShuffle->getType()) {2138 LLVM_DEBUG(dbgs() << " - Shuffle types aren't equal.\n");2139 return nullptr;2140 }2141 if (!CheckDeinterleavingShuffle(RealShuffle)) {2142 LLVM_DEBUG(dbgs() << " - RealShuffle is invalid type.\n");2143 return nullptr;2144 }2145 if (!CheckDeinterleavingShuffle(ImagShuffle)) {2146 LLVM_DEBUG(dbgs() << " - ImagShuffle is invalid type.\n");2147 return nullptr;2148 }2149 2150 CompositeNode *PlaceholderNode =2151 prepareCompositeNode(llvm::ComplexDeinterleavingOperation::Deinterleave,2152 RealShuffle, ImagShuffle);2153 PlaceholderNode->ReplacementNode = RealShuffle->getOperand(0);2154 FinalInstructions.insert(RealShuffle);2155 FinalInstructions.insert(ImagShuffle);2156 return submitCompositeNode(PlaceholderNode);2157}2158 2159ComplexDeinterleavingGraph::CompositeNode *2160ComplexDeinterleavingGraph::identifySplat(ComplexValues &Vals) {2161 auto IsSplat = [](Value *V) -> bool {2162 // Fixed-width vector with constants2163 if (isa<ConstantDataVector>(V))2164 return true;2165 2166 if (isa<ConstantInt>(V) || isa<ConstantFP>(V))2167 return isa<VectorType>(V->getType());2168 2169 VectorType *VTy;2170 ArrayRef<int> Mask;2171 // Splats are represented differently depending on whether the repeated2172 // value is a constant or an Instruction2173 if (auto *Const = dyn_cast<ConstantExpr>(V)) {2174 if (Const->getOpcode() != Instruction::ShuffleVector)2175 return false;2176 VTy = cast<VectorType>(Const->getType());2177 Mask = Const->getShuffleMask();2178 } else if (auto *Shuf = dyn_cast<ShuffleVectorInst>(V)) {2179 VTy = Shuf->getType();2180 Mask = Shuf->getShuffleMask();2181 } else {2182 return false;2183 }2184 2185 // When the data type is <1 x Type>, it's not possible to differentiate2186 // between the ComplexDeinterleaving::Deinterleave and2187 // ComplexDeinterleaving::Splat operations.2188 if (!VTy->isScalableTy() && VTy->getElementCount().getKnownMinValue() == 1)2189 return false;2190 2191 return all_equal(Mask) && Mask[0] == 0;2192 };2193 2194 // The splats must meet the following requirements:2195 // 1. Must either be all instructions or all values.2196 // 2. Non-constant splats must live in the same block.2197 if (auto *FirstValAsInstruction = dyn_cast<Instruction>(Vals[0].Real)) {2198 BasicBlock *FirstBB = FirstValAsInstruction->getParent();2199 for (auto &V : Vals) {2200 if (!IsSplat(V.Real) || !IsSplat(V.Imag))2201 return nullptr;2202 2203 auto *Real = dyn_cast<Instruction>(V.Real);2204 auto *Imag = dyn_cast<Instruction>(V.Imag);2205 if (!Real || !Imag || Real->getParent() != FirstBB ||2206 Imag->getParent() != FirstBB)2207 return nullptr;2208 }2209 } else {2210 for (auto &V : Vals) {2211 if (!IsSplat(V.Real) || !IsSplat(V.Imag) || isa<Instruction>(V.Real) ||2212 isa<Instruction>(V.Imag))2213 return nullptr;2214 }2215 }2216 2217 for (auto &V : Vals) {2218 auto *Real = dyn_cast<Instruction>(V.Real);2219 auto *Imag = dyn_cast<Instruction>(V.Imag);2220 if (Real && Imag) {2221 FinalInstructions.insert(Real);2222 FinalInstructions.insert(Imag);2223 }2224 }2225 CompositeNode *PlaceholderNode =2226 prepareCompositeNode(ComplexDeinterleavingOperation::Splat, Vals);2227 return submitCompositeNode(PlaceholderNode);2228}2229 2230ComplexDeinterleavingGraph::CompositeNode *2231ComplexDeinterleavingGraph::identifyPHINode(Instruction *Real,2232 Instruction *Imag) {2233 if (Real != RealPHI || (ImagPHI && Imag != ImagPHI))2234 return nullptr;2235 2236 PHIsFound = true;2237 CompositeNode *PlaceholderNode = prepareCompositeNode(2238 ComplexDeinterleavingOperation::ReductionPHI, Real, Imag);2239 return submitCompositeNode(PlaceholderNode);2240}2241 2242ComplexDeinterleavingGraph::CompositeNode *2243ComplexDeinterleavingGraph::identifySelectNode(Instruction *Real,2244 Instruction *Imag) {2245 auto *SelectReal = dyn_cast<SelectInst>(Real);2246 auto *SelectImag = dyn_cast<SelectInst>(Imag);2247 if (!SelectReal || !SelectImag)2248 return nullptr;2249 2250 Instruction *MaskA, *MaskB;2251 Instruction *AR, *AI, *RA, *BI;2252 if (!match(Real, m_Select(m_Instruction(MaskA), m_Instruction(AR),2253 m_Instruction(RA))) ||2254 !match(Imag, m_Select(m_Instruction(MaskB), m_Instruction(AI),2255 m_Instruction(BI))))2256 return nullptr;2257 2258 if (MaskA != MaskB && !MaskA->isIdenticalTo(MaskB))2259 return nullptr;2260 2261 if (!MaskA->getType()->isVectorTy())2262 return nullptr;2263 2264 auto NodeA = identifyNode(AR, AI);2265 if (!NodeA)2266 return nullptr;2267 2268 auto NodeB = identifyNode(RA, BI);2269 if (!NodeB)2270 return nullptr;2271 2272 CompositeNode *PlaceholderNode = prepareCompositeNode(2273 ComplexDeinterleavingOperation::ReductionSelect, Real, Imag);2274 PlaceholderNode->addOperand(NodeA);2275 PlaceholderNode->addOperand(NodeB);2276 FinalInstructions.insert(MaskA);2277 FinalInstructions.insert(MaskB);2278 return submitCompositeNode(PlaceholderNode);2279}2280 2281static Value *replaceSymmetricNode(IRBuilderBase &B, unsigned Opcode,2282 std::optional<FastMathFlags> Flags,2283 Value *InputA, Value *InputB) {2284 Value *I;2285 switch (Opcode) {2286 case Instruction::FNeg:2287 I = B.CreateFNeg(InputA);2288 break;2289 case Instruction::FAdd:2290 I = B.CreateFAdd(InputA, InputB);2291 break;2292 case Instruction::Add:2293 I = B.CreateAdd(InputA, InputB);2294 break;2295 case Instruction::FSub:2296 I = B.CreateFSub(InputA, InputB);2297 break;2298 case Instruction::Sub:2299 I = B.CreateSub(InputA, InputB);2300 break;2301 case Instruction::FMul:2302 I = B.CreateFMul(InputA, InputB);2303 break;2304 case Instruction::Mul:2305 I = B.CreateMul(InputA, InputB);2306 break;2307 default:2308 llvm_unreachable("Incorrect symmetric opcode");2309 }2310 if (Flags)2311 cast<Instruction>(I)->setFastMathFlags(*Flags);2312 return I;2313}2314 2315Value *ComplexDeinterleavingGraph::replaceNode(IRBuilderBase &Builder,2316 CompositeNode *Node) {2317 if (Node->ReplacementNode)2318 return Node->ReplacementNode;2319 2320 auto ReplaceOperandIfExist = [&](CompositeNode *Node,2321 unsigned Idx) -> Value * {2322 return Node->Operands.size() > Idx2323 ? replaceNode(Builder, Node->Operands[Idx])2324 : nullptr;2325 };2326 2327 Value *ReplacementNode = nullptr;2328 switch (Node->Operation) {2329 case ComplexDeinterleavingOperation::CDot: {2330 Value *Input0 = ReplaceOperandIfExist(Node, 0);2331 Value *Input1 = ReplaceOperandIfExist(Node, 1);2332 Value *Accumulator = ReplaceOperandIfExist(Node, 2);2333 assert(!Input1 || (Input0->getType() == Input1->getType() &&2334 "Node inputs need to be of the same type"));2335 ReplacementNode = TL->createComplexDeinterleavingIR(2336 Builder, Node->Operation, Node->Rotation, Input0, Input1, Accumulator);2337 break;2338 }2339 case ComplexDeinterleavingOperation::CAdd:2340 case ComplexDeinterleavingOperation::CMulPartial:2341 case ComplexDeinterleavingOperation::Symmetric: {2342 Value *Input0 = ReplaceOperandIfExist(Node, 0);2343 Value *Input1 = ReplaceOperandIfExist(Node, 1);2344 Value *Accumulator = ReplaceOperandIfExist(Node, 2);2345 assert(!Input1 || (Input0->getType() == Input1->getType() &&2346 "Node inputs need to be of the same type"));2347 assert(!Accumulator ||2348 (Input0->getType() == Accumulator->getType() &&2349 "Accumulator and input need to be of the same type"));2350 if (Node->Operation == ComplexDeinterleavingOperation::Symmetric)2351 ReplacementNode = replaceSymmetricNode(Builder, Node->Opcode, Node->Flags,2352 Input0, Input1);2353 else2354 ReplacementNode = TL->createComplexDeinterleavingIR(2355 Builder, Node->Operation, Node->Rotation, Input0, Input1,2356 Accumulator);2357 break;2358 }2359 case ComplexDeinterleavingOperation::Deinterleave:2360 llvm_unreachable("Deinterleave node should already have ReplacementNode");2361 break;2362 case ComplexDeinterleavingOperation::Splat: {2363 SmallVector<Value *> Ops;2364 for (auto &V : Node->Vals) {2365 Ops.push_back(V.Real);2366 Ops.push_back(V.Imag);2367 }2368 auto *R = dyn_cast<Instruction>(Node->Vals[0].Real);2369 auto *I = dyn_cast<Instruction>(Node->Vals[0].Imag);2370 if (R && I) {2371 // Splats that are not constant are interleaved where they are located2372 Instruction *InsertPoint = R;2373 for (auto V : Node->Vals) {2374 if (InsertPoint->comesBefore(cast<Instruction>(V.Real)))2375 InsertPoint = cast<Instruction>(V.Real);2376 if (InsertPoint->comesBefore(cast<Instruction>(V.Imag)))2377 InsertPoint = cast<Instruction>(V.Imag);2378 }2379 InsertPoint = InsertPoint->getNextNode();2380 IRBuilder<> IRB(InsertPoint);2381 ReplacementNode = IRB.CreateVectorInterleave(Ops);2382 } else {2383 ReplacementNode = Builder.CreateVectorInterleave(Ops);2384 }2385 break;2386 }2387 case ComplexDeinterleavingOperation::ReductionPHI: {2388 // If Operation is ReductionPHI, a new empty PHINode is created.2389 // It is filled later when the ReductionOperation is processed.2390 auto *OldPHI = cast<PHINode>(Node->Vals[0].Real);2391 auto *VTy = cast<VectorType>(Node->Vals[0].Real->getType());2392 auto *NewVTy = VectorType::getDoubleElementsVectorType(VTy);2393 auto *NewPHI = PHINode::Create(NewVTy, 0, "", BackEdge->getFirstNonPHIIt());2394 OldToNewPHI[OldPHI] = NewPHI;2395 ReplacementNode = NewPHI;2396 break;2397 }2398 case ComplexDeinterleavingOperation::ReductionSingle:2399 ReplacementNode = replaceNode(Builder, Node->Operands[0]);2400 processReductionSingle(ReplacementNode, Node);2401 break;2402 case ComplexDeinterleavingOperation::ReductionOperation:2403 ReplacementNode = replaceNode(Builder, Node->Operands[0]);2404 processReductionOperation(ReplacementNode, Node);2405 break;2406 case ComplexDeinterleavingOperation::ReductionSelect: {2407 auto *MaskReal = cast<Instruction>(Node->Vals[0].Real)->getOperand(0);2408 auto *MaskImag = cast<Instruction>(Node->Vals[0].Imag)->getOperand(0);2409 auto *A = replaceNode(Builder, Node->Operands[0]);2410 auto *B = replaceNode(Builder, Node->Operands[1]);2411 auto *NewMask = Builder.CreateVectorInterleave({MaskReal, MaskImag});2412 ReplacementNode = Builder.CreateSelect(NewMask, A, B);2413 break;2414 }2415 }2416 2417 assert(ReplacementNode && "Target failed to create Intrinsic call.");2418 NumComplexTransformations += 1;2419 Node->ReplacementNode = ReplacementNode;2420 return ReplacementNode;2421}2422 2423void ComplexDeinterleavingGraph::processReductionSingle(2424 Value *OperationReplacement, CompositeNode *Node) {2425 auto *Real = cast<Instruction>(Node->Vals[0].Real);2426 auto *OldPHI = ReductionInfo[Real].first;2427 auto *NewPHI = OldToNewPHI[OldPHI];2428 auto *VTy = cast<VectorType>(Real->getType());2429 auto *NewVTy = VectorType::getDoubleElementsVectorType(VTy);2430 2431 Value *Init = OldPHI->getIncomingValueForBlock(Incoming);2432 2433 IRBuilder<> Builder(Incoming->getTerminator());2434 2435 Value *NewInit = nullptr;2436 if (auto *C = dyn_cast<Constant>(Init)) {2437 if (C->isZeroValue())2438 NewInit = Constant::getNullValue(NewVTy);2439 }2440 2441 if (!NewInit)2442 NewInit =2443 Builder.CreateVectorInterleave({Init, Constant::getNullValue(VTy)});2444 2445 NewPHI->addIncoming(NewInit, Incoming);2446 NewPHI->addIncoming(OperationReplacement, BackEdge);2447 2448 auto *FinalReduction = ReductionInfo[Real].second;2449 Builder.SetInsertPoint(&*FinalReduction->getParent()->getFirstInsertionPt());2450 2451 auto *AddReduce = Builder.CreateAddReduce(OperationReplacement);2452 FinalReduction->replaceAllUsesWith(AddReduce);2453}2454 2455void ComplexDeinterleavingGraph::processReductionOperation(2456 Value *OperationReplacement, CompositeNode *Node) {2457 auto *Real = cast<Instruction>(Node->Vals[0].Real);2458 auto *Imag = cast<Instruction>(Node->Vals[0].Imag);2459 auto *OldPHIReal = ReductionInfo[Real].first;2460 auto *OldPHIImag = ReductionInfo[Imag].first;2461 auto *NewPHI = OldToNewPHI[OldPHIReal];2462 2463 // We have to interleave initial origin values coming from IncomingBlock2464 Value *InitReal = OldPHIReal->getIncomingValueForBlock(Incoming);2465 Value *InitImag = OldPHIImag->getIncomingValueForBlock(Incoming);2466 2467 IRBuilder<> Builder(Incoming->getTerminator());2468 auto *NewInit = Builder.CreateVectorInterleave({InitReal, InitImag});2469 2470 NewPHI->addIncoming(NewInit, Incoming);2471 NewPHI->addIncoming(OperationReplacement, BackEdge);2472 2473 // Deinterleave complex vector outside of loop so that it can be finally2474 // reduced2475 auto *FinalReductionReal = ReductionInfo[Real].second;2476 auto *FinalReductionImag = ReductionInfo[Imag].second;2477 2478 Builder.SetInsertPoint(2479 &*FinalReductionReal->getParent()->getFirstInsertionPt());2480 auto *Deinterleave = Builder.CreateIntrinsic(Intrinsic::vector_deinterleave2,2481 OperationReplacement->getType(),2482 OperationReplacement);2483 2484 auto *NewReal = Builder.CreateExtractValue(Deinterleave, (uint64_t)0);2485 FinalReductionReal->replaceUsesOfWith(Real, NewReal);2486 2487 Builder.SetInsertPoint(FinalReductionImag);2488 auto *NewImag = Builder.CreateExtractValue(Deinterleave, 1);2489 FinalReductionImag->replaceUsesOfWith(Imag, NewImag);2490}2491 2492void ComplexDeinterleavingGraph::replaceNodes() {2493 SmallVector<Instruction *, 16> DeadInstrRoots;2494 for (auto *RootInstruction : OrderedRoots) {2495 // Check if this potential root went through check process and we can2496 // deinterleave it2497 if (!RootToNode.count(RootInstruction))2498 continue;2499 2500 IRBuilder<> Builder(RootInstruction);2501 auto RootNode = RootToNode[RootInstruction];2502 Value *R = replaceNode(Builder, RootNode);2503 2504 if (RootNode->Operation ==2505 ComplexDeinterleavingOperation::ReductionOperation) {2506 auto *RootReal = cast<Instruction>(RootNode->Vals[0].Real);2507 auto *RootImag = cast<Instruction>(RootNode->Vals[0].Imag);2508 ReductionInfo[RootReal].first->removeIncomingValue(BackEdge);2509 ReductionInfo[RootImag].first->removeIncomingValue(BackEdge);2510 DeadInstrRoots.push_back(RootReal);2511 DeadInstrRoots.push_back(RootImag);2512 } else if (RootNode->Operation ==2513 ComplexDeinterleavingOperation::ReductionSingle) {2514 auto *RootInst = cast<Instruction>(RootNode->Vals[0].Real);2515 auto &Info = ReductionInfo[RootInst];2516 Info.first->removeIncomingValue(BackEdge);2517 DeadInstrRoots.push_back(Info.second);2518 } else {2519 assert(R && "Unable to find replacement for RootInstruction");2520 DeadInstrRoots.push_back(RootInstruction);2521 RootInstruction->replaceAllUsesWith(R);2522 }2523 }2524 2525 for (auto *I : DeadInstrRoots)2526 RecursivelyDeleteTriviallyDeadInstructions(I, TLI);2527}2528