1414
1515#include " llvm-c/Transforms/IntrinsicsOpenMP.h"
1616#include " CGIntrinsicsOpenMP.h"
17+ #include " llvm/ADT/Optional.h"
18+ #include " llvm/ADT/SmallVector.h"
1719#include " llvm/ADT/Statistic.h"
20+ #include " llvm/Analysis/PostDominators.h"
1821#include " llvm/Frontend/OpenMP/OMP.h.inc"
1922#include " llvm/Frontend/OpenMP/OMPConstants.h"
2023#include " llvm/Frontend/OpenMP/OMPIRBuilder.h"
2528#include " llvm/IR/Verifier.h"
2629#include " llvm/Pass.h"
2730#include " llvm/Passes/PassBuilder.h"
31+ #include " llvm/Support/ErrorHandling.h"
2832#include " llvm/Support/raw_ostream.h"
2933#include " llvm/Transforms/IPO/PassManagerBuilder.h"
3034#include " llvm/Transforms/IntrinsicsOpenMP/IntrinsicsOpenMP.h"
3135#include " llvm/Transforms/Utils/BasicBlockUtils.h"
3236#include " llvm/Transforms/Utils/ModuleUtils.h"
37+ #include < algorithm>
3338#include < memory>
3439
3540using namespace llvm ;
@@ -43,27 +48,36 @@ STATISTIC(NumOpenMPRegions, "Counts number of OpenMP regions created");
4348
4449namespace {
4550
51+ class DirectiveRegionAnalysis ;
52+
53+ class DirectiveRegion ;
54+ SmallVector<std::unique_ptr<DirectiveRegion>, 8 > DirectiveRegionStorage;
55+
4656class DirectiveRegion {
4757public:
4858 DirectiveRegion () = delete ;
4959
50- void addNested (DirectiveRegion *DR) {
51- // TODO: add into the nest, under the innermost nested directive.
52- }
60+ void addNested (DirectiveRegionAnalysis &DRA, DirectiveRegion *DR);
5361
54- const SmallVector<DirectiveRegion *, 4 > &getNested () { return Nested; }
62+ const SmallVector<DirectiveRegion *, 4 > &getNested () const { return Nested; }
5563
56- CallBase *getEntry () { return CBEntry; }
64+ CallBase *getEntry () const { return CBEntry; }
5765
58- CallBase *getExit () { return CBExit; }
66+ CallBase *getExit () const { return CBExit; }
5967
6068 void setParent (DirectiveRegion *P) { Parent = P; }
6169
62- const DirectiveRegion *getParent () { return Parent; }
70+ DirectiveRegion *getParent () const { return Parent; }
71+
72+ StringRef getTag () const {
73+ return getEntry ()->getOperandBundleAt (0 ).getTagName ();
74+ }
6375
6476 static DirectiveRegion *create (CallBase *CBEntry, CallBase *CBExit) {
65- DirectiveRegion *DR = new DirectiveRegion (CBEntry, CBExit);
66- return DR;
77+ // Use global storage of unique_ptr for auto-cleanup.
78+ DirectiveRegionStorage.push_back (
79+ std::unique_ptr<DirectiveRegion>(new DirectiveRegion{CBEntry, CBExit}));
80+ return DirectiveRegionStorage.back ().get ();
6781 }
6882
6983private:
@@ -73,9 +87,48 @@ class DirectiveRegion {
7387 SmallVector<DirectiveRegion *, 4 > Nested;
7488
7589 DirectiveRegion (CallBase *CBEntry, CallBase *CBExit)
76- : CBEntry(CBEntry), CBExit(CBExit), Parent(this ) {}
90+ : CBEntry(CBEntry), CBExit(CBExit), Parent(nullptr ) {}
91+ };
92+
93+ class DirectiveRegionAnalysis {
94+ public:
95+ explicit DirectiveRegionAnalysis (Function &F) : DT(F), PDT(F) {}
96+
97+ bool directiveEncloses (DirectiveRegion *DR, DirectiveRegion *OtherDR) {
98+ // Use DominatorTree for Entry and PostDominatorTree for Exit.
99+ // PostDominator is effective for checking Exit when there are loops in
100+ // the CFG, since dominance does not hold for graphs with cycles, but
101+ // post-dominance does.
102+ if (DT.dominates (DR->getEntry (), OtherDR->getEntry ()) &&
103+ PDT.dominates (DR->getExit (), OtherDR->getExit ()))
104+ return true ;
105+
106+ return false ;
107+ };
108+
109+ bool directiveEntryDominates (DirectiveRegion *DR, DirectiveRegion *OtherDR) {
110+ if (DT.dominates (DR->getEntry (), OtherDR->getEntry ()))
111+ return true ;
112+
113+ return false ;
114+ }
115+
116+ private:
117+ DominatorTree DT;
118+ PostDominatorTree PDT;
77119};
78120
121+ void DirectiveRegion::addNested (DirectiveRegionAnalysis &DRA,
122+ DirectiveRegion *DR) {
123+ // Insert in topological order.
124+ auto Compare = [&DRA](DirectiveRegion *DR, DirectiveRegion *OtherDR) {
125+ return DRA.directiveEntryDominates (DR, OtherDR);
126+ };
127+
128+ Nested.insert (std::upper_bound (Nested.begin (), Nested.end (), DR, Compare),
129+ DR);
130+ }
131+
79132static SmallVector<Value *>
80133collectGlobalizedValues (DirectiveRegion &Directive) {
81134
@@ -149,103 +202,109 @@ struct IntrinsicsOpenMP : public ModulePass {
149202 FunctionToDirectives[F].push_back (DM);
150203 }
151204
152- SmallVector<std::list<DirectiveRegion *>, 4 > DirectiveListVector;
153- // Create directive lists per function, list stores outermost to innermost.
205+ SmallVector<SmallVector<DirectiveRegion *, 4 >, 4 > DirectiveListVector;
206+ // Create directive lists per function, building trees of directive nests.
207+ // Each list stores directives outermost to innermost (pre-order).
154208 for (auto &FTD : FunctionToDirectives) {
155209 // Find the dominator tree for the function to find directive lists.
156- DominatorTree DT ( *FTD.first ) ;
210+ Function &F = *FTD.first ;
157211 auto &DirectiveRegions = FTD.second ;
212+ DirectiveRegionAnalysis DRA{F};
158213
159- // TODO: do we need a "tree" structure or are nesting lists enough?
160- #if 0
161- for(auto *DR: DirectiveRegions) {
162- // Skip directives for which parent is found.
163- if (DR->getParent() != DR)
164- continue;
214+ // Construct directive tree nests. First, find immediate parents, then add
215+ // nested children to parents.
165216
166- for(auto *IDR : DirectiveRegions) {
167- if(IDR == DR)
217+ // Find immediate parents.
218+ for (auto *DR : DirectiveRegions) {
219+ for (auto *OtherDR : DirectiveRegions) {
220+ if (DR == OtherDR)
168221 continue ;
169222
170- // DR dominates IDR.
171- if (DT.dominates(DR->getEntry(), IDR->getEntry()) &&
172- DT.dominates(IDR->getExit(), DR->getExit())) {
173- DR->addNested(IDR);
174- }
175- }
176- }
177- #endif
223+ if (!DRA.directiveEncloses (OtherDR, DR))
224+ continue ;
178225
179- // First pass, sweep directive regions and form lists.
180- for (auto *DR : DirectiveRegions) {
181- bool Inserted = false ;
182- for (auto &DirectiveList : DirectiveListVector) {
183- auto *Outer = DirectiveList.front ();
184-
185- // If DR dominates the Outer directive then put it in front.
186- if (DT.dominates (DR->getEntry (), Outer->getEntry ()) &&
187- DT.dominates (Outer->getExit (), DR->getExit ())) {
188- // XXX: modifies the iterator, should exit loop.
189- DirectiveList.push_front (DR);
190- Inserted = true ;
191- // Possibly merge with other lists now that Outer is updated to DR.
192- for (auto &OtherDirectiveList : DirectiveListVector) {
193- auto *Outer = OtherDirectiveList.front ();
194- if (Outer == DR)
195- continue ;
196-
197- if (DT.dominates (DR->getEntry (), Outer->getEntry ()) &&
198- DT.dominates (Outer->getExit (), DR->getExit ())) {
199- DirectiveList.insert (DirectiveList.end (),
200- OtherDirectiveList.begin (),
201- OtherDirectiveList.end ());
202- OtherDirectiveList.clear ();
203- }
204- }
205- break ;
226+ DirectiveRegion *Parent = DR->getParent ();
227+ if (!Parent) {
228+ DR->setParent (OtherDR);
229+ continue ;
206230 }
207231
208- // If DR is outside the Outer, continue.
209- if (!(DT.dominates (Outer->getEntry (), DR->getEntry ()) &&
210- DT.dominates (DR->getExit (), Outer->getExit ())))
232+ // If OtherDR is nested under Parent and encloses DR, then OtherDR is
233+ // the immediate parent of DR.
234+ if (DRA.directiveEncloses (Parent, OtherDR)) {
235+ DR->setParent (OtherDR);
211236 continue ;
212-
213- // DR is inside the outer region, find where to put it in the
214- // DirectiveList.
215- auto InsertIt = DirectiveList.end ();
216- for (auto It = DirectiveList.begin (), End = DirectiveList.end ();
217- It != End; ++It) {
218- DirectiveRegion *IDR = *It;
219- // Insert it after the dominating directive.
220- if (DT.dominates (IDR->getEntry (), DR->getEntry ()) &&
221- DT.dominates (DR->getExit (), IDR->getExit ()))
222- InsertIt = std::next (It);
223237 }
224238
225- // XXX: Modifies the iterator, should exit loop.
226- DirectiveList.insert (InsertIt, DR);
227- Inserted = true ;
228- break ;
239+ // Else, OtherDR must be enclosing Parent. It is not OtherDR's
240+ // immediate parent, hence no change to OtherDR.
241+ assert (DRA.directiveEncloses (OtherDR, Parent));
242+ }
243+ }
244+ // Gather all root directives, add nested children.
245+ SmallVector<DirectiveRegion *, 4 > Roots;
246+ for (auto *DR : DirectiveRegions) {
247+ DirectiveRegion *Parent = DR->getParent ();
248+ if (!Parent) {
249+ Roots.push_back (DR);
250+ continue ;
229251 }
230252
231- if (!Inserted)
232- DirectiveListVector.push_back (std::list<DirectiveRegion *>{DR});
253+ Parent->addNested (DRA, DR);
233254 }
234255
235- // Delete empty lists.
236- DirectiveListVector.erase (
237- std::remove_if (
238- DirectiveListVector.begin (), DirectiveListVector.end (),
239- [](std::list<DirectiveRegion *> &DL) { return DL.empty (); }),
240- DirectiveListVector.end ());
256+ // Travese the tree and add directives (outermost to innermost)
257+ // in a list.
258+ for (auto *Root : Roots) {
259+ SmallVector<DirectiveRegion *, 4 > DirectiveList;
260+
261+ auto VisitNode = [&DirectiveList](DirectiveRegion *Node, int Depth,
262+ auto &&VisitNode) -> void {
263+ DirectiveList.push_back (Node);
264+ for (auto *Nested : Node->getNested ())
265+ VisitNode (Nested, Depth + 1 , VisitNode);
266+ };
267+
268+ VisitNode (Root, 0 , VisitNode);
269+
270+ DirectiveListVector.push_back (DirectiveList);
271+
272+ auto PrintTree = [&]() {
273+ dbgs () << " === TREE\n " ;
274+ auto PrintNode = [](DirectiveRegion *Node, int Depth,
275+ auto &&PrintNode) -> void {
276+ if (Depth) {
277+ for (int I = 0 ; I < Depth; ++I)
278+ dbgs () << " " ;
279+ dbgs () << " |_ " ;
280+ }
281+ dbgs () << Node->getTag () << " \n " ;
282+
283+ for (auto *Nested : Node->getNested ())
284+ PrintNode (Nested, Depth + 1 , PrintNode);
285+ };
286+ PrintNode (Root, 0 , PrintNode);
287+ dbgs () << " === END OF TREE\n " ;
288+ };
289+ LLVM_DEBUG (PrintTree ());
290+
291+ auto PrintList = [&]() {
292+ dbgs () << " === List\n " ;
293+ for (auto *DR : DirectiveList)
294+ dbgs () << DR->getTag () << " -> " ;
295+ dbgs () << " EOL\n " ;
296+ dbgs () << " === End of List\n " ;
297+ };
298+ LLVM_DEBUG (PrintList ());
299+ }
241300 }
242301
243302 // Iterate all directive lists and codegen.
244303 for (auto &DirectiveList : DirectiveListVector) {
245304 // If the outermost directive is a TARGET directive, collect globalized
246305 // values to set for codegen.
247306 // TODO: implement Directives as a class, parse each directive before
248- // codegen.
307+ // codegen, optimize privatization .
249308 auto *Outer = DirectiveList.front ();
250309 if (Outer->getEntry ()->getOperandBundleAt (0 ).getTagName ().contains (
251310 " TARGET" )) {
@@ -257,7 +316,7 @@ struct IntrinsicsOpenMP : public ModulePass {
257316 for (auto It = DirectiveList.rbegin (), E = DirectiveList.rend (); It != E;
258317 ++It) {
259318 DirectiveRegion *DR = *It;
260- LLVM_DEBUG (dbgs () << " Found Directive" << *DR->getEntry () << " \n " );
319+ LLVM_DEBUG (dbgs () << " Found Directive " << *DR->getEntry () << " \n " );
261320 // Extract the directive kind and data sharing attributes of values
262321 // from the operand bundles of the intrinsic call.
263322 Directive Dir = OMPD_unknown;
0 commit comments