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)
608 if (
I->getOpcode() == Instruction::FNeg)
609 return I->getOperand(0);
611 return I->getOperand(1);
614bool ComplexDeinterleaving::evaluateBasicBlock(BasicBlock *
B,
unsigned Factor) {
615 ComplexDeinterleavingGraph Graph(TL, TLI, Factor);
616 if (Graph.collectPotentialReductions(
B))
617 Graph.identifyReductionNodes();
620 Graph.identifyNodes(&
I);
622 if (Graph.checkNodes()) {
623 Graph.replaceNodes();
630ComplexDeinterleavingGraph::CompositeNode *
631ComplexDeinterleavingGraph::identifyNodeWithImplicitAdd(
632 Instruction *Real, Instruction *Imag,
633 std::pair<Value *, Value *> &PartialMatch) {
634 LLVM_DEBUG(
dbgs() <<
"identifyNodeWithImplicitAdd " << *Real <<
" / " << *Imag
642 if ((Real->
getOpcode() != Instruction::FMul &&
643 Real->
getOpcode() != Instruction::Mul) ||
644 (Imag->
getOpcode() != Instruction::FMul &&
645 Imag->
getOpcode() != Instruction::Mul)) {
647 dbgs() <<
" - Real or imaginary instruction is not fmul or mul\n");
662 }
else if (
isNeg(R1)) {
671 }
else if (
isNeg(I1)) {
679 Value *CommonOperand;
680 Value *UncommonRealOp;
681 Value *UncommonImagOp;
683 if (R0 == I0 || R0 == I1) {
686 }
else if (R1 == I0 || R1 == I1) {
694 UncommonImagOp = (CommonOperand == I0) ? I1 : I0;
695 if (Rotation == ComplexDeinterleavingRotation::Rotation_90 ||
696 Rotation == ComplexDeinterleavingRotation::Rotation_270)
697 std::swap(UncommonRealOp, UncommonImagOp);
701 if (Rotation == ComplexDeinterleavingRotation::Rotation_0 ||
702 Rotation == ComplexDeinterleavingRotation::Rotation_180)
703 PartialMatch.first = CommonOperand;
705 PartialMatch.second = CommonOperand;
707 if (!PartialMatch.first || !PartialMatch.second) {
712 CompositeNode *CommonNode =
713 identifyNode(PartialMatch.first, PartialMatch.second);
719 CompositeNode *UncommonNode = identifyNode(UncommonRealOp, UncommonImagOp);
725 CompositeNode *
Node = prepareCompositeNode(
726 ComplexDeinterleavingOperation::CMulPartial, Real, Imag);
727 Node->Rotation = Rotation;
728 Node->addOperand(CommonNode);
729 Node->addOperand(UncommonNode);
730 return submitCompositeNode(Node);
733ComplexDeinterleavingGraph::CompositeNode *
734ComplexDeinterleavingGraph::identifyPartialMul(Instruction *Real,
736 LLVM_DEBUG(
dbgs() <<
"identifyPartialMul " << *Real <<
" / " << *Imag
740 auto IsAdd = [](
unsigned Op) {
741 return Op == Instruction::FAdd ||
Op == Instruction::Add;
743 auto IsSub = [](
unsigned Op) {
744 return Op == Instruction::FSub ||
Op == Instruction::Sub;
748 Rotation = ComplexDeinterleavingRotation::Rotation_0;
750 Rotation = ComplexDeinterleavingRotation::Rotation_90;
752 Rotation = ComplexDeinterleavingRotation::Rotation_180;
754 Rotation = ComplexDeinterleavingRotation::Rotation_270;
763 LLVM_DEBUG(
dbgs() <<
" - Contract is missing from the FastMath flags.\n");
786 Value *CommonOperand;
787 Value *UncommonRealOp;
788 Value *UncommonImagOp;
790 if (R0 == I0 || R0 == I1) {
793 }
else if (R1 == I0 || R1 == I1) {
801 UncommonImagOp = (CommonOperand == I0) ? I1 : I0;
802 if (Rotation == ComplexDeinterleavingRotation::Rotation_90 ||
803 Rotation == ComplexDeinterleavingRotation::Rotation_270)
804 std::swap(UncommonRealOp, UncommonImagOp);
806 std::pair<Value *, Value *> PartialMatch(
807 (Rotation == ComplexDeinterleavingRotation::Rotation_0 ||
808 Rotation == ComplexDeinterleavingRotation::Rotation_180)
811 (Rotation == ComplexDeinterleavingRotation::Rotation_90 ||
812 Rotation == ComplexDeinterleavingRotation::Rotation_270)
819 if (!CRInst || !CIInst) {
820 LLVM_DEBUG(
dbgs() <<
" - Common operands are not instructions.\n");
824 CompositeNode *CNode =
825 identifyNodeWithImplicitAdd(CRInst, CIInst, PartialMatch);
831 CompositeNode *UncommonRes = identifyNode(UncommonRealOp, UncommonImagOp);
837 assert(PartialMatch.first && PartialMatch.second);
838 CompositeNode *CommonRes =
839 identifyNode(PartialMatch.first, PartialMatch.second);
845 CompositeNode *
Node = prepareCompositeNode(
846 ComplexDeinterleavingOperation::CMulPartial, Real, Imag);
847 Node->Rotation = Rotation;
848 Node->addOperand(CommonRes);
849 Node->addOperand(UncommonRes);
850 Node->addOperand(CNode);
851 return submitCompositeNode(Node);
854ComplexDeinterleavingGraph::CompositeNode *
855ComplexDeinterleavingGraph::identifyAdd(Instruction *Real, Instruction *Imag) {
856 LLVM_DEBUG(
dbgs() <<
"identifyAdd " << *Real <<
" / " << *Imag <<
"\n");
860 if ((Real->
getOpcode() == Instruction::FSub &&
861 Imag->
getOpcode() == Instruction::FAdd) ||
862 (Real->
getOpcode() == Instruction::Sub &&
864 Rotation = ComplexDeinterleavingRotation::Rotation_90;
865 else if ((Real->
getOpcode() == Instruction::FAdd &&
866 Imag->
getOpcode() == Instruction::FSub) ||
867 (Real->
getOpcode() == Instruction::Add &&
869 Rotation = ComplexDeinterleavingRotation::Rotation_270;
871 LLVM_DEBUG(
dbgs() <<
" - Unhandled case, rotation is not assigned.\n");
880 if (!AR || !AI || !BR || !BI) {
885 CompositeNode *ResA = identifyNode(AR, AI);
887 LLVM_DEBUG(
dbgs() <<
" - AR/AI is not identified as a composite node.\n");
890 CompositeNode *ResB = identifyNode(BR, BI);
892 LLVM_DEBUG(
dbgs() <<
" - BR/BI is not identified as a composite node.\n");
896 CompositeNode *
Node =
897 prepareCompositeNode(ComplexDeinterleavingOperation::CAdd, Real, Imag);
898 Node->Rotation = Rotation;
899 Node->addOperand(ResA);
900 Node->addOperand(ResB);
901 return submitCompositeNode(Node);
905 unsigned OpcA =
A->getOpcode();
906 unsigned OpcB =
B->getOpcode();
908 return (OpcA == Instruction::FSub && OpcB == Instruction::FAdd) ||
909 (OpcA == Instruction::FAdd && OpcB == Instruction::FSub) ||
910 (OpcA == Instruction::Sub && OpcB == Instruction::Add) ||
911 (OpcA == Instruction::Add && OpcB == Instruction::Sub);
922 switch (
I->getOpcode()) {
923 case Instruction::FAdd:
924 case Instruction::FSub:
925 case Instruction::FMul:
926 case Instruction::FNeg:
927 case Instruction::Add:
928 case Instruction::Sub:
929 case Instruction::Mul:
936ComplexDeinterleavingGraph::CompositeNode *
937ComplexDeinterleavingGraph::identifySymmetricOperation(
ComplexValues &Vals) {
939 unsigned FirstOpc = FirstReal->getOpcode();
940 for (
auto &V : Vals) {
957 for (
auto &V : Vals) {
963 CompositeNode *Op0 = identifyNode(OpVals);
964 CompositeNode *Op1 =
nullptr;
968 if (FirstReal->isBinaryOp()) {
970 for (
auto &V : Vals) {
975 Op1 = identifyNode(OpVals);
981 prepareCompositeNode(ComplexDeinterleavingOperation::Symmetric, Vals);
982 Node->Opcode = FirstReal->getOpcode();
984 Node->Flags = FirstReal->getFastMathFlags();
986 Node->addOperand(Op0);
987 if (FirstReal->isBinaryOp())
988 Node->addOperand(Op1);
990 return submitCompositeNode(Node);
993ComplexDeinterleavingGraph::CompositeNode *
994ComplexDeinterleavingGraph::identifyDotProduct(
Value *V) {
996 ComplexDeinterleavingOperation::CDot,
V->getType())) {
997 LLVM_DEBUG(
dbgs() <<
"Target doesn't support complex deinterleaving "
998 "operation CDot with the type "
999 << *
V->getType() <<
"\n");
1007 prepareCompositeNode(ComplexDeinterleavingOperation::CDot, Inst,
nullptr);
1009 CompositeNode *ANode =
nullptr;
1011 const Intrinsic::ID PartialReduceInt = Intrinsic::vector_partial_reduce_add;
1013 Value *AReal =
nullptr;
1014 Value *AImag =
nullptr;
1015 Value *BReal =
nullptr;
1016 Value *BImag =
nullptr;
1021 return CI->getOperand(0);
1035 if (
match(Inst, PatternRot0)) {
1036 CN->Rotation = ComplexDeinterleavingRotation::Rotation_0;
1037 }
else if (
match(Inst, PatternRot270)) {
1038 CN->Rotation = ComplexDeinterleavingRotation::Rotation_270;
1049 if (!
match(Inst, PatternRot90Rot180))
1052 A0 = UnwrapCast(A0);
1053 A1 = UnwrapCast(A1);
1056 ANode = identifyNode(A0, A1);
1059 ANode = identifyNode(A1, A0);
1063 CN->Rotation = ComplexDeinterleavingRotation::Rotation_90;
1069 CN->Rotation = ComplexDeinterleavingRotation::Rotation_180;
1073 AReal = UnwrapCast(AReal);
1074 AImag = UnwrapCast(AImag);
1075 BReal = UnwrapCast(BReal);
1076 BImag = UnwrapCast(BImag);
1079 Type *ExpectedOperandTy = VectorType::getSubdividedVectorType(VTy, 2);
1080 if (AReal->
getType() != ExpectedOperandTy)
1082 if (AImag->
getType() != ExpectedOperandTy)
1084 if (BReal->
getType() != ExpectedOperandTy)
1086 if (BImag->
getType() != ExpectedOperandTy)
1089 if (
Phi->getType() != VTy && RealUser->getType() != VTy)
1092 CompositeNode *
Node = identifyNode(AReal, AImag);
1097 if (ANode && Node != ANode) {
1100 <<
"Identified node is different from previously identified node. "
1101 "Unable to confidently generate a complex operation node\n");
1105 CN->addOperand(Node);
1106 CN->addOperand(identifyNode(BReal, BImag));
1107 CN->addOperand(identifyNode(Phi, RealUser));
1109 return submitCompositeNode(CN);
1112ComplexDeinterleavingGraph::CompositeNode *
1113ComplexDeinterleavingGraph::identifyPartialReduction(
Value *R,
Value *
I) {
1118 if (!
R->hasUseList() || !
I->hasUseList())
1122 findCommonBetweenCollections<Value *>(
R->users(),
I->users());
1127 if (!IInst || IInst->getIntrinsicID() != Intrinsic::vector_partial_reduce_add)
1130 if (CompositeNode *CN = identifyDotProduct(IInst))
1136ComplexDeinterleavingGraph::CompositeNode *
1137ComplexDeinterleavingGraph::identifyNode(
ComplexValues &Vals) {
1138 auto It = CachedResult.
find(Vals);
1139 if (It != CachedResult.
end()) {
1144 if (Vals.
size() == 1) {
1145 assert(Factor == 2 &&
"Can only handle interleave factors of 2");
1148 if (CompositeNode *CN = identifyPartialReduction(R,
I))
1150 bool IsReduction = RealPHI ==
R && (!ImagPHI || ImagPHI ==
I);
1151 if (!IsReduction &&
R->getType() !=
I->getType())
1155 if (CompositeNode *CN = identifySplat(Vals))
1158 for (
auto &V : Vals) {
1165 if (CompositeNode *CN = identifyDeinterleave(Vals))
1168 if (Vals.size() == 1) {
1169 assert(Factor == 2 &&
"Can only handle interleave factors of 2");
1172 if (CompositeNode *CN = identifyPHINode(Real, Imag))
1175 if (CompositeNode *CN = identifySelectNode(Real, Imag))
1179 auto *NewVTy = VectorType::getDoubleElementsVectorType(VTy);
1182 ComplexDeinterleavingOperation::CMulPartial, NewVTy);
1184 ComplexDeinterleavingOperation::CAdd, NewVTy);
1187 if (CompositeNode *CN = identifyPartialMul(Real, Imag))
1192 if (CompositeNode *CN = identifyAdd(Real, Imag))
1196 if (HasCMulSupport && HasCAddSupport) {
1197 if (CompositeNode *CN = identifyReassocNodes(Real, Imag)) {
1203 if (CompositeNode *CN = identifySymmetricOperation(Vals))
1207 CachedResult[Vals] =
nullptr;
1211ComplexDeinterleavingGraph::CompositeNode *
1212ComplexDeinterleavingGraph::identifyReassocNodes(Instruction *Real,
1213 Instruction *Imag) {
1214 auto IsOperationSupported = [](
Instruction *
I) ->
bool {
1215 unsigned Opcode =
I->getOpcode();
1217 Opcode == Instruction::FAdd || Opcode == Instruction::FSub ||
1218 Opcode == Instruction::FNeg || Opcode == Instruction::Add ||
1219 Opcode == Instruction::Sub;
1222 if (!IsOperationSupported(Real) || !IsOperationSupported(Imag))
1225 std::optional<FastMathFlags>
Flags;
1228 LLVM_DEBUG(
dbgs() <<
"The flags in Real and Imaginary instructions are "
1234 if (!
Flags->allowReassoc()) {
1237 <<
"the 'Reassoc' attribute is missing in the FastMath flags\n");
1246 AddendList &Addends) ->
bool {
1248 while (!Worklist.
empty()) {
1253 Addends.emplace_back(V, IsPositive);
1263 if (
I != Insn &&
I->hasNUsesOrMore(2)) {
1264 LLVM_DEBUG(
dbgs() <<
"Found potential sub-expression: " << *
I <<
"\n");
1265 Addends.emplace_back(
I, IsPositive);
1268 switch (
I->getOpcode()) {
1269 case Instruction::FAdd:
1270 case Instruction::Add:
1274 case Instruction::FSub:
1278 case Instruction::Sub:
1286 case Instruction::FMul:
1287 case Instruction::Mul: {
1289 if (
isNeg(
I->getOperand(0))) {
1291 IsPositive = !IsPositive;
1293 A =
I->getOperand(0);
1296 if (
isNeg(
I->getOperand(1))) {
1298 IsPositive = !IsPositive;
1300 B =
I->getOperand(1);
1302 Muls.push_back(Product{
A,
B, IsPositive});
1305 case Instruction::FNeg:
1308 case Instruction::Call: {
1314 Addends.emplace_back(
I, IsPositive);
1318 bool IsProductPositive = IsPositive;
1321 IsProductPositive = !IsProductPositive;
1326 IsProductPositive = !IsProductPositive;
1329 Muls.push_back(Product{
A,
B, IsProductPositive});
1334 Addends.emplace_back(
I, IsPositive);
1338 if (Flags &&
I->getFastMathFlags() != *Flags) {
1340 "inconsistent with the root instructions' flags: "
1349 AddendList RealAddends, ImagAddends;
1350 if (!Collect(Real, RealMuls, RealAddends) ||
1351 !Collect(Imag, ImagMuls, ImagAddends))
1354 if (RealAddends.size() != ImagAddends.size())
1357 CompositeNode *FinalNode =
nullptr;
1358 if (!RealMuls.
empty() || !ImagMuls.
empty()) {
1361 FinalNode = extractPositiveAddend(RealAddends, ImagAddends);
1362 FinalNode = identifyMultiplications(RealMuls, ImagMuls, FinalNode);
1368 if (!RealAddends.empty() || !ImagAddends.empty()) {
1369 FinalNode = identifyAdditions(RealAddends, ImagAddends, Flags, FinalNode);
1373 assert(FinalNode &&
"FinalNode can not be nullptr here");
1374 assert(FinalNode->Vals.size() == 1);
1376 FinalNode->Vals[0].Real = Real;
1377 FinalNode->Vals[0].Imag = Imag;
1378 submitCompositeNode(FinalNode);
1382bool ComplexDeinterleavingGraph::collectPartialMuls(
1384 SmallVectorImpl<PartialMulCandidate> &PartialMulCandidates) {
1386 auto FindCommonInstruction = [](
const Product &Real,
1387 const Product &Imag) ->
Value * {
1388 if (Real.Multiplicand == Imag.Multiplicand ||
1389 Real.Multiplicand == Imag.Multiplier)
1390 return Real.Multiplicand;
1392 if (Real.Multiplier == Imag.Multiplicand ||
1393 Real.Multiplier == Imag.Multiplier)
1394 return Real.Multiplier;
1403 for (
unsigned i = 0; i < RealMuls.
size(); ++i) {
1404 bool FoundCommon =
false;
1405 for (
unsigned j = 0;
j < ImagMuls.
size(); ++
j) {
1406 auto *Common = FindCommonInstruction(RealMuls[i], ImagMuls[j]);
1410 auto *
A = RealMuls[i].Multiplicand == Common ? RealMuls[i].Multiplier
1411 : RealMuls[i].Multiplicand;
1412 auto *
B = ImagMuls[
j].Multiplicand == Common ? ImagMuls[
j].Multiplier
1413 : ImagMuls[
j].Multiplicand;
1415 auto Node = identifyNode(
A,
B);
1421 Node = identifyNode(
B,
A);
1433ComplexDeinterleavingGraph::CompositeNode *
1434ComplexDeinterleavingGraph::identifyMultiplications(
1435 SmallVectorImpl<Product> &RealMuls, SmallVectorImpl<Product> &ImagMuls,
1437 if (RealMuls.
size() != ImagMuls.
size())
1441 if (!collectPartialMuls(RealMuls, ImagMuls, Info))
1445 DenseMap<Value *, CompositeNode *> CommonToNode;
1446 SmallVector<bool> Processed(
Info.size(),
false);
1447 for (
unsigned I = 0;
I <
Info.size(); ++
I) {
1451 PartialMulCandidate &InfoA =
Info[
I];
1452 for (
unsigned J =
I + 1; J <
Info.size(); ++J) {
1456 PartialMulCandidate &InfoB =
Info[J];
1457 auto *InfoReal = &InfoA;
1458 auto *InfoImag = &InfoB;
1460 auto NodeFromCommon = identifyNode(InfoReal->Common, InfoImag->Common);
1461 if (!NodeFromCommon) {
1463 NodeFromCommon = identifyNode(InfoReal->Common, InfoImag->Common);
1465 if (!NodeFromCommon)
1468 CommonToNode[InfoReal->Common] = NodeFromCommon;
1469 CommonToNode[InfoImag->Common] = NodeFromCommon;
1470 Processed[
I] =
true;
1471 Processed[J] =
true;
1475 SmallVector<bool> ProcessedReal(RealMuls.
size(),
false);
1476 SmallVector<bool> ProcessedImag(ImagMuls.
size(),
false);
1478 for (
auto &PMI : Info) {
1479 if (ProcessedReal[PMI.RealIdx] || ProcessedImag[PMI.ImagIdx])
1482 auto It = CommonToNode.
find(PMI.Common);
1485 if (It == CommonToNode.
end()) {
1487 dbgs() <<
"Unprocessed independent partial multiplication:\n";
1488 for (
auto *
Mul : {&RealMuls[PMI.RealIdx], &RealMuls[PMI.RealIdx]})
1490 <<
" multiplied by " << *
Mul->Multiplicand <<
"\n";
1495 auto &RealMul = RealMuls[PMI.RealIdx];
1496 auto &ImagMul = ImagMuls[PMI.ImagIdx];
1498 auto NodeA = It->second;
1499 auto NodeB = PMI.Node;
1500 auto IsMultiplicandReal = PMI.Common == NodeA->Vals[0].Real;
1515 if ((IsMultiplicandReal && PMI.IsNodeInverted) ||
1516 (!IsMultiplicandReal && !PMI.IsNodeInverted))
1521 if (IsMultiplicandReal) {
1523 if (RealMul.IsPositive && ImagMul.IsPositive)
1525 else if (!RealMul.IsPositive && !ImagMul.IsPositive)
1532 if (!RealMul.IsPositive && ImagMul.IsPositive)
1534 else if (RealMul.IsPositive && !ImagMul.IsPositive)
1541 dbgs() <<
"Identified partial multiplication (X, Y) * (U, V):\n";
1542 dbgs().
indent(4) <<
"X: " << *NodeA->Vals[0].Real <<
"\n";
1543 dbgs().
indent(4) <<
"Y: " << *NodeA->Vals[0].Imag <<
"\n";
1544 dbgs().
indent(4) <<
"U: " << *NodeB->Vals[0].Real <<
"\n";
1545 dbgs().
indent(4) <<
"V: " << *NodeB->Vals[0].Imag <<
"\n";
1546 dbgs().
indent(4) <<
"Rotation - " << (int)Rotation * 90 <<
"\n";
1549 CompositeNode *NodeMul = prepareCompositeNode(
1550 ComplexDeinterleavingOperation::CMulPartial,
nullptr,
nullptr);
1551 NodeMul->Rotation = Rotation;
1552 NodeMul->addOperand(NodeA);
1553 NodeMul->addOperand(NodeB);
1555 NodeMul->addOperand(Result);
1556 submitCompositeNode(NodeMul);
1558 ProcessedReal[PMI.RealIdx] =
true;
1559 ProcessedImag[PMI.ImagIdx] =
true;
1563 if (!
all_of(ProcessedReal, [](
bool V) {
return V; }) ||
1564 !
all_of(ProcessedImag, [](
bool V) {
return V; })) {
1569 dbgs() <<
"Unprocessed products (Real):\n";
1570 for (
size_t i = 0; i < ProcessedReal.size(); ++i) {
1571 if (!ProcessedReal[i])
1572 dbgs().
indent(4) << (RealMuls[i].IsPositive ?
"+" :
"-")
1573 << *RealMuls[i].Multiplier <<
" multiplied by "
1574 << *RealMuls[i].Multiplicand <<
"\n";
1576 dbgs() <<
"Unprocessed products (Imag):\n";
1577 for (
size_t i = 0; i < ProcessedImag.size(); ++i) {
1578 if (!ProcessedImag[i])
1579 dbgs().
indent(4) << (ImagMuls[i].IsPositive ?
"+" :
"-")
1580 << *ImagMuls[i].Multiplier <<
" multiplied by "
1581 << *ImagMuls[i].Multiplicand <<
"\n";
1590ComplexDeinterleavingGraph::CompositeNode *
1591ComplexDeinterleavingGraph::identifyAdditions(
1592 AddendList &RealAddends, AddendList &ImagAddends,
1593 std::optional<FastMathFlags> Flags, CompositeNode *
Accumulator =
nullptr) {
1594 if (RealAddends.size() != ImagAddends.size())
1597 CompositeNode *
Result =
nullptr;
1603 Result = extractPositiveAddend(RealAddends, ImagAddends);
1608 while (!RealAddends.empty()) {
1609 auto ItR = RealAddends.begin();
1610 auto [
R, IsPositiveR] = *ItR;
1612 bool FoundImag =
false;
1613 for (
auto ItI = ImagAddends.begin(); ItI != ImagAddends.end(); ++ItI) {
1614 auto [
I, IsPositiveI] = *ItI;
1616 if (IsPositiveR && IsPositiveI)
1617 Rotation = ComplexDeinterleavingRotation::Rotation_0;
1618 else if (!IsPositiveR && IsPositiveI)
1619 Rotation = ComplexDeinterleavingRotation::Rotation_90;
1620 else if (!IsPositiveR && !IsPositiveI)
1621 Rotation = ComplexDeinterleavingRotation::Rotation_180;
1623 Rotation = ComplexDeinterleavingRotation::Rotation_270;
1625 CompositeNode *AddNode =
nullptr;
1626 if (Rotation == ComplexDeinterleavingRotation::Rotation_0 ||
1627 Rotation == ComplexDeinterleavingRotation::Rotation_180) {
1628 AddNode = identifyNode(R,
I);
1630 AddNode = identifyNode(
I, R);
1634 dbgs() <<
"Identified addition:\n";
1637 dbgs().
indent(4) <<
"Rotation - " << (int)Rotation * 90 <<
"\n";
1640 CompositeNode *TmpNode =
nullptr;
1642 TmpNode = prepareCompositeNode(
1643 ComplexDeinterleavingOperation::Symmetric,
nullptr,
nullptr);
1645 TmpNode->Opcode = Instruction::FAdd;
1646 TmpNode->Flags = *
Flags;
1648 TmpNode->Opcode = Instruction::Add;
1650 }
else if (Rotation ==
1652 TmpNode = prepareCompositeNode(
1653 ComplexDeinterleavingOperation::Symmetric,
nullptr,
nullptr);
1655 TmpNode->Opcode = Instruction::FSub;
1656 TmpNode->Flags = *
Flags;
1658 TmpNode->Opcode = Instruction::Sub;
1661 TmpNode = prepareCompositeNode(ComplexDeinterleavingOperation::CAdd,
1663 TmpNode->Rotation = Rotation;
1666 TmpNode->addOperand(Result);
1667 TmpNode->addOperand(AddNode);
1668 submitCompositeNode(TmpNode);
1670 RealAddends.erase(ItR);
1671 ImagAddends.erase(ItI);
1682ComplexDeinterleavingGraph::CompositeNode *
1683ComplexDeinterleavingGraph::extractPositiveAddend(AddendList &RealAddends,
1684 AddendList &ImagAddends) {
1685 for (
auto ItR = RealAddends.begin(); ItR != RealAddends.end(); ++ItR) {
1686 for (
auto ItI = ImagAddends.begin(); ItI != ImagAddends.end(); ++ItI) {
1687 auto [
R, IsPositiveR] = *ItR;
1688 auto [
I, IsPositiveI] = *ItI;
1689 if (IsPositiveR && IsPositiveI) {
1690 auto Result = identifyNode(R,
I);
1692 RealAddends.erase(ItR);
1693 ImagAddends.erase(ItI);
1702bool ComplexDeinterleavingGraph::identifyNodes(Instruction *RootI) {
1707 auto It = RootToNode.
find(RootI);
1708 if (It != RootToNode.
end()) {
1709 auto RootNode = It->second;
1710 assert(RootNode->Operation ==
1711 ComplexDeinterleavingOperation::ReductionOperation ||
1712 RootNode->Operation ==
1713 ComplexDeinterleavingOperation::ReductionSingle);
1714 assert(RootNode->Vals.size() == 1 &&
1715 "Cannot handle reductions involving multiple complex values");
1724 ReplacementAnchor =
R->comesBefore(
I) ?
I :
R;
1726 ReplacementAnchor =
R;
1728 if (ReplacementAnchor != RootI)
1734 auto RootNode = identifyRoot(RootI);
1741 dbgs() <<
"Complex deinterleaving graph for " <<
F->getName()
1742 <<
"::" <<
B->getName() <<
".\n";
1746 RootToNode[RootI] = RootNode;
1751bool ComplexDeinterleavingGraph::collectPotentialReductions(BasicBlock *
B) {
1752 bool FoundPotentialReduction =
false;
1761 if (Br->getSuccessor(0) !=
B && Br->getSuccessor(1) !=
B)
1764 for (
auto &
PHI :
B->phis()) {
1765 if (
PHI.getNumIncomingValues() != 2)
1768 if (!
PHI.getType()->isVectorTy())
1778 for (
auto *U : ReductionOp->users()) {
1785 if (NumUsers != 2 || !FinalReduction || FinalReduction->
getParent() ==
B ||
1789 ReductionInfo[ReductionOp] = {&
PHI, FinalReduction};
1791 auto BackEdgeIdx =
PHI.getBasicBlockIndex(
B);
1792 auto IncomingIdx = BackEdgeIdx == 0 ? 1 : 0;
1793 Incoming =
PHI.getIncomingBlock(IncomingIdx);
1794 FoundPotentialReduction =
true;
1800 FinalInstructions.
insert(InitPHI);
1802 return FoundPotentialReduction;
1805void ComplexDeinterleavingGraph::identifyReductionNodes() {
1806 assert(Factor == 2 &&
"Cannot handle multiple complex values");
1808 SmallVector<bool> Processed(ReductionInfo.
size(),
false);
1809 SmallVector<Instruction *> OperationInstruction;
1810 for (
auto &
P : ReductionInfo)
1815 for (
size_t i = 0; i < OperationInstruction.
size(); ++i) {
1818 for (
size_t j = i + 1;
j < OperationInstruction.
size(); ++
j) {
1821 auto *Real = OperationInstruction[i];
1822 auto *Imag = OperationInstruction[
j];
1823 if (Real->getType() != Imag->
getType())
1826 RealPHI = ReductionInfo[Real].first;
1827 ImagPHI = ReductionInfo[Imag].first;
1829 auto Node = identifyNode(Real, Imag);
1833 Node = identifyNode(Real, Imag);
1839 if (Node && PHIsFound) {
1840 LLVM_DEBUG(
dbgs() <<
"Identified reduction starting from instructions: "
1841 << *Real <<
" / " << *Imag <<
"\n");
1842 Processed[i] =
true;
1843 Processed[
j] =
true;
1844 auto RootNode = prepareCompositeNode(
1845 ComplexDeinterleavingOperation::ReductionOperation, Real, Imag);
1846 RootNode->addOperand(Node);
1847 RootToNode[Real] = RootNode;
1848 RootToNode[Imag] = RootNode;
1849 submitCompositeNode(RootNode);
1854 auto *Real = OperationInstruction[i];
1857 if (Processed[i] || Real->getNumOperands() < 2)
1861 if (!ReductionInfo[Real].second->getType()->isIntegerTy())
1864 RealPHI = ReductionInfo[Real].first;
1867 auto Node = identifyNode(Real->getOperand(0), Real->getOperand(1));
1868 if (Node && PHIsFound) {
1870 dbgs() <<
"Identified single reduction starting from instruction: "
1871 << *Real <<
"/" << *ReductionInfo[Real].second <<
"\n");
1880 if (ReductionInfo[Real].second->getType()->isVectorTy())
1883 Processed[i] =
true;
1884 auto RootNode = prepareCompositeNode(
1885 ComplexDeinterleavingOperation::ReductionSingle, Real,
nullptr);
1886 RootNode->addOperand(Node);
1887 RootToNode[Real] = RootNode;
1888 submitCompositeNode(RootNode);
1896bool ComplexDeinterleavingGraph::checkNodes() {
1897 bool FoundDeinterleaveNode =
false;
1898 for (CompositeNode *
N : CompositeNodes) {
1899 if (!
N->areOperandsValid())
1902 if (
N->Operation == ComplexDeinterleavingOperation::Deinterleave)
1903 FoundDeinterleaveNode =
true;
1908 if (!FoundDeinterleaveNode) {
1910 dbgs() <<
"Couldn't find a deinterleave node within the graph, cannot "
1911 "guarantee safety during graph transformation.\n");
1916 SmallPtrSet<Instruction *, 16> AllInstructions;
1917 SmallVector<Instruction *, 8> Worklist;
1918 for (
auto &Pair : RootToNode)
1923 while (!Worklist.
empty()) {
1926 if (!AllInstructions.
insert(
I).second)
1931 if (!FinalInstructions.
count(
I))
1938 for (
auto *
I : AllInstructions) {
1940 if (RootToNode.count(
I))
1943 for (User *U :
I->users()) {
1955 SmallPtrSet<Instruction *, 16> Visited;
1956 while (!Worklist.
empty()) {
1958 if (!Visited.
insert(
I).second)
1963 if (RootToNode.count(
I)) {
1965 <<
" could be deinterleaved but its chain of complex "
1966 "operations have an outside user\n");
1967 RootToNode.erase(
I);
1970 if (!AllInstructions.count(
I) || FinalInstructions.
count(
I))
1973 for (User *U :
I->users())
1981 return !RootToNode.empty();
1984ComplexDeinterleavingGraph::CompositeNode *
1985ComplexDeinterleavingGraph::identifyRoot(Instruction *RootI) {
1992 for (
unsigned I = 0;
I < Factor;
I += 2) {
2000 ComplexDeinterleavingGraph::CompositeNode *Node1 = identifyNode(Vals);
2028 return identifyNode(Real, Imag);
2031ComplexDeinterleavingGraph::CompositeNode *
2032ComplexDeinterleavingGraph::identifyDeinterleave(
ComplexValues &Vals) {
2036 auto CheckExtract = [&](
Value *
V,
unsigned ExpectedIdx,
2037 Instruction *ExpectedInsn) -> ExtractValueInst * {
2039 if (!EVI || EVI->getNumIndices() != 1 ||
2040 EVI->getIndices()[0] != ExpectedIdx ||
2042 (ExpectedInsn && ExpectedInsn != EVI->getAggregateOperand()))
2047 for (
unsigned Idx = 0; Idx < Vals.
size(); Idx++) {
2048 ExtractValueInst *RealEVI = CheckExtract(Vals[Idx].Real, Idx * 2,
II);
2049 if (RealEVI && Idx == 0)
2051 if (!RealEVI || !CheckExtract(Vals[Idx].Imag, (Idx * 2) + 1,
II)) {
2058 if (IntrinsicII->getIntrinsicID() !=
2063 CompositeNode *PlaceholderNode = prepareCompositeNode(
2065 PlaceholderNode->ReplacementNode =
II->getOperand(0);
2066 for (
auto &V : Vals) {
2070 return submitCompositeNode(PlaceholderNode);
2073 if (Vals.size() != 1)
2076 Value *Real = Vals[0].Real;
2077 Value *Imag = Vals[0].Imag;
2080 if (!RealShuffle || !ImagShuffle) {
2081 if (RealShuffle || ImagShuffle)
2082 LLVM_DEBUG(
dbgs() <<
" - There's a shuffle where there shouldn't be.\n");
2086 Value *RealOp1 = RealShuffle->getOperand(1);
2091 Value *ImagOp1 = ImagShuffle->getOperand(1);
2097 Value *RealOp0 = RealShuffle->getOperand(0);
2098 Value *ImagOp0 = ImagShuffle->getOperand(0);
2100 if (RealOp0 != ImagOp0) {
2105 ArrayRef<int> RealMask = RealShuffle->getShuffleMask();
2106 ArrayRef<int> ImagMask = ImagShuffle->getShuffleMask();
2112 if (RealMask[0] != 0 || ImagMask[0] != 1) {
2113 LLVM_DEBUG(
dbgs() <<
" - Masks do not have the correct initial value.\n");
2119 auto CheckType = [&](ShuffleVectorInst *Shuffle) {
2120 Value *
Op = Shuffle->getOperand(0);
2124 if (OpTy->getScalarType() != ShuffleTy->getScalarType())
2126 if ((ShuffleTy->getNumElements() * 2) != OpTy->getNumElements())
2132 auto CheckDeinterleavingShuffle = [&](ShuffleVectorInst *Shuffle) ->
bool {
2136 ArrayRef<int>
Mask = Shuffle->getShuffleMask();
2139 Value *
Op = Shuffle->getOperand(0);
2141 int NumElements = OpTy->getNumElements();
2145 return Last < NumElements;
2148 if (RealShuffle->getType() != ImagShuffle->getType()) {
2152 if (!CheckDeinterleavingShuffle(RealShuffle)) {
2156 if (!CheckDeinterleavingShuffle(ImagShuffle)) {
2161 CompositeNode *PlaceholderNode =
2163 RealShuffle, ImagShuffle);
2164 PlaceholderNode->ReplacementNode = RealShuffle->getOperand(0);
2165 FinalInstructions.
insert(RealShuffle);
2166 FinalInstructions.
insert(ImagShuffle);
2167 return submitCompositeNode(PlaceholderNode);
2170ComplexDeinterleavingGraph::CompositeNode *
2171ComplexDeinterleavingGraph::identifySplat(
ComplexValues &Vals) {
2172 auto IsSplat = [](
Value *
V) ->
bool {
2185 if (
Const->getOpcode() != Instruction::ShuffleVector)
2190 VTy = Shuf->getType();
2191 Mask = Shuf->getShuffleMask();
2199 if (!VTy->isScalableTy() && VTy->getElementCount().getKnownMinValue() == 1)
2209 BasicBlock *FirstBB = FirstValAsInstruction->getParent();
2210 for (
auto &V : Vals) {
2211 if (!IsSplat(
V.Real) || !IsSplat(
V.Imag))
2216 if (!Real || !Imag || Real->getParent() != FirstBB ||
2217 Imag->getParent() != FirstBB)
2221 for (
auto &V : Vals) {
2228 for (
auto &V : Vals) {
2232 FinalInstructions.
insert(Real);
2233 FinalInstructions.
insert(Imag);
2236 CompositeNode *PlaceholderNode =
2237 prepareCompositeNode(ComplexDeinterleavingOperation::Splat, Vals);
2238 return submitCompositeNode(PlaceholderNode);
2241ComplexDeinterleavingGraph::CompositeNode *
2242ComplexDeinterleavingGraph::identifyPHINode(Instruction *Real,
2243 Instruction *Imag) {
2244 if (Real != RealPHI || (ImagPHI && Imag != ImagPHI))
2248 CompositeNode *PlaceholderNode = prepareCompositeNode(
2249 ComplexDeinterleavingOperation::ReductionPHI, Real, Imag);
2250 return submitCompositeNode(PlaceholderNode);
2253ComplexDeinterleavingGraph::CompositeNode *
2254ComplexDeinterleavingGraph::identifySelectNode(Instruction *Real,
2255 Instruction *Imag) {
2258 if (!SelectReal || !SelectImag)
2275 auto NodeA = identifyNode(AR, AI);
2279 auto NodeB = identifyNode(
RA, BI);
2283 CompositeNode *PlaceholderNode = prepareCompositeNode(
2284 ComplexDeinterleavingOperation::ReductionSelect, Real, Imag);
2285 PlaceholderNode->addOperand(NodeA);
2286 PlaceholderNode->addOperand(NodeB);
2287 FinalInstructions.
insert(MaskA);
2288 FinalInstructions.
insert(MaskB);
2289 return submitCompositeNode(PlaceholderNode);
2293 std::optional<FastMathFlags> Flags,
2297 case Instruction::FNeg:
2298 I =
B.CreateFNeg(InputA);
2300 case Instruction::FAdd:
2301 I =
B.CreateFAdd(InputA, InputB);
2303 case Instruction::Add:
2304 I =
B.CreateAdd(InputA, InputB);
2306 case Instruction::FSub:
2307 I =
B.CreateFSub(InputA, InputB);
2309 case Instruction::Sub:
2310 I =
B.CreateSub(InputA, InputB);
2312 case Instruction::FMul:
2313 I =
B.CreateFMul(InputA, InputB);
2315 case Instruction::Mul:
2316 I =
B.CreateMul(InputA, InputB);
2326Value *ComplexDeinterleavingGraph::replaceNode(IRBuilderBase &Builder,
2327 CompositeNode *Node) {
2328 if (
Node->ReplacementNode)
2329 return Node->ReplacementNode;
2331 auto ReplaceOperandIfExist = [&](CompositeNode *
Node,
2332 unsigned Idx) ->
Value * {
2333 return Node->Operands.size() > Idx
2334 ? replaceNode(Builder,
Node->Operands[Idx])
2338 Value *ReplacementNode =
nullptr;
2339 switch (
Node->Operation) {
2340 case ComplexDeinterleavingOperation::CDot: {
2341 Value *Input0 = ReplaceOperandIfExist(Node, 0);
2342 Value *Input1 = ReplaceOperandIfExist(Node, 1);
2345 "Node inputs need to be of the same type"));
2350 case ComplexDeinterleavingOperation::CAdd:
2351 case ComplexDeinterleavingOperation::CMulPartial:
2352 case ComplexDeinterleavingOperation::Symmetric: {
2353 Value *Input0 = ReplaceOperandIfExist(Node, 0);
2354 Value *Input1 = ReplaceOperandIfExist(Node, 1);
2357 "Node inputs need to be of the same type"));
2360 "Accumulator and input need to be of the same type"));
2361 if (
Node->Operation == ComplexDeinterleavingOperation::Symmetric)
2366 Builder,
Node->Operation,
Node->Rotation, Input0, Input1,
2370 case ComplexDeinterleavingOperation::Deinterleave:
2373 case ComplexDeinterleavingOperation::Splat: {
2375 for (
auto &V :
Node->Vals) {
2376 Ops.push_back(
V.Real);
2377 Ops.push_back(
V.Imag);
2384 for (
auto V :
Node->Vals) {
2392 ReplacementNode = IRB.CreateVectorInterleave(
Ops);
2398 case ComplexDeinterleavingOperation::ReductionPHI: {
2403 auto *NewVTy = VectorType::getDoubleElementsVectorType(VTy);
2405 OldToNewPHI[OldPHI] = NewPHI;
2406 ReplacementNode = NewPHI;
2409 case ComplexDeinterleavingOperation::ReductionSingle:
2410 ReplacementNode = replaceNode(Builder,
Node->Operands[0]);
2411 processReductionSingle(ReplacementNode, Node);
2413 case ComplexDeinterleavingOperation::ReductionOperation:
2414 ReplacementNode = replaceNode(Builder,
Node->Operands[0]);
2415 processReductionOperation(ReplacementNode, Node);
2417 case ComplexDeinterleavingOperation::ReductionSelect: {
2420 auto *
A = replaceNode(Builder,
Node->Operands[0]);
2421 auto *
B = replaceNode(Builder,
Node->Operands[1]);
2428 assert(ReplacementNode &&
"Target failed to create Intrinsic call.");
2429 NumComplexTransformations += 1;
2430 Node->ReplacementNode = ReplacementNode;
2431 return ReplacementNode;
2434void ComplexDeinterleavingGraph::processReductionSingle(
2435 Value *OperationReplacement, CompositeNode *Node) {
2437 auto *OldPHI = ReductionInfo[Real].first;
2438 auto *NewPHI = OldToNewPHI[OldPHI];
2440 auto *NewVTy = VectorType::getDoubleElementsVectorType(VTy);
2442 Value *Init = OldPHI->getIncomingValueForBlock(Incoming);
2446 Value *NewInit =
nullptr;
2448 if (
C->isNullValue())
2456 NewPHI->addIncoming(NewInit, Incoming);
2457 NewPHI->addIncoming(OperationReplacement, BackEdge);
2459 auto *FinalReduction = ReductionInfo[Real].second;
2466void ComplexDeinterleavingGraph::processReductionOperation(
2467 Value *OperationReplacement, CompositeNode *Node) {
2470 auto *OldPHIReal = ReductionInfo[Real].first;
2471 auto *OldPHIImag = ReductionInfo[Imag].first;
2472 auto *NewPHI = OldToNewPHI[OldPHIReal];
2475 Value *InitReal = OldPHIReal->getIncomingValueForBlock(Incoming);
2476 Value *InitImag = OldPHIImag->getIncomingValueForBlock(Incoming);
2481 NewPHI->addIncoming(NewInit, Incoming);
2482 NewPHI->addIncoming(OperationReplacement, BackEdge);
2486 auto *FinalReductionReal = ReductionInfo[Real].second;
2487 auto *FinalReductionImag = ReductionInfo[Imag].second;
2490 BasicBlock *ExitBB = Br->getSuccessor(Br->getSuccessor(0) == BackEdge);
2494 OperationReplacement->
getType(),
2495 OperationReplacement);
2498 FinalReductionReal->replaceUsesOfWith(Real, NewReal);
2502 FinalReductionImag->replaceUsesOfWith(Imag, NewImag);
2505void ComplexDeinterleavingGraph::replaceNodes() {
2506 SmallVector<Instruction *, 16> DeadInstrRoots;
2507 for (
auto *RootInstruction : OrderedRoots) {
2510 if (!RootToNode.count(RootInstruction))
2514 auto RootNode = RootToNode[RootInstruction];
2515 Value *
R = replaceNode(Builder, RootNode);
2517 if (RootNode->Operation ==
2518 ComplexDeinterleavingOperation::ReductionOperation) {
2521 ReductionInfo[RootReal].first->removeIncomingValue(BackEdge);
2522 ReductionInfo[RootImag].first->removeIncomingValue(BackEdge);
2525 }
else if (RootNode->Operation ==
2526 ComplexDeinterleavingOperation::ReductionSingle) {
2528 auto &
Info = ReductionInfo[RootInst];
2529 Info.first->removeIncomingValue(BackEdge);
2532 assert(R &&
"Unable to find replacement for RootInstruction");
2533 DeadInstrRoots.
push_back(RootInstruction);
2534 RootInstruction->replaceAllUsesWith(R);
2538 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.
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
FNeg_match< OpTy > m_FNeg(const OpTy &X)
Match 'fneg X' as 'fsub -0.0, X'.
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
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.
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
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
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...