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);
1320 IsPositive = !IsPositive;
1325 IsPositive = !IsPositive;
1328 Muls.push_back(Product{
A,
B, IsPositive});
1333 Addends.emplace_back(
I, IsPositive);
1337 if (Flags &&
I->getFastMathFlags() != *Flags) {
1339 "inconsistent with the root instructions' flags: "
1348 AddendList RealAddends, ImagAddends;
1349 if (!Collect(Real, RealMuls, RealAddends) ||
1350 !Collect(Imag, ImagMuls, ImagAddends))
1353 if (RealAddends.size() != ImagAddends.size())
1356 CompositeNode *FinalNode =
nullptr;
1357 if (!RealMuls.
empty() || !ImagMuls.
empty()) {
1360 FinalNode = extractPositiveAddend(RealAddends, ImagAddends);
1361 FinalNode = identifyMultiplications(RealMuls, ImagMuls, FinalNode);
1367 if (!RealAddends.empty() || !ImagAddends.empty()) {
1368 FinalNode = identifyAdditions(RealAddends, ImagAddends, Flags, FinalNode);
1372 assert(FinalNode &&
"FinalNode can not be nullptr here");
1373 assert(FinalNode->Vals.size() == 1);
1375 FinalNode->Vals[0].Real = Real;
1376 FinalNode->Vals[0].Imag = Imag;
1377 submitCompositeNode(FinalNode);
1381bool ComplexDeinterleavingGraph::collectPartialMuls(
1383 SmallVectorImpl<PartialMulCandidate> &PartialMulCandidates) {
1385 auto FindCommonInstruction = [](
const Product &Real,
1386 const Product &Imag) ->
Value * {
1387 if (Real.Multiplicand == Imag.Multiplicand ||
1388 Real.Multiplicand == Imag.Multiplier)
1389 return Real.Multiplicand;
1391 if (Real.Multiplier == Imag.Multiplicand ||
1392 Real.Multiplier == Imag.Multiplier)
1393 return Real.Multiplier;
1402 for (
unsigned i = 0; i < RealMuls.
size(); ++i) {
1403 bool FoundCommon =
false;
1404 for (
unsigned j = 0;
j < ImagMuls.
size(); ++
j) {
1405 auto *Common = FindCommonInstruction(RealMuls[i], ImagMuls[j]);
1409 auto *
A = RealMuls[i].Multiplicand == Common ? RealMuls[i].Multiplier
1410 : RealMuls[i].Multiplicand;
1411 auto *
B = ImagMuls[
j].Multiplicand == Common ? ImagMuls[
j].Multiplier
1412 : ImagMuls[
j].Multiplicand;
1414 auto Node = identifyNode(
A,
B);
1420 Node = identifyNode(
B,
A);
1432ComplexDeinterleavingGraph::CompositeNode *
1433ComplexDeinterleavingGraph::identifyMultiplications(
1434 SmallVectorImpl<Product> &RealMuls, SmallVectorImpl<Product> &ImagMuls,
1436 if (RealMuls.
size() != ImagMuls.
size())
1440 if (!collectPartialMuls(RealMuls, ImagMuls, Info))
1444 DenseMap<Value *, CompositeNode *> CommonToNode;
1445 SmallVector<bool> Processed(
Info.size(),
false);
1446 for (
unsigned I = 0;
I <
Info.size(); ++
I) {
1450 PartialMulCandidate &InfoA =
Info[
I];
1451 for (
unsigned J =
I + 1; J <
Info.size(); ++J) {
1455 PartialMulCandidate &InfoB =
Info[J];
1456 auto *InfoReal = &InfoA;
1457 auto *InfoImag = &InfoB;
1459 auto NodeFromCommon = identifyNode(InfoReal->Common, InfoImag->Common);
1460 if (!NodeFromCommon) {
1462 NodeFromCommon = identifyNode(InfoReal->Common, InfoImag->Common);
1464 if (!NodeFromCommon)
1467 CommonToNode[InfoReal->Common] = NodeFromCommon;
1468 CommonToNode[InfoImag->Common] = NodeFromCommon;
1469 Processed[
I] =
true;
1470 Processed[J] =
true;
1474 SmallVector<bool> ProcessedReal(RealMuls.
size(),
false);
1475 SmallVector<bool> ProcessedImag(ImagMuls.
size(),
false);
1477 for (
auto &PMI : Info) {
1478 if (ProcessedReal[PMI.RealIdx] || ProcessedImag[PMI.ImagIdx])
1481 auto It = CommonToNode.
find(PMI.Common);
1484 if (It == CommonToNode.
end()) {
1486 dbgs() <<
"Unprocessed independent partial multiplication:\n";
1487 for (
auto *
Mul : {&RealMuls[PMI.RealIdx], &RealMuls[PMI.RealIdx]})
1489 <<
" multiplied by " << *
Mul->Multiplicand <<
"\n";
1494 auto &RealMul = RealMuls[PMI.RealIdx];
1495 auto &ImagMul = ImagMuls[PMI.ImagIdx];
1497 auto NodeA = It->second;
1498 auto NodeB = PMI.Node;
1499 auto IsMultiplicandReal = PMI.Common == NodeA->Vals[0].Real;
1514 if ((IsMultiplicandReal && PMI.IsNodeInverted) ||
1515 (!IsMultiplicandReal && !PMI.IsNodeInverted))
1520 if (IsMultiplicandReal) {
1522 if (RealMul.IsPositive && ImagMul.IsPositive)
1524 else if (!RealMul.IsPositive && !ImagMul.IsPositive)
1531 if (!RealMul.IsPositive && ImagMul.IsPositive)
1533 else if (RealMul.IsPositive && !ImagMul.IsPositive)
1540 dbgs() <<
"Identified partial multiplication (X, Y) * (U, V):\n";
1541 dbgs().
indent(4) <<
"X: " << *NodeA->Vals[0].Real <<
"\n";
1542 dbgs().
indent(4) <<
"Y: " << *NodeA->Vals[0].Imag <<
"\n";
1543 dbgs().
indent(4) <<
"U: " << *NodeB->Vals[0].Real <<
"\n";
1544 dbgs().
indent(4) <<
"V: " << *NodeB->Vals[0].Imag <<
"\n";
1545 dbgs().
indent(4) <<
"Rotation - " << (int)Rotation * 90 <<
"\n";
1548 CompositeNode *NodeMul = prepareCompositeNode(
1549 ComplexDeinterleavingOperation::CMulPartial,
nullptr,
nullptr);
1550 NodeMul->Rotation = Rotation;
1551 NodeMul->addOperand(NodeA);
1552 NodeMul->addOperand(NodeB);
1554 NodeMul->addOperand(Result);
1555 submitCompositeNode(NodeMul);
1557 ProcessedReal[PMI.RealIdx] =
true;
1558 ProcessedImag[PMI.ImagIdx] =
true;
1562 if (!
all_of(ProcessedReal, [](
bool V) {
return V; }) ||
1563 !
all_of(ProcessedImag, [](
bool V) {
return V; })) {
1568 dbgs() <<
"Unprocessed products (Real):\n";
1569 for (
size_t i = 0; i < ProcessedReal.size(); ++i) {
1570 if (!ProcessedReal[i])
1571 dbgs().
indent(4) << (RealMuls[i].IsPositive ?
"+" :
"-")
1572 << *RealMuls[i].Multiplier <<
" multiplied by "
1573 << *RealMuls[i].Multiplicand <<
"\n";
1575 dbgs() <<
"Unprocessed products (Imag):\n";
1576 for (
size_t i = 0; i < ProcessedImag.size(); ++i) {
1577 if (!ProcessedImag[i])
1578 dbgs().
indent(4) << (ImagMuls[i].IsPositive ?
"+" :
"-")
1579 << *ImagMuls[i].Multiplier <<
" multiplied by "
1580 << *ImagMuls[i].Multiplicand <<
"\n";
1589ComplexDeinterleavingGraph::CompositeNode *
1590ComplexDeinterleavingGraph::identifyAdditions(
1591 AddendList &RealAddends, AddendList &ImagAddends,
1592 std::optional<FastMathFlags> Flags, CompositeNode *
Accumulator =
nullptr) {
1593 if (RealAddends.size() != ImagAddends.size())
1596 CompositeNode *
Result =
nullptr;
1602 Result = extractPositiveAddend(RealAddends, ImagAddends);
1607 while (!RealAddends.empty()) {
1608 auto ItR = RealAddends.begin();
1609 auto [
R, IsPositiveR] = *ItR;
1611 bool FoundImag =
false;
1612 for (
auto ItI = ImagAddends.begin(); ItI != ImagAddends.end(); ++ItI) {
1613 auto [
I, IsPositiveI] = *ItI;
1615 if (IsPositiveR && IsPositiveI)
1616 Rotation = ComplexDeinterleavingRotation::Rotation_0;
1617 else if (!IsPositiveR && IsPositiveI)
1618 Rotation = ComplexDeinterleavingRotation::Rotation_90;
1619 else if (!IsPositiveR && !IsPositiveI)
1620 Rotation = ComplexDeinterleavingRotation::Rotation_180;
1622 Rotation = ComplexDeinterleavingRotation::Rotation_270;
1624 CompositeNode *AddNode =
nullptr;
1625 if (Rotation == ComplexDeinterleavingRotation::Rotation_0 ||
1626 Rotation == ComplexDeinterleavingRotation::Rotation_180) {
1627 AddNode = identifyNode(R,
I);
1629 AddNode = identifyNode(
I, R);
1633 dbgs() <<
"Identified addition:\n";
1636 dbgs().
indent(4) <<
"Rotation - " << (int)Rotation * 90 <<
"\n";
1639 CompositeNode *TmpNode =
nullptr;
1641 TmpNode = prepareCompositeNode(
1642 ComplexDeinterleavingOperation::Symmetric,
nullptr,
nullptr);
1644 TmpNode->Opcode = Instruction::FAdd;
1645 TmpNode->Flags = *
Flags;
1647 TmpNode->Opcode = Instruction::Add;
1649 }
else if (Rotation ==
1651 TmpNode = prepareCompositeNode(
1652 ComplexDeinterleavingOperation::Symmetric,
nullptr,
nullptr);
1654 TmpNode->Opcode = Instruction::FSub;
1655 TmpNode->Flags = *
Flags;
1657 TmpNode->Opcode = Instruction::Sub;
1660 TmpNode = prepareCompositeNode(ComplexDeinterleavingOperation::CAdd,
1662 TmpNode->Rotation = Rotation;
1665 TmpNode->addOperand(Result);
1666 TmpNode->addOperand(AddNode);
1667 submitCompositeNode(TmpNode);
1669 RealAddends.erase(ItR);
1670 ImagAddends.erase(ItI);
1681ComplexDeinterleavingGraph::CompositeNode *
1682ComplexDeinterleavingGraph::extractPositiveAddend(AddendList &RealAddends,
1683 AddendList &ImagAddends) {
1684 for (
auto ItR = RealAddends.begin(); ItR != RealAddends.end(); ++ItR) {
1685 for (
auto ItI = ImagAddends.begin(); ItI != ImagAddends.end(); ++ItI) {
1686 auto [
R, IsPositiveR] = *ItR;
1687 auto [
I, IsPositiveI] = *ItI;
1688 if (IsPositiveR && IsPositiveI) {
1689 auto Result = identifyNode(R,
I);
1691 RealAddends.erase(ItR);
1692 ImagAddends.erase(ItI);
1701bool ComplexDeinterleavingGraph::identifyNodes(Instruction *RootI) {
1706 auto It = RootToNode.
find(RootI);
1707 if (It != RootToNode.
end()) {
1708 auto RootNode = It->second;
1709 assert(RootNode->Operation ==
1710 ComplexDeinterleavingOperation::ReductionOperation ||
1711 RootNode->Operation ==
1712 ComplexDeinterleavingOperation::ReductionSingle);
1713 assert(RootNode->Vals.size() == 1 &&
1714 "Cannot handle reductions involving multiple complex values");
1723 ReplacementAnchor =
R->comesBefore(
I) ?
I :
R;
1725 ReplacementAnchor =
R;
1727 if (ReplacementAnchor != RootI)
1733 auto RootNode = identifyRoot(RootI);
1740 dbgs() <<
"Complex deinterleaving graph for " <<
F->getName()
1741 <<
"::" <<
B->getName() <<
".\n";
1745 RootToNode[RootI] = RootNode;
1750bool ComplexDeinterleavingGraph::collectPotentialReductions(BasicBlock *
B) {
1751 bool FoundPotentialReduction =
false;
1760 if (Br->getSuccessor(0) !=
B && Br->getSuccessor(1) !=
B)
1763 for (
auto &
PHI :
B->phis()) {
1764 if (
PHI.getNumIncomingValues() != 2)
1767 if (!
PHI.getType()->isVectorTy())
1777 for (
auto *U : ReductionOp->users()) {
1784 if (NumUsers != 2 || !FinalReduction || FinalReduction->
getParent() ==
B ||
1788 ReductionInfo[ReductionOp] = {&
PHI, FinalReduction};
1790 auto BackEdgeIdx =
PHI.getBasicBlockIndex(
B);
1791 auto IncomingIdx = BackEdgeIdx == 0 ? 1 : 0;
1792 Incoming =
PHI.getIncomingBlock(IncomingIdx);
1793 FoundPotentialReduction =
true;
1799 FinalInstructions.
insert(InitPHI);
1801 return FoundPotentialReduction;
1804void ComplexDeinterleavingGraph::identifyReductionNodes() {
1805 assert(Factor == 2 &&
"Cannot handle multiple complex values");
1807 SmallVector<bool> Processed(ReductionInfo.
size(),
false);
1808 SmallVector<Instruction *> OperationInstruction;
1809 for (
auto &
P : ReductionInfo)
1814 for (
size_t i = 0; i < OperationInstruction.
size(); ++i) {
1817 for (
size_t j = i + 1;
j < OperationInstruction.
size(); ++
j) {
1820 auto *Real = OperationInstruction[i];
1821 auto *Imag = OperationInstruction[
j];
1822 if (Real->getType() != Imag->
getType())
1825 RealPHI = ReductionInfo[Real].first;
1826 ImagPHI = ReductionInfo[Imag].first;
1828 auto Node = identifyNode(Real, Imag);
1832 Node = identifyNode(Real, Imag);
1838 if (Node && PHIsFound) {
1839 LLVM_DEBUG(
dbgs() <<
"Identified reduction starting from instructions: "
1840 << *Real <<
" / " << *Imag <<
"\n");
1841 Processed[i] =
true;
1842 Processed[
j] =
true;
1843 auto RootNode = prepareCompositeNode(
1844 ComplexDeinterleavingOperation::ReductionOperation, Real, Imag);
1845 RootNode->addOperand(Node);
1846 RootToNode[Real] = RootNode;
1847 RootToNode[Imag] = RootNode;
1848 submitCompositeNode(RootNode);
1853 auto *Real = OperationInstruction[i];
1856 if (Processed[i] || Real->getNumOperands() < 2)
1860 if (!ReductionInfo[Real].second->getType()->isIntegerTy())
1863 RealPHI = ReductionInfo[Real].first;
1866 auto Node = identifyNode(Real->getOperand(0), Real->getOperand(1));
1867 if (Node && PHIsFound) {
1869 dbgs() <<
"Identified single reduction starting from instruction: "
1870 << *Real <<
"/" << *ReductionInfo[Real].second <<
"\n");
1879 if (ReductionInfo[Real].second->getType()->isVectorTy())
1882 Processed[i] =
true;
1883 auto RootNode = prepareCompositeNode(
1884 ComplexDeinterleavingOperation::ReductionSingle, Real,
nullptr);
1885 RootNode->addOperand(Node);
1886 RootToNode[Real] = RootNode;
1887 submitCompositeNode(RootNode);
1895bool ComplexDeinterleavingGraph::checkNodes() {
1896 bool FoundDeinterleaveNode =
false;
1897 for (CompositeNode *
N : CompositeNodes) {
1898 if (!
N->areOperandsValid())
1901 if (
N->Operation == ComplexDeinterleavingOperation::Deinterleave)
1902 FoundDeinterleaveNode =
true;
1907 if (!FoundDeinterleaveNode) {
1909 dbgs() <<
"Couldn't find a deinterleave node within the graph, cannot "
1910 "guarantee safety during graph transformation.\n");
1915 SmallPtrSet<Instruction *, 16> AllInstructions;
1916 SmallVector<Instruction *, 8> Worklist;
1917 for (
auto &Pair : RootToNode)
1922 while (!Worklist.
empty()) {
1925 if (!AllInstructions.
insert(
I).second)
1930 if (!FinalInstructions.
count(
I))
1937 for (
auto *
I : AllInstructions) {
1939 if (RootToNode.count(
I))
1942 for (User *U :
I->users()) {
1954 SmallPtrSet<Instruction *, 16> Visited;
1955 while (!Worklist.
empty()) {
1957 if (!Visited.
insert(
I).second)
1962 if (RootToNode.count(
I)) {
1964 <<
" could be deinterleaved but its chain of complex "
1965 "operations have an outside user\n");
1966 RootToNode.erase(
I);
1969 if (!AllInstructions.count(
I) || FinalInstructions.
count(
I))
1972 for (User *U :
I->users())
1980 return !RootToNode.empty();
1983ComplexDeinterleavingGraph::CompositeNode *
1984ComplexDeinterleavingGraph::identifyRoot(Instruction *RootI) {
1991 for (
unsigned I = 0;
I < Factor;
I += 2) {
1999 ComplexDeinterleavingGraph::CompositeNode *Node1 = identifyNode(Vals);
2027 return identifyNode(Real, Imag);
2030ComplexDeinterleavingGraph::CompositeNode *
2031ComplexDeinterleavingGraph::identifyDeinterleave(
ComplexValues &Vals) {
2035 auto CheckExtract = [&](
Value *
V,
unsigned ExpectedIdx,
2036 Instruction *ExpectedInsn) -> ExtractValueInst * {
2038 if (!EVI || EVI->getNumIndices() != 1 ||
2039 EVI->getIndices()[0] != ExpectedIdx ||
2041 (ExpectedInsn && ExpectedInsn != EVI->getAggregateOperand()))
2046 for (
unsigned Idx = 0; Idx < Vals.
size(); Idx++) {
2047 ExtractValueInst *RealEVI = CheckExtract(Vals[Idx].Real, Idx * 2,
II);
2048 if (RealEVI && Idx == 0)
2050 if (!RealEVI || !CheckExtract(Vals[Idx].Imag, (Idx * 2) + 1,
II)) {
2057 if (IntrinsicII->getIntrinsicID() !=
2062 CompositeNode *PlaceholderNode = prepareCompositeNode(
2064 PlaceholderNode->ReplacementNode =
II->getOperand(0);
2065 for (
auto &V : Vals) {
2069 return submitCompositeNode(PlaceholderNode);
2072 if (Vals.size() != 1)
2075 Value *Real = Vals[0].Real;
2076 Value *Imag = Vals[0].Imag;
2079 if (!RealShuffle || !ImagShuffle) {
2080 if (RealShuffle || ImagShuffle)
2081 LLVM_DEBUG(
dbgs() <<
" - There's a shuffle where there shouldn't be.\n");
2085 Value *RealOp1 = RealShuffle->getOperand(1);
2090 Value *ImagOp1 = ImagShuffle->getOperand(1);
2096 Value *RealOp0 = RealShuffle->getOperand(0);
2097 Value *ImagOp0 = ImagShuffle->getOperand(0);
2099 if (RealOp0 != ImagOp0) {
2104 ArrayRef<int> RealMask = RealShuffle->getShuffleMask();
2105 ArrayRef<int> ImagMask = ImagShuffle->getShuffleMask();
2111 if (RealMask[0] != 0 || ImagMask[0] != 1) {
2112 LLVM_DEBUG(
dbgs() <<
" - Masks do not have the correct initial value.\n");
2118 auto CheckType = [&](ShuffleVectorInst *Shuffle) {
2119 Value *
Op = Shuffle->getOperand(0);
2123 if (OpTy->getScalarType() != ShuffleTy->getScalarType())
2125 if ((ShuffleTy->getNumElements() * 2) != OpTy->getNumElements())
2131 auto CheckDeinterleavingShuffle = [&](ShuffleVectorInst *Shuffle) ->
bool {
2135 ArrayRef<int>
Mask = Shuffle->getShuffleMask();
2138 Value *
Op = Shuffle->getOperand(0);
2140 int NumElements = OpTy->getNumElements();
2144 return Last < NumElements;
2147 if (RealShuffle->getType() != ImagShuffle->getType()) {
2151 if (!CheckDeinterleavingShuffle(RealShuffle)) {
2155 if (!CheckDeinterleavingShuffle(ImagShuffle)) {
2160 CompositeNode *PlaceholderNode =
2162 RealShuffle, ImagShuffle);
2163 PlaceholderNode->ReplacementNode = RealShuffle->getOperand(0);
2164 FinalInstructions.
insert(RealShuffle);
2165 FinalInstructions.
insert(ImagShuffle);
2166 return submitCompositeNode(PlaceholderNode);
2169ComplexDeinterleavingGraph::CompositeNode *
2170ComplexDeinterleavingGraph::identifySplat(
ComplexValues &Vals) {
2171 auto IsSplat = [](
Value *
V) ->
bool {
2184 if (
Const->getOpcode() != Instruction::ShuffleVector)
2189 VTy = Shuf->getType();
2190 Mask = Shuf->getShuffleMask();
2198 if (!VTy->isScalableTy() && VTy->getElementCount().getKnownMinValue() == 1)
2208 BasicBlock *FirstBB = FirstValAsInstruction->getParent();
2209 for (
auto &V : Vals) {
2210 if (!IsSplat(
V.Real) || !IsSplat(
V.Imag))
2215 if (!Real || !Imag || Real->getParent() != FirstBB ||
2216 Imag->getParent() != FirstBB)
2220 for (
auto &V : Vals) {
2227 for (
auto &V : Vals) {
2231 FinalInstructions.
insert(Real);
2232 FinalInstructions.
insert(Imag);
2235 CompositeNode *PlaceholderNode =
2236 prepareCompositeNode(ComplexDeinterleavingOperation::Splat, Vals);
2237 return submitCompositeNode(PlaceholderNode);
2240ComplexDeinterleavingGraph::CompositeNode *
2241ComplexDeinterleavingGraph::identifyPHINode(Instruction *Real,
2242 Instruction *Imag) {
2243 if (Real != RealPHI || (ImagPHI && Imag != ImagPHI))
2247 CompositeNode *PlaceholderNode = prepareCompositeNode(
2248 ComplexDeinterleavingOperation::ReductionPHI, Real, Imag);
2249 return submitCompositeNode(PlaceholderNode);
2252ComplexDeinterleavingGraph::CompositeNode *
2253ComplexDeinterleavingGraph::identifySelectNode(Instruction *Real,
2254 Instruction *Imag) {
2257 if (!SelectReal || !SelectImag)
2274 auto NodeA = identifyNode(AR, AI);
2278 auto NodeB = identifyNode(
RA, BI);
2282 CompositeNode *PlaceholderNode = prepareCompositeNode(
2283 ComplexDeinterleavingOperation::ReductionSelect, Real, Imag);
2284 PlaceholderNode->addOperand(NodeA);
2285 PlaceholderNode->addOperand(NodeB);
2286 FinalInstructions.
insert(MaskA);
2287 FinalInstructions.
insert(MaskB);
2288 return submitCompositeNode(PlaceholderNode);
2292 std::optional<FastMathFlags> Flags,
2296 case Instruction::FNeg:
2297 I =
B.CreateFNeg(InputA);
2299 case Instruction::FAdd:
2300 I =
B.CreateFAdd(InputA, InputB);
2302 case Instruction::Add:
2303 I =
B.CreateAdd(InputA, InputB);
2305 case Instruction::FSub:
2306 I =
B.CreateFSub(InputA, InputB);
2308 case Instruction::Sub:
2309 I =
B.CreateSub(InputA, InputB);
2311 case Instruction::FMul:
2312 I =
B.CreateFMul(InputA, InputB);
2314 case Instruction::Mul:
2315 I =
B.CreateMul(InputA, InputB);
2325Value *ComplexDeinterleavingGraph::replaceNode(IRBuilderBase &Builder,
2326 CompositeNode *Node) {
2327 if (
Node->ReplacementNode)
2328 return Node->ReplacementNode;
2330 auto ReplaceOperandIfExist = [&](CompositeNode *
Node,
2331 unsigned Idx) ->
Value * {
2332 return Node->Operands.size() > Idx
2333 ? replaceNode(Builder,
Node->Operands[Idx])
2337 Value *ReplacementNode =
nullptr;
2338 switch (
Node->Operation) {
2339 case ComplexDeinterleavingOperation::CDot: {
2340 Value *Input0 = ReplaceOperandIfExist(Node, 0);
2341 Value *Input1 = ReplaceOperandIfExist(Node, 1);
2344 "Node inputs need to be of the same type"));
2349 case ComplexDeinterleavingOperation::CAdd:
2350 case ComplexDeinterleavingOperation::CMulPartial:
2351 case ComplexDeinterleavingOperation::Symmetric: {
2352 Value *Input0 = ReplaceOperandIfExist(Node, 0);
2353 Value *Input1 = ReplaceOperandIfExist(Node, 1);
2356 "Node inputs need to be of the same type"));
2359 "Accumulator and input need to be of the same type"));
2360 if (
Node->Operation == ComplexDeinterleavingOperation::Symmetric)
2365 Builder,
Node->Operation,
Node->Rotation, Input0, Input1,
2369 case ComplexDeinterleavingOperation::Deinterleave:
2372 case ComplexDeinterleavingOperation::Splat: {
2374 for (
auto &V :
Node->Vals) {
2375 Ops.push_back(
V.Real);
2376 Ops.push_back(
V.Imag);
2383 for (
auto V :
Node->Vals) {
2391 ReplacementNode = IRB.CreateVectorInterleave(
Ops);
2397 case ComplexDeinterleavingOperation::ReductionPHI: {
2402 auto *NewVTy = VectorType::getDoubleElementsVectorType(VTy);
2404 OldToNewPHI[OldPHI] = NewPHI;
2405 ReplacementNode = NewPHI;
2408 case ComplexDeinterleavingOperation::ReductionSingle:
2409 ReplacementNode = replaceNode(Builder,
Node->Operands[0]);
2410 processReductionSingle(ReplacementNode, Node);
2412 case ComplexDeinterleavingOperation::ReductionOperation:
2413 ReplacementNode = replaceNode(Builder,
Node->Operands[0]);
2414 processReductionOperation(ReplacementNode, Node);
2416 case ComplexDeinterleavingOperation::ReductionSelect: {
2419 auto *
A = replaceNode(Builder,
Node->Operands[0]);
2420 auto *
B = replaceNode(Builder,
Node->Operands[1]);
2427 assert(ReplacementNode &&
"Target failed to create Intrinsic call.");
2428 NumComplexTransformations += 1;
2429 Node->ReplacementNode = ReplacementNode;
2430 return ReplacementNode;
2433void ComplexDeinterleavingGraph::processReductionSingle(
2434 Value *OperationReplacement, CompositeNode *Node) {
2436 auto *OldPHI = ReductionInfo[Real].first;
2437 auto *NewPHI = OldToNewPHI[OldPHI];
2439 auto *NewVTy = VectorType::getDoubleElementsVectorType(VTy);
2441 Value *Init = OldPHI->getIncomingValueForBlock(Incoming);
2445 Value *NewInit =
nullptr;
2447 if (
C->isNullValue())
2455 NewPHI->addIncoming(NewInit, Incoming);
2456 NewPHI->addIncoming(OperationReplacement, BackEdge);
2458 auto *FinalReduction = ReductionInfo[Real].second;
2465void ComplexDeinterleavingGraph::processReductionOperation(
2466 Value *OperationReplacement, CompositeNode *Node) {
2469 auto *OldPHIReal = ReductionInfo[Real].first;
2470 auto *OldPHIImag = ReductionInfo[Imag].first;
2471 auto *NewPHI = OldToNewPHI[OldPHIReal];
2474 Value *InitReal = OldPHIReal->getIncomingValueForBlock(Incoming);
2475 Value *InitImag = OldPHIImag->getIncomingValueForBlock(Incoming);
2480 NewPHI->addIncoming(NewInit, Incoming);
2481 NewPHI->addIncoming(OperationReplacement, BackEdge);
2485 auto *FinalReductionReal = ReductionInfo[Real].second;
2486 auto *FinalReductionImag = ReductionInfo[Imag].second;
2489 BasicBlock *ExitBB = Br->getSuccessor(Br->getSuccessor(0) == BackEdge);
2493 OperationReplacement->
getType(),
2494 OperationReplacement);
2497 FinalReductionReal->replaceUsesOfWith(Real, NewReal);
2501 FinalReductionImag->replaceUsesOfWith(Imag, NewImag);
2504void ComplexDeinterleavingGraph::replaceNodes() {
2505 SmallVector<Instruction *, 16> DeadInstrRoots;
2506 for (
auto *RootInstruction : OrderedRoots) {
2509 if (!RootToNode.count(RootInstruction))
2513 auto RootNode = RootToNode[RootInstruction];
2514 Value *
R = replaceNode(Builder, RootNode);
2516 if (RootNode->Operation ==
2517 ComplexDeinterleavingOperation::ReductionOperation) {
2520 ReductionInfo[RootReal].first->removeIncomingValue(BackEdge);
2521 ReductionInfo[RootImag].first->removeIncomingValue(BackEdge);
2524 }
else if (RootNode->Operation ==
2525 ComplexDeinterleavingOperation::ReductionSingle) {
2527 auto &
Info = ReductionInfo[RootInst];
2528 Info.first->removeIncomingValue(BackEdge);
2531 assert(R &&
"Unable to find replacement for RootInstruction");
2532 DeadInstrRoots.
push_back(RootInstruction);
2533 RootInstruction->replaceAllUsesWith(R);
2537 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...