Skip to content

Commit d577518

Browse files
authored
[Frontend][OpenMP] Implement getLeafOrCompositeConstructs (#89104)
This function will break up a construct into constituent leaf and composite constructs, e.g. if OMPD_c_d_e and OMPD_d_e are composite constructs, then OMPD_a_b_c_d_e will be broken up into the list {OMPD_a, OMPD_b, OMPD_c_d_e}.
1 parent b87b6e2 commit d577518

File tree

3 files changed

+128
-13
lines changed

3 files changed

+128
-13
lines changed

llvm/include/llvm/Frontend/OpenMP/OMP.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,15 @@
1616
#include "llvm/Frontend/OpenMP/OMP.h.inc"
1717

1818
#include "llvm/ADT/ArrayRef.h"
19+
#include "llvm/ADT/SmallVector.h"
1920

2021
namespace llvm::omp {
2122
ArrayRef<Directive> getLeafConstructs(Directive D);
23+
ArrayRef<Directive> getLeafConstructsOrSelf(Directive D);
24+
25+
ArrayRef<Directive>
26+
getLeafOrCompositeConstructs(Directive D, SmallVectorImpl<Directive> &Output);
27+
2228
Directive getCompoundConstruct(ArrayRef<Directive> Parts);
2329

2430
bool isLeafConstruct(Directive D);

llvm/lib/Frontend/OpenMP/OMP.cpp

Lines changed: 90 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,54 @@ using namespace llvm::omp;
2525
#define GEN_DIRECTIVES_IMPL
2626
#include "llvm/Frontend/OpenMP/OMP.inc"
2727

28+
static iterator_range<ArrayRef<Directive>::iterator>
29+
getFirstCompositeRange(iterator_range<ArrayRef<Directive>::iterator> Leafs) {
30+
// OpenMP Spec 5.2: [17.3, 8-9]
31+
// If directive-name-A and directive-name-B both correspond to loop-
32+
// associated constructs then directive-name is a composite construct
33+
// otherwise directive-name is a combined construct.
34+
//
35+
// In the list of leaf constructs, find the first loop-associated construct,
36+
// this is the beginning of the returned range. Then, starting from the
37+
// immediately following leaf construct, find the first sequence of adjacent
38+
// loop-associated constructs. The last of those is the last one of the
39+
// range, that is, the end of the range is one past that element.
40+
// If such a sequence of adjacent loop-associated directives does not exist,
41+
// return an empty range.
42+
//
43+
// The end of the returned range (including empty range) is intended to be
44+
// a point from which the search for the next range could resume.
45+
//
46+
// Consequently, this function can't return a range with a single leaf
47+
// construct in it.
48+
49+
auto firstLoopAssociated =
50+
[](iterator_range<ArrayRef<Directive>::iterator> List) {
51+
for (auto It = List.begin(), End = List.end(); It != End; ++It) {
52+
if (getDirectiveAssociation(*It) == Association::Loop)
53+
return It;
54+
}
55+
return List.end();
56+
};
57+
58+
auto Empty = llvm::make_range(Leafs.end(), Leafs.end());
59+
60+
auto Begin = firstLoopAssociated(Leafs);
61+
if (Begin == Leafs.end())
62+
return Empty;
63+
64+
auto End =
65+
firstLoopAssociated(llvm::make_range(std::next(Begin), Leafs.end()));
66+
if (End == Leafs.end())
67+
return Empty;
68+
69+
for (; End != Leafs.end(); ++End) {
70+
if (getDirectiveAssociation(*End) != Association::Loop)
71+
break;
72+
}
73+
return llvm::make_range(Begin, End);
74+
}
75+
2876
namespace llvm::omp {
2977
ArrayRef<Directive> getLeafConstructs(Directive D) {
3078
auto Idx = static_cast<std::size_t>(D);
@@ -34,6 +82,44 @@ ArrayRef<Directive> getLeafConstructs(Directive D) {
3482
return ArrayRef(&Row[2], static_cast<int>(Row[1]));
3583
}
3684

85+
ArrayRef<Directive> getLeafConstructsOrSelf(Directive D) {
86+
if (auto Leafs = getLeafConstructs(D); !Leafs.empty())
87+
return Leafs;
88+
auto Idx = static_cast<size_t>(D);
89+
assert(Idx < Directive_enumSize && "Invalid directive");
90+
const auto *Row = LeafConstructTable[LeafConstructTableOrdering[Idx]];
91+
// The first entry in the row is the directive itself.
92+
return ArrayRef(&Row[0], &Row[0] + 1);
93+
}
94+
95+
ArrayRef<Directive>
96+
getLeafOrCompositeConstructs(Directive D, SmallVectorImpl<Directive> &Output) {
97+
using ArrayTy = ArrayRef<Directive>;
98+
using IteratorTy = ArrayTy::iterator;
99+
ArrayRef<Directive> Leafs = getLeafConstructsOrSelf(D);
100+
101+
IteratorTy Iter = Leafs.begin();
102+
do {
103+
auto Range = getFirstCompositeRange(llvm::make_range(Iter, Leafs.end()));
104+
// All directives before the range are leaf constructs.
105+
for (; Iter != Range.begin(); ++Iter)
106+
Output.push_back(*Iter);
107+
if (!Range.empty()) {
108+
Directive Comp =
109+
getCompoundConstruct(ArrayTy(Range.begin(), Range.end()));
110+
assert(Comp != OMPD_unknown);
111+
Output.push_back(Comp);
112+
Iter = Range.end();
113+
// As of now, a composite construct must contain all constituent leaf
114+
// constructs from some point until the end of all constituent leaf
115+
// constructs.
116+
assert(Iter == Leafs.end() && "Malformed directive");
117+
}
118+
} while (Iter != Leafs.end());
119+
120+
return Output;
121+
}
122+
37123
Directive getCompoundConstruct(ArrayRef<Directive> Parts) {
38124
if (Parts.empty())
39125
return OMPD_unknown;
@@ -88,20 +174,11 @@ Directive getCompoundConstruct(ArrayRef<Directive> Parts) {
88174
bool isLeafConstruct(Directive D) { return getLeafConstructs(D).empty(); }
89175

90176
bool isCompositeConstruct(Directive D) {
91-
// OpenMP Spec 5.2: [17.3, 8-9]
92-
// If directive-name-A and directive-name-B both correspond to loop-
93-
// associated constructs then directive-name is a composite construct
94-
llvm::ArrayRef<Directive> Leafs{getLeafConstructs(D)};
95-
if (Leafs.empty())
96-
return false;
97-
if (getDirectiveAssociation(Leafs.front()) != Association::Loop)
177+
ArrayRef<Directive> Leafs = getLeafConstructsOrSelf(D);
178+
if (Leafs.size() <= 1)
98179
return false;
99-
100-
size_t numLoopConstructs =
101-
llvm::count_if(Leafs.drop_front(), [](Directive L) {
102-
return getDirectiveAssociation(L) == Association::Loop;
103-
});
104-
return numLoopConstructs != 0;
180+
auto Range = getFirstCompositeRange(Leafs);
181+
return Range.begin() == Leafs.begin() && Range.end() == Leafs.end();
105182
}
106183

107184
bool isCombinedConstruct(Directive D) {

llvm/unittests/Frontend/OpenMPCompositionTest.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "llvm/ADT/ArrayRef.h"
10+
#include "llvm/ADT/SmallVector.h"
1011
#include "llvm/Frontend/OpenMP/OMP.h"
1112
#include "gtest/gtest.h"
1213

@@ -40,6 +41,37 @@ TEST(Composition, GetCompoundConstruct) {
4041
ASSERT_EQ(C7, OMPD_do_simd); // Make sure it's not OMPD_end_do_simd
4142
}
4243

44+
TEST(Composition, GetLeafOrCompositeConstructs) {
45+
SmallVector<Directive> Out1;
46+
auto Ret1 = getLeafOrCompositeConstructs(
47+
OMPD_target_teams_distribute_parallel_for, Out1);
48+
ASSERT_EQ(Ret1, ArrayRef<Directive>(Out1));
49+
ASSERT_EQ((ArrayRef<Directive>(Out1)),
50+
(ArrayRef<Directive>{OMPD_target, OMPD_teams,
51+
OMPD_distribute_parallel_for}));
52+
53+
SmallVector<Directive> Out2;
54+
auto Ret2 =
55+
getLeafOrCompositeConstructs(OMPD_parallel_masked_taskloop_simd, Out2);
56+
ASSERT_EQ(Ret2, ArrayRef<Directive>(Out2));
57+
ASSERT_EQ(
58+
(ArrayRef<Directive>(Out2)),
59+
(ArrayRef<Directive>{OMPD_parallel, OMPD_masked, OMPD_taskloop_simd}));
60+
61+
SmallVector<Directive> Out3;
62+
auto Ret3 =
63+
getLeafOrCompositeConstructs(OMPD_distribute_parallel_do_simd, Out3);
64+
ASSERT_EQ(Ret3, ArrayRef<Directive>(Out3));
65+
ASSERT_EQ((ArrayRef<Directive>(Out3)),
66+
(ArrayRef<Directive>{OMPD_distribute_parallel_do_simd}));
67+
68+
SmallVector<Directive> Out4;
69+
auto Ret4 = getLeafOrCompositeConstructs(OMPD_target_parallel_loop, Out4);
70+
ASSERT_EQ(Ret4, ArrayRef<Directive>(Out4));
71+
ASSERT_EQ((ArrayRef<Directive>(Out4)),
72+
(ArrayRef<Directive>{OMPD_target, OMPD_parallel, OMPD_loop}));
73+
}
74+
4375
TEST(Composition, IsLeafConstruct) {
4476
ASSERT_TRUE(isLeafConstruct(OMPD_loop));
4577
ASSERT_TRUE(isLeafConstruct(OMPD_teams));

0 commit comments

Comments
 (0)