This is an archive of the discontinued LLVM Phabricator instance.

[OpenMP] Support construct trait set for Clang
ClosedPublic

Authored by cchen on Sep 10 2021, 3:31 PM.

Details

Summary

This patch supports construct trait set selector by using the existed
declare variant infrastructure inside OMPContext and simd selector is
currently not supported. The goal of this patch is to pass the declare variant
test inside sollve test suite.

Diff Detail

Event Timeline

cchen created this revision.Sep 10 2021, 3:31 PM
cchen requested review of this revision.Sep 10 2021, 3:31 PM
Herald added a project: Restricted Project. · View Herald TranscriptSep 10 2021, 3:31 PM
cchen added inline comments.Sep 10 2021, 3:41 PM
clang/lib/AST/OpenMPClause.cpp
2344–2345

I'm now removing this line since the properties are already added at line 2334 and not removing this line would lead to an extra iteration in OMPContext.cpp (check out the second diff), and the code will always return false even if the construct trait properties are added.

Diff for OpenMPClause.cpp

2333       for (const OMPTraitProperty &Property : Selector.Properties)
2334         VMI.addTrait(Set.Kind, Property.Kind, Property.RawString, ScorePtr);
2335
2336       if (Set.Kind != TraitSet::construct)
2337         continue;
2338
2339       // TODO: This might not hold once we implement SIMD properly.
2340       assert(Selector.Properties.size() == 1 &&
2341              Selector.Properties.front().Kind ==
2342                  getOpenMPContextTraitPropertyForSelector(
2343                      Selector.Kind) &&
2344              "Ill-formed construct selector!");
2345
2346       // VMI.ConstructTraits.push_back(Selector.Properties.front().Kind);

Diff for lib/Frontend/OpenMP/OMPContext.cpp:

224     unsigned ConstructIdx = 0, NoConstructTraits = Ctx.ConstructTraits.size();
225     for (TraitProperty Property : VMI.ConstructTraits) {
226       assert(getOpenMPContextTraitSetForProperty(Property) ==
227                  TraitSet::construct &&
228              "Variant context is ill-formed!");
229
230       // Verify the nesting.
231       bool FoundInOrder = false;
232       while (!FoundInOrder && ConstructIdx != NoConstructTraits)
233         FoundInOrder = (Ctx.ConstructTraits[ConstructIdx++] == Property);
234       if (ConstructMatches)
235         ConstructMatches->push_back(ConstructIdx - 1);
236
237       Optional<bool> Result = HandleTrait(Property, FoundInOrder);
238       if (Result.hasValue())
239         return Result.getValue();
240
241       if (!FoundInOrder) {
242         LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE << "] Construct property "
243                           << getOpenMPContextTraitPropertyName(Property, "")
244                           << " was not nested properly.\n");
245         return false;
246       }
247
248       // TODO: Verify SIMD
249     }
cchen added inline comments.Sep 10 2021, 3:42 PM
clang/test/OpenMP/declare_variant_construct_codegen_1.c
24

Cool!

We certainly need more tests but the design you came up with is certainly nicer than what I had in mind.
One thing I wanted to do though is keep track of the constructs in the OpenMPIRBuilder instead. So move the

/// Vector of declare variant construct traits.
SmallVector<llvm::omp::TraitProperty, 8> ConstructTraits;

into OpenMPIRBuilder and add/delete the things there. It's not a conceptual difference but makes it easier
to opt-in for Flang later.

I also left some comments below. I don't think there is anything major though.

clang/lib/AST/OpenMPClause.cpp
2344–2345

I'm not surprised some things need adjustment. Never tested construct trait matching much as we did not expose it via clang. Just delete the line if you think it's wrong. Also consider deleting the code before if it's not needed.

clang/lib/Sema/SemaOpenMP.cpp
737

Modification was made to make it clear what happens but now I think this is not needed.

See below first. Maybe the interface should be "handleConstructTrait(Property, bool Insert)" and if Insert is false you verify it's the last one and delete it. You'd need to traverse them in opposite order though to verify, unsure if verification is therefore strictly necessary.

3900–3902
4497

I know think you need to call something like addDeclareVariantConstructTrait again and do pop_back() instead of push_back() for each trait matching the DKind. Clearing, or erasing a fixed amount of traits, does not work.

6845

Maybe we should pass the traits to the constructor, makes it clearer they have to be passed.

One thing I wanted to do though is keep track of the constructs in the OpenMPIRBuilder instead. So move the

/// Vector of declare variant construct traits.
SmallVector<llvm::omp::TraitProperty, 8> ConstructTraits;

into OpenMPIRBuilder and add/delete the things there. It's not a conceptual difference but makes it easier
to opt-in for Flang later.

We don't have any OpenMPIRBuilder instance inside SemaOpenMP yet and the OpenMPIRBuilder constructor requires a Module parameter so I'm not sure how to achieve this, can you give me some suggestions?

clang/lib/Sema/SemaOpenMP.cpp
737

For the delete part, I'm not sure how passing Property would work since I'm not deleting all the construct trait properties inside ActOnOpenMPRegionEnd function.

cchen added inline comments.Sep 13 2021, 1:55 PM
clang/lib/Sema/SemaOpenMP.cpp
737

I think I've figured out a way to achieve what you suggest.

4497

So you are saying that instead of removing all the construct property inside ActOnOpenMPRegionEnd, we should delete those construct properties more fine-grained? I'd like to do so and has tried putting the insert/delete logic inside more specific function such as ActOnOpenMPParllell,

cchen updated this revision to Diff 372347.EditedSep 13 2021, 2:37 PM

Rebase and fix based on suggestions

Haven't moved ConstructTrait to IRBuilder

jdoerfert added inline comments.Sep 13 2021, 4:06 PM
clang/lib/AST/OpenMPClause.cpp
2487

Nit: no braces.

clang/lib/Parse/ParseOpenMP.cpp
2052

{} might do it but this is fine too.

clang/lib/Sema/SemaOpenMP.cpp
746

So, SmalVector has a pop_back_val which we could use to verify the properties are the ones we expect. However, we would need to first put them into a vector and if insert is false we would need to reverse the vector.
Maybe that's the way to go:

  1. Where you call handleConstructTrait right now, just put the traits in a vector.
  2. Make it handleConstructTraits and take a vector of construct traits.
  3. For insert == true, just append them all.
  4. For insert == falser reverse the vector and do pop_back_val with an assertion that they match the result of vector.pop_back_val();

Does that make sense?

(Apologies for making you rewrite this twice.)

cchen updated this revision to Diff 372529.Sep 14 2021, 12:13 PM

Fix based on feedback (wait for comment about moving ConstructTrait to IRBuilder)

cchen updated this revision to Diff 372531.Sep 14 2021, 12:15 PM

Remove braces

jdoerfert added inline comments.Sep 14 2021, 12:29 PM
clang/lib/Sema/SemaOpenMP.cpp
746

This is not what I meant and I doubt this works. Let me try to explain with an example:

handleDeclareVariantConstructTrait for a DSKind parallel_for will first add a parallel then a for construct trait.
When we leave the parallel for we should pop them of our construct trait stack again, and preferably verify we do see the ones we expect.
So let's assume the stack was like this before

[ teams ]
// enter parallel for code generation
[ teams, parallel, for]
...
// exit parallel for code generation

at this point we want to pop for and then parallel from the end.

If the last one on the stack was not for or the second to last was not parallel something went wrong.
Since handleDeclareVariantConstructTrait does give use the traits "in order", thus [parallel, for], we need to do something different to verify this is the suffix of the stack.

I proposed to accumulate all traits in handleDeclareVariantConstructTrait rather than passing them to handleConstructTrait one by one.
So there would be a single call to handleConstructTrait at the end with all the traits, here [parallel, for].
If we are entering the scope we just append them to the stack: [teams] + [parallel, for] = [teams, parallel, for]
If we are exiting the scope (Insert == false, or name it ScopeEntry instead), we reverse the trait set and compare it against what we push from the stack:

stack = [teams, parallel, for] 
trait_set = [parallel, for] (passed to `handleConstructTrait` by `handleDeclareVariantConstructTrait) 
verification:
  for (trait in reverse(trait_set)) {
    stack_last = stack.pop_back_val();
    assert(trait == stack_last && "Something left a trait on the stack!");
  }

Does this make sense?

cchen updated this revision to Diff 372584.Sep 14 2021, 4:13 PM

Fix based on suggestions

cchen added inline comments.Sep 14 2021, 4:15 PM
clang/lib/Sema/SemaOpenMP.cpp
746

Thanks for your further explanation and patience, it really helps a lot for me to understand!

Great! This should work. Though we need actual tests ;)

I also provided you with two minor edits below to make it easier to read, no functional change though.

clang/lib/Sema/SemaOpenMP.cpp
737–738
740
cchen updated this revision to Diff 372843.Sep 15 2021, 5:06 PM

Add tests and fix coding style

cchen retitled this revision from [WIP][OpenMP] Support construct trait set for Clang to [OpenMP] Support construct trait set for Clang.Sep 15 2021, 5:07 PM
cchen edited the summary of this revision. (Show Details)
jdoerfert accepted this revision.Sep 15 2021, 8:33 PM

LGTM, thanks :)

This revision is now accepted and ready to land.Sep 15 2021, 8:33 PM
This revision was landed with ongoing or failed builds.Sep 16 2021, 9:34 AM
This revision was automatically updated to reflect the committed changes.
MaskRay added inline comments.
clang/lib/Sema/SemaOpenMP.cpp
741

I fixed -Wunused-variable in c5f480fcbec04f46a9cfcad08914665ff83d8d8a