82#define DEBUG_TYPE "complex-deinterleaving"
84STATISTIC(NumComplexTransformations,
"Amount of complex patterns transformed");
87 "enable-complex-deinterleaving",
115 Value *Real =
nullptr;
116 Value *Imag =
nullptr;
119 return Real ==
Other.Real && Imag ==
Other.Imag;
134 static bool isEqual(
const ComplexValue &LHS,
const ComplexValue &RHS) {
135 return LHS.Real == RHS.Real && LHS.Imag == RHS.Imag;
140template <
typename T,
typename IterT>
141std::optional<T> findCommonBetweenCollections(IterT
A, IterT
B) {
143 if (Common !=
A.end())
144 return std::make_optional(*Common);
148class ComplexDeinterleavingLegacyPass :
public FunctionPass {
152 ComplexDeinterleavingLegacyPass(
const TargetMachine *TM =
nullptr)
153 : FunctionPass(ID), TM(TM) {}
155 StringRef getPassName()
const override {
156 return "Complex Deinterleaving Pass";
160 void getAnalysisUsage(AnalysisUsage &AU)
const override {
166 const TargetMachine *TM;
169class ComplexDeinterleavingGraph;
170struct ComplexDeinterleavingCompositeNode {
175 Vals.push_back({
R,
I});
180 : Operation(
Op), Vals(
Other) {}
183 friend class ComplexDeinterleavingGraph;
184 using CompositeNode = ComplexDeinterleavingCompositeNode;
185 bool OperandsValid =
true;
194 std::optional<FastMathFlags> Flags;
197 ComplexDeinterleavingRotation::Rotation_0;
199 Value *ReplacementNode =
nullptr;
203 OperandsValid =
false;
204 Operands.push_back(Node);
208 void dump(raw_ostream &OS) {
209 auto PrintValue = [&](
Value *
V) {
217 auto PrintNodeRef = [&](CompositeNode *Ptr) {
224 OS <<
"- CompositeNode: " <<
this <<
"\n";
225 for (
unsigned I = 0;
I < Vals.size();
I++) {
226 OS <<
" Real(" <<
I <<
") : ";
227 PrintValue(Vals[
I].Real);
228 OS <<
" Imag(" <<
I <<
") : ";
229 PrintValue(Vals[
I].Imag);
231 OS <<
" ReplacementNode: ";
232 PrintValue(ReplacementNode);
233 OS <<
" Operation: " << (int)Operation <<
"\n";
234 OS <<
" Rotation: " << ((int)Rotation * 90) <<
"\n";
235 OS <<
" Operands: \n";
236 for (
const auto &
Op : Operands) {
242 bool areOperandsValid() {
return OperandsValid; }
245class ComplexDeinterleavingGraph {
253 using Addend = std::pair<Value *, bool>;
255 using CompositeNode = ComplexDeinterleavingCompositeNode::CompositeNode;
259 struct PartialMulCandidate {
267 explicit ComplexDeinterleavingGraph(
const TargetLowering *TL,
268 const TargetLibraryInfo *TLI,
270 : TL(TL), TLI(TLI), Factor(Factor) {}
273 const TargetLowering *TL =
nullptr;
274 const TargetLibraryInfo *TLI =
nullptr;
277 DenseMap<ComplexValues, CompositeNode *> CachedResult;
278 SpecificBumpPtrAllocator<ComplexDeinterleavingCompositeNode> Allocator;
280 SmallPtrSet<Instruction *, 16> FinalInstructions;
283 DenseMap<Instruction *, CompositeNode *> RootToNode;
310 MapVector<Instruction *, std::pair<PHINode *, Instruction *>> ReductionInfo;
318 PHINode *RealPHI =
nullptr;
319 PHINode *ImagPHI =
nullptr;
323 bool PHIsFound =
false;
331 DenseMap<PHINode *, PHINode *> OldToNewPHI;
336 Operation != ComplexDeinterleavingOperation::ReductionOperation) ||
338 "Reduction related nodes must have Real and Imaginary parts");
339 return new (Allocator.Allocate())
340 ComplexDeinterleavingCompositeNode(
Operation, R,
I);
346 for (
auto &V : Vals) {
348 ((
Operation != ComplexDeinterleavingOperation::ReductionPHI &&
349 Operation != ComplexDeinterleavingOperation::ReductionOperation) ||
350 (
V.Real &&
V.Imag)) &&
351 "Reduction related nodes must have Real and Imaginary parts");
354 return new (Allocator.Allocate())
355 ComplexDeinterleavingCompositeNode(
Operation, Vals);
358 CompositeNode *submitCompositeNode(CompositeNode *Node) {
359 CompositeNodes.push_back(Node);
360 if (
Node->Vals[0].Real)
376 CompositeNode *identifyPartialMul(Instruction *Real, Instruction *Imag);
382 identifyNodeWithImplicitAdd(Instruction *
I, Instruction *J,
383 std::pair<Value *, Value *> &CommonOperandI);
392 CompositeNode *identifyAdd(Instruction *Real, Instruction *Imag);
393 CompositeNode *identifySymmetricOperation(
ComplexValues &Vals);
394 CompositeNode *identifyPartialReduction(
Value *R,
Value *
I);
395 CompositeNode *identifyDotProduct(
Value *Inst);
402 return identifyNode(Vals);
409 CompositeNode *identifyAdditions(AddendList &RealAddends,
410 AddendList &ImagAddends,
411 std::optional<FastMathFlags> Flags,
415 CompositeNode *extractPositiveAddend(AddendList &RealAddends,
416 AddendList &ImagAddends);
421 CompositeNode *identifyMultiplications(SmallVectorImpl<Product> &RealMuls,
422 SmallVectorImpl<Product> &ImagMuls,
430 SmallVectorImpl<PartialMulCandidate> &Candidates);
438 CompositeNode *identifyReassocNodes(Instruction *
I, Instruction *J);
440 CompositeNode *identifyRoot(Instruction *
I);
458 CompositeNode *identifyPHINode(Instruction *Real, Instruction *Imag);
462 CompositeNode *identifySelectNode(Instruction *Real, Instruction *Imag);
464 Value *replaceNode(IRBuilderBase &Builder, CompositeNode *Node);
471 void processReductionOperation(
Value *OperationReplacement,
472 CompositeNode *Node);
473 void processReductionSingle(
Value *OperationReplacement, CompositeNode *Node);
477 void dump(raw_ostream &OS) {
478 for (
const auto &Node : CompositeNodes)
484 bool identifyNodes(Instruction *RootI);
489 bool collectPotentialReductions(BasicBlock *
B);
491 void identifyReductionNodes();
501class ComplexDeinterleaving {
503 ComplexDeinterleaving(
const TargetLowering *tl,
const TargetLibraryInfo *tli)
504 : TL(tl), TLI(tli) {}
508 bool evaluateBasicBlock(BasicBlock *
B,
unsigned Factor);
510 const TargetLowering *TL =
nullptr;
511 const TargetLibraryInfo *TLI =
nullptr;
516char ComplexDeinterleavingLegacyPass::ID = 0;
519 "Complex Deinterleaving",
false,
false)
525 const TargetLowering *TL = TM->getSubtargetImpl(
F)->getTargetLowering();
536 return new ComplexDeinterleavingLegacyPass(TM);
539bool ComplexDeinterleavingLegacyPass::runOnFunction(
Function &
F) {
541 auto TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(
F);
542 return ComplexDeinterleaving(TL, &TLI).runOnFunction(
F);
545bool ComplexDeinterleaving::runOnFunction(
Function &
F) {
548 dbgs() <<
"Complex deinterleaving has been explicitly disabled.\n");
554 dbgs() <<
"Complex deinterleaving has been disabled, target does "
555 "not support lowering of complex number operations.\n");
561 Changed |= evaluateBasicBlock(&
B, 2);
566 Changed |= evaluateBasicBlock(&
B, 4);
576 if ((Mask.size() & 1))
579 int HalfNumElements = Mask.size() / 2;
580 for (
int Idx = 0; Idx < HalfNumElements; ++Idx) {
581 int MaskIdx = Idx * 2;
582 if (Mask[MaskIdx] != Idx || Mask[MaskIdx + 1] != (Idx + HalfNumElements))
591 int HalfNumElements = Mask.size() / 2;
593 for (
int Idx = 1; Idx < HalfNumElements; ++Idx) {
594 if (Mask[Idx] != (Idx * 2) +
Offset)
609 if (
I->getOpcode() == Instruction::FNeg)
610 return I->getOperand(0);
612 return I->getOperand(1);
615bool ComplexDeinterleaving::evaluateBasicBlock(BasicBlock *
B,
unsigned Factor) {
616 ComplexDeinterleavingGraph
Graph(TL, TLI, Factor);
617 if (
Graph.collectPotentialReductions(
B))
618 Graph.identifyReductionNodes();
623 if (
Graph.checkNodes()) {
624 Graph.replaceNodes();
631ComplexDeinterleavingGraph::CompositeNode *
632ComplexDeinterleavingGraph::identifyNodeWithImplicitAdd(
633 Instruction *Real, Instruction *Imag,
634 std::pair<Value *, Value *> &PartialMatch) {
635 LLVM_DEBUG(
dbgs() <<
"identifyNodeWithImplicitAdd " << *Real <<
" / " << *Imag
643 if ((Real->
getOpcode() != Instruction::FMul &&
644 Real->
getOpcode() != Instruction::Mul) ||
645 (Imag->
getOpcode() != Instruction::FMul &&
646 Imag->
getOpcode() != Instruction::Mul)) {
648 dbgs() <<
" - Real or imaginary instruction is not fmul or mul\n");
663 }
else if (
isNeg(R1)) {
672 }
else if (
isNeg(I1)) {
680 Value *CommonOperand;
681 Value *UncommonRealOp;
682 Value *UncommonImagOp;
684 if (R0 == I0 || R0 == I1) {
687 }
else if (R1 == I0 || R1 == I1) {
695 UncommonImagOp = (CommonOperand == I0) ? I1 : I0;
696 if (Rotation == ComplexDeinterleavingRotation::Rotation_90 ||
697 Rotation == ComplexDeinterleavingRotation::Rotation_270)
698 std::swap(UncommonRealOp, UncommonImagOp);
702 if (Rotation == ComplexDeinterleavingRotation::Rotation_0 ||
703 Rotation == ComplexDeinterleavingRotation::Rotation_180)
704 PartialMatch.first = CommonOperand;
706 PartialMatch.second = CommonOperand;
708 if (!PartialMatch.first || !PartialMatch.second) {
713 CompositeNode *CommonNode =
714 identifyNode(PartialMatch.first, PartialMatch.second);
720 CompositeNode *UncommonNode = identifyNode(UncommonRealOp, UncommonImagOp);
726 CompositeNode *
Node = prepareCompositeNode(
727 ComplexDeinterleavingOperation::CMulPartial, Real, Imag);
728 Node->Rotation = Rotation;
729 Node->addOperand(CommonNode);
730 Node->addOperand(UncommonNode);
731 return submitCompositeNode(Node);
734ComplexDeinterleavingGraph::CompositeNode *
735ComplexDeinterleavingGraph::identifyPartialMul(Instruction *Real,
737 LLVM_DEBUG(
dbgs() <<
"identifyPartialMul " << *Real <<
" / " << *Imag
741 auto IsAdd = [](
unsigned Op) {
742 return Op == Instruction::FAdd ||
Op == Instruction::Add;
744 auto IsSub = [](
unsigned Op) {
745 return Op == Instruction::FSub ||
Op == Instruction::Sub;
749 Rotation = ComplexDeinterleavingRotation::Rotation_0;
751 Rotation = ComplexDeinterleavingRotation::Rotation_90;
753 Rotation = ComplexDeinterleavingRotation::Rotation_180;
755 Rotation = ComplexDeinterleavingRotation::Rotation_270;
764 LLVM_DEBUG(
dbgs() <<
" - Contract is missing from the FastMath flags.\n");
787 Value *CommonOperand;
788 Value *UncommonRealOp;
789 Value *UncommonImagOp;
791 if (R0 == I0 || R0 == I1) {
794 }
else if (R1 == I0 || R1 == I1) {
802 UncommonImagOp = (CommonOperand == I0) ? I1 : I0;
803 if (Rotation == ComplexDeinterleavingRotation::Rotation_90 ||
804 Rotation == ComplexDeinterleavingRotation::Rotation_270)
805 std::swap(UncommonRealOp, UncommonImagOp);
807 std::pair<Value *, Value *> PartialMatch(
808 (Rotation == ComplexDeinterleavingRotation::Rotation_0 ||
809 Rotation == ComplexDeinterleavingRotation::Rotation_180)
812 (Rotation == ComplexDeinterleavingRotation::Rotation_90 ||
813 Rotation == ComplexDeinterleavingRotation::Rotation_270)
820 if (!CRInst || !CIInst) {
821 LLVM_DEBUG(
dbgs() <<
" - Common operands are not instructions.\n");
825 CompositeNode *CNode =
826 identifyNodeWithImplicitAdd(CRInst, CIInst, PartialMatch);
832 CompositeNode *UncommonRes = identifyNode(UncommonRealOp, UncommonImagOp);
838 assert(PartialMatch.first && PartialMatch.second);
839 CompositeNode *CommonRes =
840 identifyNode(PartialMatch.first, PartialMatch.second);
846 CompositeNode *
Node = prepareCompositeNode(
847 ComplexDeinterleavingOperation::CMulPartial, Real, Imag);
848 Node->Rotation = Rotation;
849 Node->addOperand(CommonRes);
850 Node->addOperand(UncommonRes);
851 Node->addOperand(CNode);
852 return submitCompositeNode(Node);
855ComplexDeinterleavingGraph::CompositeNode *
856ComplexDeinterleavingGraph::identifyAdd(Instruction *Real, Instruction *Imag) {
857 LLVM_DEBUG(
dbgs() <<
"identifyAdd " << *Real <<
" / " << *Imag <<
"\n");
861 if ((Real->
getOpcode() == Instruction::FSub &&
862 Imag->
getOpcode() == Instruction::FAdd) ||
863 (Real->
getOpcode() == Instruction::Sub &&
865 Rotation = ComplexDeinterleavingRotation::Rotation_90;
866 else if ((Real->
getOpcode() == Instruction::FAdd &&
867 Imag->
getOpcode() == Instruction::FSub) ||
868 (Real->
getOpcode() == Instruction::Add &&
870 Rotation = ComplexDeinterleavingRotation::Rotation_270;
872 LLVM_DEBUG(
dbgs() <<
" - Unhandled case, rotation is not assigned.\n");
881 if (!AR || !AI || !BR || !BI) {
886 CompositeNode *ResA = identifyNode(AR, AI);
888 LLVM_DEBUG(
dbgs() <<
" - AR/AI is not identified as a composite node.\n");
891 CompositeNode *ResB = identifyNode(BR, BI);
893 LLVM_DEBUG(
dbgs() <<
" - BR/BI is not identified as a composite node.\n");
897 CompositeNode *
Node =
898 prepareCompositeNode(ComplexDeinterleavingOperation::CAdd, Real, Imag);
899 Node->Rotation = Rotation;
900 Node->addOperand(ResA);
901 Node->addOperand(ResB);
902 return submitCompositeNode(Node);
906 unsigned OpcA =
A->getOpcode();
907 unsigned OpcB =
B->getOpcode();
909 return (OpcA == Instruction::FSub && OpcB == Instruction::FAdd) ||
910 (OpcA == Instruction::FAdd && OpcB == Instruction::FSub) ||
911 (OpcA == Instruction::Sub && OpcB == Instruction::Add) ||
912 (OpcA == Instruction::Add && OpcB == Instruction::Sub);
923 switch (
I->getOpcode()) {
924 case Instruction::FAdd:
925 case Instruction::FSub:
926 case Instruction::FMul:
927 case Instruction::FNeg:
928 case Instruction::Add:
929 case Instruction::Sub:
930 case Instruction::Mul:
937ComplexDeinterleavingGraph::CompositeNode *
938ComplexDeinterleavingGraph::identifySymmetricOperation(
ComplexValues &Vals) {
940 unsigned FirstOpc = FirstReal->getOpcode();
941 FastMathFlags CommonFlags;
943 CommonFlags = FirstReal->getFastMathFlags();
944 for (
auto &V : Vals) {
961 for (
auto &V : Vals) {
967 CompositeNode *Op0 = identifyNode(OpVals);
968 CompositeNode *Op1 =
nullptr;
972 if (FirstReal->isBinaryOp()) {
974 for (
auto &V : Vals) {
979 Op1 = identifyNode(OpVals);
985 prepareCompositeNode(ComplexDeinterleavingOperation::Symmetric, Vals);
986 Node->Opcode = FirstReal->getOpcode();
988 Node->Flags = CommonFlags;
990 Node->addOperand(Op0);
991 if (FirstReal->isBinaryOp())
992 Node->addOperand(Op1);
994 return submitCompositeNode(Node);
997ComplexDeinterleavingGraph::CompositeNode *
998ComplexDeinterleavingGraph::identifyDotProduct(
Value *V) {
1000 ComplexDeinterleavingOperation::CDot,
V->getType())) {
1001 LLVM_DEBUG(
dbgs() <<
"Target doesn't support complex deinterleaving "
1002 "operation CDot with the type "
1003 << *
V->getType() <<
"\n");
1011 prepareCompositeNode(ComplexDeinterleavingOperation::CDot, Inst,
nullptr);
1013 CompositeNode *ANode =
nullptr;
1015 const Intrinsic::ID PartialReduceInt = Intrinsic::vector_partial_reduce_add;
1017 Value *AReal =
nullptr;
1018 Value *AImag =
nullptr;
1019 Value *BReal =
nullptr;
1020 Value *BImag =
nullptr;
1025 return CI->getOperand(0);
1039 if (
match(Inst, PatternRot0)) {
1040 CN->Rotation = ComplexDeinterleavingRotation::Rotation_0;
1041 }
else if (
match(Inst, PatternRot270)) {
1042 CN->Rotation = ComplexDeinterleavingRotation::Rotation_270;
1053 if (!
match(Inst, PatternRot90Rot180))
1056 A0 = UnwrapCast(A0);
1057 A1 = UnwrapCast(A1);
1060 ANode = identifyNode(A0, A1);
1063 ANode = identifyNode(A1, A0);
1067 CN->Rotation = ComplexDeinterleavingRotation::Rotation_90;
1073 CN->Rotation = ComplexDeinterleavingRotation::Rotation_180;
1077 AReal = UnwrapCast(AReal);
1078 AImag = UnwrapCast(AImag);
1079 BReal = UnwrapCast(BReal);
1080 BImag = UnwrapCast(BImag);
1083 Type *ExpectedOperandTy = VectorType::getSubdividedVectorType(VTy, 2);
1084 if (AReal->
getType() != ExpectedOperandTy)
1086 if (AImag->
getType() != ExpectedOperandTy)
1088 if (BReal->
getType() != ExpectedOperandTy)
1090 if (BImag->
getType() != ExpectedOperandTy)
1093 if (
Phi->getType() != VTy && RealUser->getType() != VTy)
1096 CompositeNode *
Node = identifyNode(AReal, AImag);
1101 if (ANode && Node != ANode) {
1104 <<
"Identified node is different from previously identified node. "
1105 "Unable to confidently generate a complex operation node\n");
1109 CN->addOperand(Node);
1110 CN->addOperand(identifyNode(BReal, BImag));
1111 CN->addOperand(identifyNode(Phi, RealUser));
1113 return submitCompositeNode(CN);
1116ComplexDeinterleavingGraph::CompositeNode *
1117ComplexDeinterleavingGraph::identifyPartialReduction(
Value *R,
Value *
I) {
1122 if (!
R->hasUseList() || !
I->hasUseList())
1126 findCommonBetweenCollections<Value *>(
R->users(),
I->users());
1131 if (!IInst || IInst->getIntrinsicID() != Intrinsic::vector_partial_reduce_add)
1134 if (CompositeNode *CN = identifyDotProduct(IInst))
1140ComplexDeinterleavingGraph::CompositeNode *
1141ComplexDeinterleavingGraph::identifyNode(
ComplexValues &Vals) {
1142 auto It = CachedResult.
find(Vals);
1143 if (It != CachedResult.
end()) {
1148 if (Vals.
size() == 1) {
1149 assert(Factor == 2 &&
"Can only handle interleave factors of 2");
1152 if (CompositeNode *CN = identifyPartialReduction(R,
I))
1154 bool IsReduction = RealPHI ==
R && (!ImagPHI || ImagPHI ==
I);
1155 if (!IsReduction &&
R->getType() !=
I->getType())
1159 if (CompositeNode *CN = identifySplat(Vals))
1162 for (
auto &V : Vals) {
1169 if (CompositeNode *CN = identifyDeinterleave(Vals))
1172 if (Vals.size() == 1) {
1173 assert(Factor == 2 &&
"Can only handle interleave factors of 2");
1176 if (CompositeNode *CN = identifyPHINode(Real, Imag))
1179 if (CompositeNode *CN = identifySelectNode(Real, Imag))
1183 auto *NewVTy = VectorType::getDoubleElementsVectorType(VTy);
1186 ComplexDeinterleavingOperation::CMulPartial, NewVTy);
1188 ComplexDeinterleavingOperation::CAdd, NewVTy);
1191 if (CompositeNode *CN = identifyPartialMul(Real, Imag))
1196 if (CompositeNode *CN = identifyAdd(Real, Imag))
1200 if (HasCMulSupport && HasCAddSupport) {
1201 if (CompositeNode *CN = identifyReassocNodes(Real, Imag)) {
1207 if (CompositeNode *CN = identifySymmetricOperation(Vals))
1211 CachedResult[Vals] =
nullptr;
1215ComplexDeinterleavingGraph::CompositeNode *
1216ComplexDeinterleavingGraph::identifyReassocNodes(Instruction *Real,
1217 Instruction *Imag) {
1218 auto IsOperationSupported = [](
Instruction *
I) ->
bool {
1219 unsigned Opcode =
I->getOpcode();
1221 Opcode == Instruction::FAdd || Opcode == Instruction::FSub ||
1222 Opcode == Instruction::FNeg || Opcode == Instruction::Add ||
1223 Opcode == Instruction::Sub;
1226 if (!IsOperationSupported(Real) || !IsOperationSupported(Imag))
1229 std::optional<FastMathFlags>
Flags;
1232 if (!
Flags->allowReassoc()) {
1235 <<
"the 'Reassoc' attribute is missing in the FastMath flags\n");
1245 AddendList &Addends) ->
bool {
1247 while (!Worklist.
empty()) {
1252 Addends.emplace_back(V, IsPositive);
1262 if (
I != Insn &&
I->hasNUsesOrMore(2)) {
1263 LLVM_DEBUG(
dbgs() <<
"Found potential sub-expression: " << *
I <<
"\n");
1264 Addends.emplace_back(
I, IsPositive);
1267 switch (
I->getOpcode()) {
1268 case Instruction::FAdd:
1269 case Instruction::Add:
1273 case Instruction::FSub:
1277 case Instruction::Sub:
1285 case Instruction::FMul:
1286 case Instruction::Mul: {
1288 if (
isNeg(
I->getOperand(0))) {
1290 IsPositive = !IsPositive;
1292 A =
I->getOperand(0);
1295 if (
isNeg(
I->getOperand(1))) {
1297 IsPositive = !IsPositive;
1299 B =
I->getOperand(1);
1301 Muls.push_back(Product{
A,
B, IsPositive});
1304 case Instruction::FNeg:
1307 case Instruction::Call: {
1313 Addends.emplace_back(
I, IsPositive);
1317 bool IsProductPositive = IsPositive;
1320 IsProductPositive = !IsProductPositive;
1325 IsProductPositive = !IsProductPositive;
1328 Muls.push_back(Product{
A,
B, IsProductPositive});
1333 Addends.emplace_back(
I, IsPositive);
1338 if (!
I->getFastMathFlags().allowReassoc()) {
1339 LLVM_DEBUG(
dbgs() <<
"The instruction does not allow reassociation: "
1343 *
Flags &=
I->getFastMathFlags();
1350 AddendList RealAddends, ImagAddends;
1351 if (!Collect(Real, RealMuls, RealAddends) ||
1352 !Collect(Imag, ImagMuls, ImagAddends))
1355 if (RealAddends.size() != ImagAddends.size())
1358 CompositeNode *FinalNode =
nullptr;
1359 if (!RealMuls.
empty() || !ImagMuls.
empty()) {
1362 FinalNode = extractPositiveAddend(RealAddends, ImagAddends);
1363 FinalNode = identifyMultiplications(RealMuls, ImagMuls, FinalNode);
1369 if (!RealAddends.empty() || !ImagAddends.empty()) {
1370 FinalNode = identifyAdditions(RealAddends, ImagAddends, Flags, FinalNode);
1374 assert(FinalNode &&
"FinalNode can not be nullptr here");
1375 assert(FinalNode->Vals.size() == 1);
1377 FinalNode->Vals[0].Real = Real;
1378 FinalNode->Vals[0].Imag = Imag;
1379 submitCompositeNode(FinalNode);
1383bool ComplexDeinterleavingGraph::collectPartialMuls(
1385 SmallVectorImpl<PartialMulCandidate> &PartialMulCandidates) {
1387 auto FindCommonInstruction = [](
const Product &Real,
1388 const Product &Imag) ->
Value * {
1389 if (Real.Multiplicand == Imag.Multiplicand ||
1390 Real.Multiplicand == Imag.Multiplier)
1391 return Real.Multiplicand;
1393 if (Real.Multiplier == Imag.Multiplicand ||
1394 Real.Multiplier == Imag.Multiplier)
1395 return Real.Multiplier;
1404 for (
unsigned i = 0; i < RealMuls.
size(); ++i) {
1405 bool FoundCommon =
false;
1406 for (
unsigned j = 0;
j < ImagMuls.
size(); ++
j) {
1407 auto *Common = FindCommonInstruction(RealMuls[i], ImagMuls[j]);
1411 auto *
A = RealMuls[i].Multiplicand == Common ? RealMuls[i].Multiplier
1412 : RealMuls[i].Multiplicand;
1413 auto *
B = ImagMuls[
j].Multiplicand == Common ? ImagMuls[
j].Multiplier
1414 : ImagMuls[
j].Multiplicand;
1416 auto Node = identifyNode(
A,
B);
1422 Node = identifyNode(
B,
A);
1434ComplexDeinterleavingGraph::CompositeNode *
1435ComplexDeinterleavingGraph::identifyMultiplications(
1436 SmallVectorImpl<Product> &RealMuls, SmallVectorImpl<Product> &ImagMuls,
1438 if (RealMuls.
size() != ImagMuls.
size())
1442 if (!collectPartialMuls(RealMuls, ImagMuls, Info))
1446 DenseMap<Value *, CompositeNode *> CommonToNode;
1447 SmallVector<bool> Processed(
Info.size(),
false);
1448 for (
unsigned I = 0;
I <
Info.size(); ++
I) {
1452 PartialMulCandidate &InfoA =
Info[
I];
1453 for (
unsigned J =
I + 1; J <
Info.size(); ++J) {
1457 PartialMulCandidate &InfoB =
Info[J];
1458 auto *InfoReal = &InfoA;
1459 auto *InfoImag = &InfoB;
1461 auto NodeFromCommon = identifyNode(InfoReal->Common, InfoImag->Common);
1462 if (!NodeFromCommon) {
1464 NodeFromCommon = identifyNode(InfoReal->Common, InfoImag->Common);
1466 if (!NodeFromCommon)
1469 CommonToNode[InfoReal->Common] = NodeFromCommon;
1470 CommonToNode[InfoImag->Common] = NodeFromCommon;
1471 Processed[
I] =
true;
1472 Processed[J] =
true;
1476 SmallVector<bool> ProcessedReal(RealMuls.
size(),
false);
1477 SmallVector<bool> ProcessedImag(ImagMuls.
size(),
false);
1479 for (
auto &PMI : Info) {
1480 if (ProcessedReal[PMI.RealIdx] || ProcessedImag[PMI.ImagIdx])
1483 auto It = CommonToNode.
find(PMI.Common);
1486 if (It == CommonToNode.
end()) {
1488 dbgs() <<
"Unprocessed independent partial multiplication:\n";
1489 for (
auto *
Mul : {&RealMuls[PMI.RealIdx], &RealMuls[PMI.RealIdx]})
1491 <<
" multiplied by " << *
Mul->Multiplicand <<
"\n";
1496 auto &RealMul = RealMuls[PMI.RealIdx];
1497 auto &ImagMul = ImagMuls[PMI.ImagIdx];
1499 auto NodeA = It->second;
1500 auto NodeB = PMI.Node;
1501 auto IsMultiplicandReal = PMI.Common == NodeA->Vals[0].Real;
1516 if ((IsMultiplicandReal && PMI.IsNodeInverted) ||
1517 (!IsMultiplicandReal && !PMI.IsNodeInverted))
1522 if (IsMultiplicandReal) {
1524 if (RealMul.IsPositive && ImagMul.IsPositive)
1526 else if (!RealMul.IsPositive && !ImagMul.IsPositive)
1533 if (!RealMul.IsPositive && ImagMul.IsPositive)
1535 else if (RealMul.IsPositive && !ImagMul.IsPositive)
1542 dbgs() <<
"Identified partial multiplication (X, Y) * (U, V):\n";
1543 dbgs().
indent(4) <<
"X: " << *NodeA->Vals[0].Real <<
"\n";
1544 dbgs().
indent(4) <<
"Y: " << *NodeA->Vals[0].Imag <<
"\n";
1545 dbgs().
indent(4) <<
"U: " << *NodeB->Vals[0].Real <<
"\n";
1546 dbgs().
indent(4) <<
"V: " << *NodeB->Vals[0].Imag <<
"\n";
1547 dbgs().
indent(4) <<
"Rotation - " << (int)Rotation * 90 <<
"\n";
1550 CompositeNode *NodeMul = prepareCompositeNode(
1551 ComplexDeinterleavingOperation::CMulPartial,
nullptr,
nullptr);
1552 NodeMul->Rotation = Rotation;
1553 NodeMul->addOperand(NodeA);
1554 NodeMul->addOperand(NodeB);
1556 NodeMul->addOperand(Result);
1557 submitCompositeNode(NodeMul);
1559 ProcessedReal[PMI.RealIdx] =
true;
1560 ProcessedImag[PMI.ImagIdx] =
true;
1564 if (!
all_of(ProcessedReal, [](
bool V) {
return V; }) ||
1565 !
all_of(ProcessedImag, [](
bool V) {
return V; })) {
1570 dbgs() <<
"Unprocessed products (Real):\n";
1571 for (
size_t i = 0; i < ProcessedReal.size(); ++i) {
1572 if (!ProcessedReal[i])
1573 dbgs().
indent(4) << (RealMuls[i].IsPositive ?
"+" :
"-")
1574 << *RealMuls[i].Multiplier <<
" multiplied by "
1575 << *RealMuls[i].Multiplicand <<
"\n";
1577 dbgs() <<
"Unprocessed products (Imag):\n";
1578 for (
size_t i = 0; i < ProcessedImag.size(); ++i) {
1579 if (!ProcessedImag[i])
1580 dbgs().
indent(4) << (ImagMuls[i].IsPositive ?
"+" :
"-")
1581 << *ImagMuls[i].Multiplier <<
" multiplied by "
1582 << *ImagMuls[i].Multiplicand <<
"\n";
1591ComplexDeinterleavingGraph::CompositeNode *
1592ComplexDeinterleavingGraph::identifyAdditions(
1593 AddendList &RealAddends, AddendList &ImagAddends,
1594 std::optional<FastMathFlags> Flags, CompositeNode *
Accumulator =
nullptr) {
1595 if (RealAddends.size() != ImagAddends.size())
1598 CompositeNode *
Result =
nullptr;
1604 Result = extractPositiveAddend(RealAddends, ImagAddends);
1609 while (!RealAddends.empty()) {
1610 auto ItR = RealAddends.begin();
1611 auto [
R, IsPositiveR] = *ItR;
1613 bool FoundImag =
false;
1614 for (
auto ItI = ImagAddends.begin(); ItI != ImagAddends.end(); ++ItI) {
1615 auto [
I, IsPositiveI] = *ItI;
1617 if (IsPositiveR && IsPositiveI)
1618 Rotation = ComplexDeinterleavingRotation::Rotation_0;
1619 else if (!IsPositiveR && IsPositiveI)
1620 Rotation = ComplexDeinterleavingRotation::Rotation_90;
1621 else if (!IsPositiveR && !IsPositiveI)
1622 Rotation = ComplexDeinterleavingRotation::Rotation_180;
1624 Rotation = ComplexDeinterleavingRotation::Rotation_270;
1626 CompositeNode *AddNode =
nullptr;
1627 if (Rotation == ComplexDeinterleavingRotation::Rotation_0 ||
1628 Rotation == ComplexDeinterleavingRotation::Rotation_180) {
1629 AddNode = identifyNode(R,
I);
1631 AddNode = identifyNode(
I, R);
1635 dbgs() <<
"Identified addition:\n";
1638 dbgs().
indent(4) <<
"Rotation - " << (int)Rotation * 90 <<
"\n";
1641 CompositeNode *TmpNode =
nullptr;
1643 TmpNode = prepareCompositeNode(
1644 ComplexDeinterleavingOperation::Symmetric,
nullptr,
nullptr);
1646 TmpNode->Opcode = Instruction::FAdd;
1647 TmpNode->Flags = *
Flags;
1649 TmpNode->Opcode = Instruction::Add;
1651 }
else if (Rotation ==
1653 TmpNode = prepareCompositeNode(
1654 ComplexDeinterleavingOperation::Symmetric,
nullptr,
nullptr);
1656 TmpNode->Opcode = Instruction::FSub;
1657 TmpNode->Flags = *
Flags;
1659 TmpNode->Opcode = Instruction::Sub;
1662 TmpNode = prepareCompositeNode(ComplexDeinterleavingOperation::CAdd,
1664 TmpNode->Rotation = Rotation;
1667 TmpNode->addOperand(Result);
1668 TmpNode->addOperand(AddNode);
1669 submitCompositeNode(TmpNode);
1671 RealAddends.erase(ItR);
1672 ImagAddends.erase(ItI);
1683ComplexDeinterleavingGraph::CompositeNode *
1684ComplexDeinterleavingGraph::extractPositiveAddend(AddendList &RealAddends,
1685 AddendList &ImagAddends) {
1686 for (
auto ItR = RealAddends.begin(); ItR != RealAddends.end(); ++ItR) {
1687 for (
auto ItI = ImagAddends.begin(); ItI != ImagAddends.end(); ++ItI) {
1688 auto [
R, IsPositiveR] = *ItR;
1689 auto [
I, IsPositiveI] = *ItI;
1690 if (IsPositiveR && IsPositiveI) {
1691 auto Result = identifyNode(R,
I);
1693 RealAddends.erase(ItR);
1694 ImagAddends.erase(ItI);
1703bool ComplexDeinterleavingGraph::identifyNodes(Instruction *RootI) {
1708 auto It = RootToNode.
find(RootI);
1709 if (It != RootToNode.
end()) {
1710 auto RootNode = It->second;
1711 assert(RootNode->Operation ==
1712 ComplexDeinterleavingOperation::ReductionOperation ||
1713 RootNode->Operation ==
1714 ComplexDeinterleavingOperation::ReductionSingle);
1715 assert(RootNode->Vals.size() == 1 &&
1716 "Cannot handle reductions involving multiple complex values");
1725 ReplacementAnchor =
R->comesBefore(
I) ?
I :
R;
1727 ReplacementAnchor =
R;
1729 if (ReplacementAnchor != RootI)
1735 auto RootNode = identifyRoot(RootI);
1742 dbgs() <<
"Complex deinterleaving graph for " <<
F->getName()
1743 <<
"::" <<
B->getName() <<
".\n";
1747 RootToNode[RootI] = RootNode;
1752bool ComplexDeinterleavingGraph::collectPotentialReductions(BasicBlock *
B) {
1753 bool FoundPotentialReduction =
false;
1762 if (Br->getSuccessor(0) !=
B && Br->getSuccessor(1) !=
B)
1765 for (
auto &
PHI :
B->phis()) {
1766 if (
PHI.getNumIncomingValues() != 2)
1769 if (!
PHI.getType()->isVectorTy())
1779 for (
auto *U : ReductionOp->users()) {
1786 if (NumUsers != 2 || !FinalReduction || FinalReduction->
getParent() ==
B ||
1790 ReductionInfo[ReductionOp] = {&
PHI, FinalReduction};
1792 auto BackEdgeIdx =
PHI.getBasicBlockIndex(
B);
1793 auto IncomingIdx = BackEdgeIdx == 0 ? 1 : 0;
1794 Incoming =
PHI.getIncomingBlock(IncomingIdx);
1795 FoundPotentialReduction =
true;
1801 FinalInstructions.
insert(InitPHI);
1803 return FoundPotentialReduction;
1806void ComplexDeinterleavingGraph::identifyReductionNodes() {
1807 assert(Factor == 2 &&
"Cannot handle multiple complex values");
1809 SmallVector<bool> Processed(ReductionInfo.
size(),
false);
1810 SmallVector<Instruction *> OperationInstruction;
1811 for (
auto &
P : ReductionInfo)
1816 for (
size_t i = 0; i < OperationInstruction.
size(); ++i) {
1819 for (
size_t j = i + 1;
j < OperationInstruction.
size(); ++
j) {
1822 auto *Real = OperationInstruction[i];
1823 auto *Imag = OperationInstruction[
j];
1824 if (Real->getType() != Imag->
getType())
1827 RealPHI = ReductionInfo[Real].first;
1828 ImagPHI = ReductionInfo[Imag].first;
1830 auto Node = identifyNode(Real, Imag);
1834 Node = identifyNode(Real, Imag);
1840 if (Node && PHIsFound) {
1841 LLVM_DEBUG(
dbgs() <<
"Identified reduction starting from instructions: "
1842 << *Real <<
" / " << *Imag <<
"\n");
1843 Processed[i] =
true;
1844 Processed[
j] =
true;
1845 auto RootNode = prepareCompositeNode(
1846 ComplexDeinterleavingOperation::ReductionOperation, Real, Imag);
1847 RootNode->addOperand(Node);
1848 RootToNode[Real] = RootNode;
1849 RootToNode[Imag] = RootNode;
1850 submitCompositeNode(RootNode);
1855 auto *Real = OperationInstruction[i];
1858 if (Processed[i] || Real->getNumOperands() < 2)
1862 if (!ReductionInfo[Real].second->getType()->isIntegerTy())
1865 RealPHI = ReductionInfo[Real].first;
1868 auto Node = identifyNode(Real->getOperand(0), Real->getOperand(1));
1869 if (Node && PHIsFound) {
1871 dbgs() <<
"Identified single reduction starting from instruction: "
1872 << *Real <<
"/" << *ReductionInfo[Real].second <<
"\n");
1881 if (ReductionInfo[Real].second->getType()->isVectorTy())
1884 Processed[i] =
true;
1885 auto RootNode = prepareCompositeNode(
1886 ComplexDeinterleavingOperation::ReductionSingle, Real,
nullptr);
1887 RootNode->addOperand(Node);
1888 RootToNode[Real] = RootNode;
1889 submitCompositeNode(RootNode);
1897bool ComplexDeinterleavingGraph::checkNodes() {
1898 bool FoundDeinterleaveNode =
false;
1899 for (CompositeNode *
N : CompositeNodes) {
1900 if (!
N->areOperandsValid())
1903 if (
N->Operation == ComplexDeinterleavingOperation::Deinterleave)
1904 FoundDeinterleaveNode =
true;
1909 if (!FoundDeinterleaveNode) {
1911 dbgs() <<
"Couldn't find a deinterleave node within the graph, cannot "
1912 "guarantee safety during graph transformation.\n");
1917 SmallPtrSet<Instruction *, 16> AllInstructions;
1918 SmallVector<Instruction *, 8> Worklist;
1919 for (
auto &Pair : RootToNode)
1924 while (!Worklist.
empty()) {
1927 if (!AllInstructions.
insert(
I).second)
1932 if (!FinalInstructions.
count(
I))
1939 for (
auto *
I : AllInstructions) {
1941 if (RootToNode.count(
I))
1944 for (User *U :
I->users()) {
1956 SmallPtrSet<Instruction *, 16> Visited;
1957 while (!Worklist.
empty()) {
1959 if (!Visited.
insert(
I).second)
1964 if (RootToNode.count(
I)) {
1966 <<
" could be deinterleaved but its chain of complex "
1967 "operations have an outside user\n");
1968 RootToNode.erase(
I);
1971 if (!AllInstructions.count(
I) || FinalInstructions.
count(
I))
1974 for (User *U :
I->users())
1982 return !RootToNode.empty();
1985ComplexDeinterleavingGraph::CompositeNode *
1986ComplexDeinterleavingGraph::identifyRoot(Instruction *RootI) {
1993 for (
unsigned I = 0;
I < Factor;
I += 2) {
2001 ComplexDeinterleavingGraph::CompositeNode *Node1 = identifyNode(Vals);
2029 return identifyNode(Real, Imag);
2032ComplexDeinterleavingGraph::CompositeNode *
2033ComplexDeinterleavingGraph::identifyDeinterleave(
ComplexValues &Vals) {
2037 auto CheckExtract = [&](
Value *
V,
unsigned ExpectedIdx,
2038 Instruction *ExpectedInsn) -> ExtractValueInst * {
2040 if (!EVI || EVI->getNumIndices() != 1 ||
2041 EVI->getIndices()[0] != ExpectedIdx ||
2043 (ExpectedInsn && ExpectedInsn != EVI->getAggregateOperand()))
2048 for (
unsigned Idx = 0;
Idx < Vals.
size();
Idx++) {
2049 ExtractValueInst *RealEVI = CheckExtract(Vals[Idx].Real, Idx * 2,
II);
2050 if (RealEVI && Idx == 0)
2052 if (!RealEVI || !CheckExtract(Vals[Idx].Imag, (Idx * 2) + 1,
II)) {
2059 if (IntrinsicII->getIntrinsicID() !=
2064 CompositeNode *PlaceholderNode = prepareCompositeNode(
2066 PlaceholderNode->ReplacementNode =
II->getOperand(0);
2067 for (
auto &V : Vals) {
2071 return submitCompositeNode(PlaceholderNode);
2074 if (Vals.size() != 1)
2077 Value *Real = Vals[0].Real;
2078 Value *Imag = Vals[0].Imag;
2081 if (!RealShuffle || !ImagShuffle) {
2082 if (RealShuffle || ImagShuffle)
2083 LLVM_DEBUG(
dbgs() <<
" - There's a shuffle where there shouldn't be.\n");
2087 Value *RealOp1 = RealShuffle->getOperand(1);
2092 Value *ImagOp1 = ImagShuffle->getOperand(1);
2098 Value *RealOp0 = RealShuffle->getOperand(0);
2099 Value *ImagOp0 = ImagShuffle->getOperand(0);
2101 if (RealOp0 != ImagOp0) {
2106 ArrayRef<int> RealMask = RealShuffle->getShuffleMask();
2107 ArrayRef<int> ImagMask = ImagShuffle->getShuffleMask();
2113 if (RealMask[0] != 0 || ImagMask[0] != 1) {
2114 LLVM_DEBUG(
dbgs() <<
" - Masks do not have the correct initial value.\n");
2120 auto CheckType = [&](ShuffleVectorInst *Shuffle) {
2121 Value *
Op = Shuffle->getOperand(0);
2125 if (OpTy->getScalarType() != ShuffleTy->getScalarType())
2127 if ((ShuffleTy->getNumElements() * 2) != OpTy->getNumElements())
2133 auto CheckDeinterleavingShuffle = [&](ShuffleVectorInst *Shuffle) ->
bool {
2137 ArrayRef<int>
Mask = Shuffle->getShuffleMask();
2140 Value *
Op = Shuffle->getOperand(0);
2142 int NumElements = OpTy->getNumElements();
2146 return Last < NumElements;
2149 if (RealShuffle->getType() != ImagShuffle->getType()) {
2153 if (!CheckDeinterleavingShuffle(RealShuffle)) {
2157 if (!CheckDeinterleavingShuffle(ImagShuffle)) {
2162 CompositeNode *PlaceholderNode =
2164 RealShuffle, ImagShuffle);
2165 PlaceholderNode->ReplacementNode = RealShuffle->getOperand(0);
2166 FinalInstructions.
insert(RealShuffle);
2167 FinalInstructions.
insert(ImagShuffle);
2168 return submitCompositeNode(PlaceholderNode);
2171ComplexDeinterleavingGraph::CompositeNode *
2172ComplexDeinterleavingGraph::identifySplat(
ComplexValues &Vals) {
2173 auto IsSplat = [](
Value *
V) ->
bool {
2186 if (
Const->getOpcode() != Instruction::ShuffleVector)
2191 VTy = Shuf->getType();
2192 Mask = Shuf->getShuffleMask();
2200 if (!VTy->isScalableTy() && VTy->getElementCount().getKnownMinValue() == 1)
2210 BasicBlock *FirstBB = FirstValAsInstruction->getParent();
2211 for (
auto &V : Vals) {
2212 if (!IsSplat(
V.Real) || !IsSplat(
V.Imag))
2217 if (!Real || !Imag || Real->getParent() != FirstBB ||
2218 Imag->getParent() != FirstBB)
2222 for (
auto &V : Vals) {
2229 for (
auto &V : Vals) {
2233 FinalInstructions.
insert(Real);
2234 FinalInstructions.
insert(Imag);
2237 CompositeNode *PlaceholderNode =
2238 prepareCompositeNode(ComplexDeinterleavingOperation::Splat, Vals);
2239 return submitCompositeNode(PlaceholderNode);
2242ComplexDeinterleavingGraph::CompositeNode *
2243ComplexDeinterleavingGraph::identifyPHINode(Instruction *Real,
2244 Instruction *Imag) {
2245 if (Real != RealPHI || (ImagPHI && Imag != ImagPHI))
2249 CompositeNode *PlaceholderNode = prepareCompositeNode(
2250 ComplexDeinterleavingOperation::ReductionPHI, Real, Imag);
2251 return submitCompositeNode(PlaceholderNode);
2254ComplexDeinterleavingGraph::CompositeNode *
2255ComplexDeinterleavingGraph::identifySelectNode(Instruction *Real,
2256 Instruction *Imag) {
2259 if (!SelectReal || !SelectImag)
2276 auto NodeA = identifyNode(AR, AI);
2280 auto NodeB = identifyNode(
RA, BI);
2284 CompositeNode *PlaceholderNode = prepareCompositeNode(
2285 ComplexDeinterleavingOperation::ReductionSelect, Real, Imag);
2286 PlaceholderNode->addOperand(NodeA);
2287 PlaceholderNode->addOperand(NodeB);
2288 FinalInstructions.
insert(MaskA);
2289 FinalInstructions.
insert(MaskB);
2290 return submitCompositeNode(PlaceholderNode);
2294 std::optional<FastMathFlags> Flags,
2298 case Instruction::FNeg:
2299 I =
B.CreateFNeg(InputA);
2301 case Instruction::FAdd:
2302 I =
B.CreateFAdd(InputA, InputB);
2304 case Instruction::Add:
2305 I =
B.CreateAdd(InputA, InputB);
2307 case Instruction::FSub:
2308 I =
B.CreateFSub(InputA, InputB);
2310 case Instruction::Sub:
2311 I =
B.CreateSub(InputA, InputB);
2313 case Instruction::FMul:
2314 I =
B.CreateFMul(InputA, InputB);
2316 case Instruction::Mul:
2317 I =
B.CreateMul(InputA, InputB);
2327Value *ComplexDeinterleavingGraph::replaceNode(IRBuilderBase &Builder,
2328 CompositeNode *Node) {
2329 if (
Node->ReplacementNode)
2330 return Node->ReplacementNode;
2332 auto ReplaceOperandIfExist = [&](CompositeNode *
Node,
2334 return Node->Operands.size() >
Idx
2335 ? replaceNode(Builder,
Node->Operands[Idx])
2339 Value *ReplacementNode =
nullptr;
2340 switch (
Node->Operation) {
2341 case ComplexDeinterleavingOperation::CDot: {
2342 Value *Input0 = ReplaceOperandIfExist(Node, 0);
2343 Value *Input1 = ReplaceOperandIfExist(Node, 1);
2346 "Node inputs need to be of the same type"));
2351 case ComplexDeinterleavingOperation::CAdd:
2352 case ComplexDeinterleavingOperation::CMulPartial:
2353 case ComplexDeinterleavingOperation::Symmetric: {
2354 Value *Input0 = ReplaceOperandIfExist(Node, 0);
2355 Value *Input1 = ReplaceOperandIfExist(Node, 1);
2358 "Node inputs need to be of the same type"));
2361 "Accumulator and input need to be of the same type"));
2362 if (
Node->Operation == ComplexDeinterleavingOperation::Symmetric)
2367 Builder,
Node->Operation,
Node->Rotation, Input0, Input1,
2371 case ComplexDeinterleavingOperation::Deinterleave:
2374 case ComplexDeinterleavingOperation::Splat: {
2376 for (
auto &V :
Node->Vals) {
2377 Ops.push_back(
V.Real);
2378 Ops.push_back(
V.Imag);
2385 for (
auto V :
Node->Vals) {
2393 ReplacementNode = IRB.CreateVectorInterleave(
Ops);
2399 case ComplexDeinterleavingOperation::ReductionPHI: {
2404 auto *NewVTy = VectorType::getDoubleElementsVectorType(VTy);
2406 OldToNewPHI[OldPHI] = NewPHI;
2407 ReplacementNode = NewPHI;
2410 case ComplexDeinterleavingOperation::ReductionSingle:
2411 ReplacementNode = replaceNode(Builder,
Node->Operands[0]);
2412 processReductionSingle(ReplacementNode, Node);
2414 case ComplexDeinterleavingOperation::ReductionOperation:
2415 ReplacementNode = replaceNode(Builder,
Node->Operands[0]);
2416 processReductionOperation(ReplacementNode, Node);
2418 case ComplexDeinterleavingOperation::ReductionSelect: {
2421 auto *
A = replaceNode(Builder,
Node->Operands[0]);
2422 auto *
B = replaceNode(Builder,
Node->Operands[1]);
2429 assert(ReplacementNode &&
"Target failed to create Intrinsic call.");
2430 NumComplexTransformations += 1;
2431 Node->ReplacementNode = ReplacementNode;
2432 return ReplacementNode;
2435void ComplexDeinterleavingGraph::processReductionSingle(
2436 Value *OperationReplacement, CompositeNode *Node) {
2438 auto *OldPHI = ReductionInfo[Real].first;
2439 auto *NewPHI = OldToNewPHI[OldPHI];
2441 auto *NewVTy = VectorType::getDoubleElementsVectorType(VTy);
2443 Value *Init = OldPHI->getIncomingValueForBlock(Incoming);
2447 Value *NewInit =
nullptr;
2449 if (
C->isNullValue())
2457 NewPHI->addIncoming(NewInit, Incoming);
2458 NewPHI->addIncoming(OperationReplacement, BackEdge);
2460 auto *FinalReduction = ReductionInfo[Real].second;
2467void ComplexDeinterleavingGraph::processReductionOperation(
2468 Value *OperationReplacement, CompositeNode *Node) {
2471 auto *OldPHIReal = ReductionInfo[Real].first;
2472 auto *OldPHIImag = ReductionInfo[Imag].first;
2473 auto *NewPHI = OldToNewPHI[OldPHIReal];
2476 Value *InitReal = OldPHIReal->getIncomingValueForBlock(Incoming);
2477 Value *InitImag = OldPHIImag->getIncomingValueForBlock(Incoming);
2482 NewPHI->addIncoming(NewInit, Incoming);
2483 NewPHI->addIncoming(OperationReplacement, BackEdge);
2487 auto *FinalReductionReal = ReductionInfo[Real].second;
2488 auto *FinalReductionImag = ReductionInfo[Imag].second;
2491 BasicBlock *ExitBB = Br->getSuccessor(Br->getSuccessor(0) == BackEdge);
2495 OperationReplacement->
getType(),
2496 OperationReplacement);
2499 FinalReductionReal->replaceUsesOfWith(Real, NewReal);
2503 FinalReductionImag->replaceUsesOfWith(Imag, NewImag);
2506void ComplexDeinterleavingGraph::replaceNodes() {
2507 SmallVector<Instruction *, 16> DeadInstrRoots;
2508 for (
auto *RootInstruction : OrderedRoots) {
2511 if (!RootToNode.count(RootInstruction))
2515 auto RootNode = RootToNode[RootInstruction];
2516 Value *
R = replaceNode(Builder, RootNode);
2518 if (RootNode->Operation ==
2519 ComplexDeinterleavingOperation::ReductionOperation) {
2522 ReductionInfo[RootReal].first->removeIncomingValue(BackEdge);
2523 ReductionInfo[RootImag].first->removeIncomingValue(BackEdge);
2526 }
else if (RootNode->Operation ==
2527 ComplexDeinterleavingOperation::ReductionSingle) {
2529 auto &
Info = ReductionInfo[RootInst];
2530 Info.first->removeIncomingValue(BackEdge);
2533 assert(R &&
"Unable to find replacement for RootInstruction");
2534 DeadInstrRoots.
push_back(RootInstruction);
2535 RootInstruction->replaceAllUsesWith(R);
2539 for (
auto *
I : DeadInstrRoots)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static MCDisassembler::DecodeStatus addOperand(MCInst &Inst, const MCOperand &Opnd)
This file defines the BumpPtrAllocator interface.
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool isInstructionPotentiallySymmetric(Instruction *I)
static Value * getNegOperand(Value *V)
Returns the operand for negation operation.
static bool isNeg(Value *V)
Returns true if the operation is a negation of V, and it works for both integers and floats.
static cl::opt< bool > ComplexDeinterleavingEnabled("enable-complex-deinterleaving", cl::desc("Enable generation of complex instructions"), cl::init(true), cl::Hidden)
static bool isInstructionPairAdd(Instruction *A, Instruction *B)
static Value * replaceSymmetricNode(IRBuilderBase &B, unsigned Opcode, std::optional< FastMathFlags > Flags, Value *InputA, Value *InputB)
static bool isInterleavingMask(ArrayRef< int > Mask)
Checks the given mask, and determines whether said mask is interleaving.
static bool isDeinterleavingMask(ArrayRef< int > Mask)
Checks the given mask, and determines whether said mask is deinterleaving.
SmallVector< struct ComplexValue, 2 > ComplexValues
static bool isInstructionPairMul(Instruction *A, Instruction *B)
static bool runOnFunction(Function &F, bool PostInlining)
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
This file implements a map that provides insertion order iteration.
uint64_t IntrinsicInst * II
PowerPC Reduce CR logical Operation
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
SI optimize exec mask operations pre RA
static LLVM_ATTRIBUTE_ALWAYS_INLINE bool CheckType(MVT::SimpleValueType VT, SDValue N, const TargetLowering *TLI, const DataLayout &DL)
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
This file describes how to lower LLVM code to machine code.
AnalysisUsage & addRequired()
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
LLVM_ABI const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
LLVM_ABI InstListType::const_iterator getFirstNonPHIIt() const
Returns an iterator to the first instruction in this block that is not a PHINode instruction.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
iterator find(const_arg_type_t< KeyT > Val)
bool allowContract() const
FunctionPass class - This class is used to implement most global optimizations.
Common base class shared among various IRBuilders.
Value * CreateExtractValue(Value *Agg, ArrayRef< unsigned > Idxs, const Twine &Name="")
LLVM_ABI Value * CreateSelect(Value *C, Value *True, Value *False, const Twine &Name="", Instruction *MDFrom=nullptr)
LLVM_ABI Value * CreateAddReduce(Value *Src)
Create a vector int add reduction intrinsic of the source vector.
LLVM_ABI Value * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > OverloadTypes, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="", ArrayRef< OperandBundleDef > OpBundles={}, function_ref< void(CallInst *)> SetFn=[](CallInst *) {})
Variant to create a possibly constant-folded intrinsic.
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
LLVM_ABI Value * CreateVectorInterleave(ArrayRef< Value * > Ops, const Twine &Name="")
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI bool comesBefore(const Instruction *Other) const
Given an instruction Other in the same basic block as this instruction, return true if this instructi...
LLVM_ABI FastMathFlags getFastMathFlags() const LLVM_READONLY
Convenience function for getting all the fast-math flags, which must be an operator which supports th...
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
LLVM_ABI bool isIdenticalTo(const Instruction *I) const LLVM_READONLY
Return true if the specified instruction is exactly identical to the current one.
static PHINode * Create(Type *Ty, unsigned NumReservedValues, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
Constructors - NumReservedValues is a hint for the number of incoming edges that this phi node will h...
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserve()
Mark an analysis as preserved.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Analysis pass providing the TargetLibraryInfo.
virtual bool isComplexDeinterleavingOperationSupported(ComplexDeinterleavingOperation Operation, Type *Ty) const
Does this target support complex deinterleaving with the given operation and type.
virtual Value * createComplexDeinterleavingIR(IRBuilderBase &B, ComplexDeinterleavingOperation OperationType, ComplexDeinterleavingRotation Rotation, Value *InputA, Value *InputB, Value *Accumulator=nullptr) const
Create the IR node for the given complex deinterleaving operation.
virtual bool isComplexDeinterleavingSupported() const
Does this target support complex deinterleaving.
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
Primary interface to the complete machine description for the target machine.
virtual const TargetSubtargetInfo * getSubtargetImpl(const Function &) const
Virtual method implemented by subclasses that returns a reference to that target's TargetSubtargetInf...
virtual const TargetLowering * getTargetLowering() const
bool isVectorTy() const
True if this is an instance of VectorType.
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
bool hasOneUse() const
Return true if there is exactly one use of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
An opaque object representing a hash code.
const ParentTy * getParent() const
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ BR
Control flow instructions. These all have token chains.
@ BasicBlock
Various leaf nodes.
LLVM_ABI Intrinsic::ID getDeinterleaveIntrinsicID(unsigned Factor)
Returns the corresponding llvm.vector.deinterleaveN intrinsic for factor N.
LLVM_ABI Intrinsic::ID getInterleaveIntrinsicID(unsigned Factor)
Returns the corresponding llvm.vector.interleaveN intrinsic for factor N.
BinaryOp_match< SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB > m_Neg(const SrcTy &&Src)
Matches a register negated by a G_SUB.
BinaryOp_match< LHS, RHS, Instruction::FMul > m_FMul(const LHS &L, const RHS &R)
bool match(Val *V, const Pattern &P)
match_bind< Instruction > m_Instruction(Instruction *&I)
Match an instruction, capturing it if we match.
ThreeOps_match< Cond, LHS, RHS, Instruction::Select > m_Select(const Cond &C, const LHS &L, const RHS &R)
Matches SelectInst.
auto m_BinOp()
Match an arbitrary binary operation and ignore it.
auto m_Value()
Match an arbitrary value and ignore it.
BinaryOp_match< LHS, RHS, Instruction::Mul > m_Mul(const LHS &L, const RHS &R)
TwoOps_match< V1_t, V2_t, Instruction::ShuffleVector > m_Shuffle(const V1_t &v1, const V2_t &v2)
Matches ShuffleVectorInst independently of mask value.
auto m_AnyIntrinsic()
Matches any intrinsic call and ignore it.
is_zero< true > m_Zero()
Match any null constant or a vector with all elements equal to 0.
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
FNeg_match< OpTy, true > m_FNegOrFSubNegZero(const OpTy &X)
Match fneg X or fsub -0.0, X.
initializer< Ty > init(const Ty &Val)
NodeAddr< PhiNode * > Phi
NodeAddr< NodeBase * > Node
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
hash_code hash_value(const FixedPointSemantics &Val)
LLVM_ABI bool RecursivelyDeleteTriviallyDeadInstructions(Value *V, const TargetLibraryInfo *TLI=nullptr, MemorySSAUpdater *MSSAU=nullptr, std::function< void(Value *)> AboutToDeleteCallback=std::function< void(Value *)>())
If the specified value is a trivially dead instruction, delete it.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
auto dyn_cast_or_null(const Y &Val)
ComplexDeinterleavingOperation
LLVM_ABI FunctionPass * createComplexDeinterleavingPass(const TargetMachine *TM)
This pass implements generation of target-specific intrinsics to support handling of complex number a...
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
ComplexDeinterleavingRotation
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
bool all_equal(std::initializer_list< T > Values)
Returns true if all Values in the initializer lists are equal or the list.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
AllocatorList< T, BumpPtrAllocator > BumpPtrList
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
ComplexDeinterleavingPass(const TargetMachine &TM)
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
static bool isEqual(const ComplexValue &LHS, const ComplexValue &RHS)
static unsigned getHashValue(const ComplexValue &Val)
An information struct used to provide DenseMap with the various necessary components for a given valu...