1 //===--- AMDGPUExportClusting.cpp - AMDGPU Export Clustering  -------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 /// \file This file contains a DAG scheduling mutation to cluster shader
10 ///       exports.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "AMDGPUExportClustering.h"
15 #include "AMDGPUSubtarget.h"
16 #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
17 #include "SIInstrInfo.h"
18 
19 using namespace llvm;
20 
21 namespace {
22 
23 class ExportClustering : public ScheduleDAGMutation {
24 public:
25   ExportClustering() {}
26   void apply(ScheduleDAGInstrs *DAG) override;
27 };
28 
29 static bool isExport(const SUnit &SU) {
30   const MachineInstr *MI = SU.getInstr();
31   return MI->getOpcode() == AMDGPU::EXP ||
32          MI->getOpcode() == AMDGPU::EXP_DONE;
33 }
34 
35 static void buildCluster(ArrayRef<SUnit *> Exports, ScheduleDAGInstrs *DAG) {
36   // Cluster a series of exports. Also copy all dependencies to the first
37   // export to avoid computation being inserted into the chain.
38   SUnit *ChainHead = Exports[0];
39   for (unsigned Idx = 0, End = Exports.size() - 1; Idx < End; ++Idx) {
40     SUnit *SUa = Exports[Idx];
41     SUnit *SUb = Exports[Idx + 1];
42     if (DAG->addEdge(SUb, SDep(SUa, SDep::Cluster))) {
43       for (const SDep &Pred : SUb->Preds) {
44         SUnit *PredSU = Pred.getSUnit();
45         if (Pred.isWeak() || isExport(*PredSU))
46           continue;
47         DAG->addEdge(ChainHead, SDep(PredSU, SDep::Artificial));
48       }
49     }
50   }
51 }
52 
53 void ExportClustering::apply(ScheduleDAGInstrs *DAG) {
54   SmallVector<SmallVector<SUnit *, 8>, 4> ExportChains;
55   DenseMap<unsigned, unsigned> ChainMap;
56 
57   // Build chains of exports
58   for (SUnit &SU : DAG->SUnits) {
59     if (!isExport(SU))
60       continue;
61 
62     unsigned ChainID = ExportChains.size();
63     for (const SDep &Pred : SU.Preds) {
64       const SUnit &PredSU = *Pred.getSUnit();
65       if (isExport(PredSU) && !Pred.isArtificial()) {
66         ChainID = ChainMap.lookup(PredSU.NodeNum);
67         break;
68       }
69     }
70     ChainMap[SU.NodeNum] = ChainID;
71 
72     if (ChainID == ExportChains.size())
73       ExportChains.push_back(SmallVector<SUnit *, 8>());
74 
75     auto &Chain = ExportChains[ChainID];
76     Chain.push_back(&SU);
77   }
78 
79   // Apply clustering
80   for (auto &Chain : ExportChains)
81     buildCluster(Chain, DAG);
82 }
83 
84 } // end namespace
85 
86 namespace llvm {
87 
88 std::unique_ptr<ScheduleDAGMutation> createAMDGPUExportClusteringDAGMutation() {
89   return std::make_unique<ExportClustering>();
90 }
91 
92 } // end namespace llvm
93