This is an archive of the discontinued LLVM Phabricator instance.

[WIP][Clang][OpenMP] Add the support for compare clause in atomic directive
AbandonedPublic

Authored by tianshilei1992 on May 13 2021, 3:48 PM.

Details

Reviewers
jdoerfert
ABataev
Summary
NOTE: Major functionalities have been implemented, but still requires some minor tweak.
NOTE: compare capture combination will be in another patch.

Diff Detail

Event Timeline

tianshilei1992 created this revision.May 13 2021, 3:48 PM
tianshilei1992 requested review of this revision.May 13 2021, 3:48 PM
Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptMay 13 2021, 3:48 PM
tianshilei1992 edited the summary of this revision. (Show Details)May 13 2021, 3:49 PM
tianshilei1992 edited the summary of this revision. (Show Details)

Is this still WIP or should it be reviewed? Needs a proper commit message.

clang/lib/CodeGen/CGStmtOpenMP.cpp
5797–5800

This looks like something is missing.

Is this still WIP or should it be reviewed? Needs a proper commit message.

Not yet.

ABataev added inline comments.Aug 24 2021, 10:15 AM
clang/include/clang/AST/StmtOpenMP.h
2797–2824

It is worth it to pre-commit these and related changes in a separate NFC patch

2848–2851

Can we pack it into a struct? At least X, V etc. params?

clang/lib/CodeGen/CGStmtOpenMP.cpp
5775–5802

I would think about moving most of the atomic codegen functionality to common runtime/OMPBuilder part to be able to override implementation for different targets. It may help to avoid codegen problems with Nvidia/AMD GPUs. Not directly related to this patch though.

tianshilei1992 marked an inline comment as done.Aug 24 2021, 10:26 AM
tianshilei1992 added inline comments.
clang/lib/CodeGen/CGStmtOpenMP.cpp
5775–5802

yeah, actually IIRC the OMPIRBuilder already supports atomic operations. Not sure if it supports the compare clause but I'll take a look. If not, I also think it's a better place to sit them.

tianshilei1992 planned changes to this revision.Aug 24 2021, 7:59 PM
tianshilei1992 marked an inline comment as done.

I'm going to move code gen into OMPIRBuilder.

Thanks for uploading this.

I tried it locally and it is missing proper parsing +sema of the cond-expr-stmt and cond-update-stmt as indicate in the openmp 5.1 spec's. I am sure you are aware of this and this is still WIP.
Do you plan to add support for that? The regression test is not exposing conditional statements, but update ones, so it is not really testing what it should.

You might also want to split parse+sema support from codegen, if it helps.

Many thanks again!

Yes, there are a couple of issues of implicit cast to be fixed. Current test is just a placeholder. I copied and pasted from the one for update clause and just replaced all updates with compare. I’m also working on that.

  1. Ignore implicit cast in some cases.
  2. Add the test case.

What are still missing:

  1. Code generation for floating point types.

Question:

  1. What atomic instruction(s) should we use for floating point types? Current I can see we do support floating point types for update clause, but the emitted code doesn't look like atomic operations.
  2. When do we have to use IgnoreParenImpCasts?

Another thing is how we deal with a corner case. Say the OpenMP code is written in the following way:

#pragma omp atomic compare
  x = e < x ? e : x;

That's how OpenMP spec defines the atomic operation. x is always in "else statement" of a conditional statement.

Now we need to lower it to LLVM IR, which is atomicrmw operation. Based on the LLVM IR reference, it only supports the atomic operations that x is in the "then statement". For example: x = x > e ? x : e. See the x here is before :. In order to lower the OpenMP statement, we have to do a transformation. In order to swap e and x, we need to transform it to x = e >= x : x : e, a.k.a. x = x <= e : x : e. However, we don't have an atomic operation for <=. We only have <. So if x != e, the result is good.

The incorrectness happens if x == e. Recall at the OpenMP statement, when x == e, the result should be x = x. But if we look at our lowered LLVM IR, x = x < e : x : e, when x == e, it becomes x = e, which doesn't conform with OpenMP spec.

What should we do here?

Another thing is how we deal with a corner case. Say the OpenMP code is written in the following way:

#pragma omp atomic compare
  x = e < x ? e : x;

That's how OpenMP spec defines the atomic operation. x is always in "else statement" of a conditional statement.

Now we need to lower it to LLVM IR, which is atomicrmw operation. Based on the LLVM IR reference, it only supports the atomic operations that x is in the "then statement". For example: x = x > e ? x : e. See the x here is before :. In order to lower the OpenMP statement, we have to do a transformation. In order to swap e and x, we need to transform it to x = e >= x : x : e, a.k.a. x = x <= e : x : e. However, we don't have an atomic operation for <=. We only have <. So if x != e, the result is good.

The incorrectness happens if x == e. Recall at the OpenMP statement, when x == e, the result should be x = x. But if we look at our lowered LLVM IR, x = x < e : x : e, when x == e, it becomes x = e, which doesn't conform with OpenMP spec.

What should we do here?

There seems to be an imbalance in the OpenMP specs, where I would have written something like the followin (page 268 or 5.1 spec's):

x = expr ordop x ? expr : x;
x = x ordop expr ? x : expr;

I tried thinking about a compact solution to your problem, including trying to take advantage of the fact that when x == e we don't need to actually do the assignment (page 272 line 17 of 5.1 spec's and see below), but I was unsuccessful.
Did you consider special casing this transforming it into the equivalent:
#pragma omp critical
{ if (x > e) x = e; }
?

Remember:

For forms where statement is cond-expr-stmt, if the result of the condition implies that the value of x
does not change then the update may not occur.

The right thing to do would be to fix the spec's, but that can't happen until 5.2.

koops added a subscriber: koops.Oct 7 2021, 8:56 PM

This is already a lot of code with parse+sema. I wonder if we should split the patch into two, i.e. 1. parse+sema; 2. code gen? @ABataev ?
It should simplify maintenance of the patch and allow time to extend the OpenMP IR builder.

This is already a lot of code with parse+sema. I wonder if we should split the patch into two, i.e. 1. parse+sema; 2. code gen? @ABataev ?
It should simplify maintenance of the patch and allow time to extend the OpenMP IR builder.

+1

I'll separate them later.

I created a patch D115561 for parser.

cchen added a subscriber: cchen.Dec 16 2021, 9:20 AM
tianshilei1992 abandoned this revision.Dec 25 2021, 11:02 AM