This is an archive of the discontinued LLVM Phabricator instance.

[flang][OpenMP] Lowering support for atomic update construct
ClosedPublic

Authored by NimishMishra on May 16 2022, 1:03 AM.

Details

Summary

This patch adds lowering support for atomic update construct. A region is associated with every omp.atomic.update operation wherein resides: (1) the evaluation of the expression on the RHS of the atomic assignment statement, and (2) a omp.yield operation that yields the extended value of expression evaluated in (1).

Diff Detail

Event Timeline

NimishMishra created this revision.May 16 2022, 1:03 AM
NimishMishra requested review of this revision.May 16 2022, 1:03 AM

Please check D125793. This patch should fail for pointers. If this fails, please implement atomic update depending on D125793.

shraiysh requested changes to this revision.May 23 2022, 3:39 AM

nit: name the test file to atomic-update.f90 in accordance with the recent changes by Peixin.

Minor changes requested. Thanks!

flang/lib/Lower/OpenMP.cpp
1250–1251

nit: move declarations closer to their use.

flang/test/Lower/OpenMP/atomic03.f90
48 ↗(On Diff #429682)

Can we please add more testcases. There are a many possibilities with memory order and hint and it would be nice to test most of them (ideally all of them). Having more testcases that test different scenarios can't hurt us. [Suggestion] Maybe we can separate them into different subroutines (based on memory order) for clarity. Feel free to separate them however you'd like to ensure readability.

This revision now requires changes to proceed.May 23 2022, 3:39 AM
peixin added inline comments.May 23 2022, 3:59 AM
flang/test/Lower/OpenMP/atomic03.f90
48 ↗(On Diff #429682)

Please add one more test case for pointer similar to D125793.

peixin requested changes to this revision.May 24 2022, 5:09 AM
peixin added inline comments.
flang/lib/Lower/OpenMP.cpp
1264

This should be incorrect for pointers. You may use the following code:

mlir::Value address = fir::getBase(converter.genExprAddr(
      *Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx));
NimishMishra marked 2 inline comments as done.

Addressed comments

Please add a description to the summary of the patch to describe what is being implemented in the patch along with a brief description of how it is implemented.

flang/lib/Lower/OpenMP.cpp
321

Nit: please document this option.

337

Would it be better to pass the mlir::Value result as an argument instead of Expr and also reuse it below at the terminator insertion?

374

Nit: expand auto

1282

Nit: Can this function share a lot of code with the genOmpAtomicUpdate? The hint clause setting, getting the designator, creating the update op etc seem to be similar?

1315

Can you add a comment here on why the omp::AtomicUpdateOp is created here? Something like the following.

"If atomic-clause is not present on the construct, the behavior is as if the update clause is specified."

flang/test/Lower/OpenMP/atomic-update.f90
2

Nit: please test with the flang driver as well.

2

Nit: atomic and atomic update constructs.

4

Nit: can this be on the same line as the one above?

47–50

If the options in {{.*}} are significant then capture in a variable and use it in the operation where it is used. If it is not significant then please remove.

This comment applies to all the tests.

NimishMishra added a child revision: Restricted Differential Revision.Jun 7 2022, 8:48 AM
NimishMishra added inline comments.Jun 9 2022, 10:52 PM
flang/lib/Lower/OpenMP.cpp
337

This is causing a change.

If earlier the IR was

omp.atomic.update %[[VAR_Y]] : !fir.ref<i32> {
   ^bb0(%[[ARG:.*]]: i32):
    fir.store %[[ARG]] to %[[TEMP_9]] : !fir.ref<i32>
    %4 = fir.load %[[TEMP_9]] : !fir.ref<i32>
    %5 = arith.constant 1 : i32
    %[[RESULT:.*]] = arith.addi %4, %5 : i32
     omp.yield(%[[RESULT]] : i32)
}

Now it becomes:

%4 = fir.load %[[TEMP_9]] : !fir.ref<i32>
%5 = arith.constant 1 : i32
%[[RESULT:.*]] = arith.addi %4, %5 : i32
omp.atomic.update %[[VAR_Y]] : !fir.ref<i32> {
   ^bb0(%[[ARG:.*]]: i32):
    fir.store %[[ARG]] to %[[TEMP_9]] : !fir.ref<i32>
     omp.yield(%[[RESULT]] : i32)
}

This does seem OK to me. But still if you could confirm it once.

shraiysh added inline comments.Jun 13 2022, 7:39 AM
flang/lib/Lower/OpenMP.cpp
337

This is not accurate IR.

The "before" IR was correct (not optimal but correct). The value would get updated with that IR.

The "after" IR is both incorrect and not optimal. It is loading an un-related value before the atomic update begins and so the result will not accurately "update" the value.

The standard mentions that the evaluation of expr in x += expr is atomic. In this case, expr is %5, not %4 or %[[RESULT]]. Hence the evaluation of %5 can be outside the construct, but not of %[[RESULT]].

Solution: The best way to do this would be to avoid generation of load-store operations and directly use the argument. This load-store is required for worksharing loops but it would be great if we could avoid generating them for update. The arith.addi operation must be inside the update region. If it seems very hard to avoid load-store then the "before" IR is at least correct.

shraiysh added inline comments.Jun 21 2022, 3:07 AM
flang/lib/Lower/OpenMP.cpp
337

The standard mentions that the evaluation of expr in x += expr is atomic. In this case, expr is %5, not %4 or %[[RESULT]]. Hence the evaluation of %5 can be outside the construct, but not of %[[RESULT]].

Correction (apologies for mistyping some stuff) - The standard mentions that only the evaluation of expr in x += expr need not be atomic, but the update to x must be atomic. In this case, expr is %5, not %4 or %[[RESULT]]. Hence the evaluation of %5 can be outside the construct, but both %4 and %[[RESULT]] must be inside the atomic region.

This still does not change the solution and the fact that the "after" IR is incorrect.

NimishMishra marked 10 inline comments as done.

Rebased and addressed comments

NimishMishra edited the summary of this revision. (Show Details)Jun 24 2022, 12:16 AM
peixin added inline comments.Jun 25 2022, 2:22 AM
flang/lib/Lower/OpenMP.cpp
314

I am thinking if this should be split into one new single function instead of handling the special case in current createBodyOfOp, which is complex enough. The atomic update only uses part of code in createBodyOfOp, and it has nothing to do with the outerCombined and privitization.

Actually, atomic update is one kind of special case, which defines the specific region statements in parsing. It is not the general body in the atomic region. So, would it be better to create one single function to support this?

  • created a new function for atomic update lowering
  • modified the generated IR to use %arg0 in the region instead of separately loading the region argument
NimishMishra added inline comments.Jun 30 2022, 5:16 AM
flang/test/Lower/OpenMP/atomic-update.f90
96

Missed this. Will fix in next diff upload

114

Missed this too. Will fix in next diff upload

peixin added inline comments.Jul 1 2022, 10:27 PM
flang/lib/Lower/OpenMP.cpp
321
// bind the argument to the symbol

This is not necessary. The code can comment itself.

329

Why do you generate the result twice?

1134
address = fir::getBase(converter.genExprAddr(
    *Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx));

Move this out of if condition.

1150

createBodyOfAtomicUpdateOp is only used here, and it's not one large function, so it is OK to inline it directly.

Addressed comments.

The generated code in testcases looks good. Please wait for @peixin's approval for the code part, but functionality-wise this LGTM.

peixin added a comment.Jul 5 2022, 2:40 AM

Thanks for the update. The structure of lowering atomic update operation is much more clear now. I have a few more comments.

flang/lib/Lower/OpenMP.cpp
303

Remove the inline.

324
1130

The vector of symbols seems to be not necessary. Use one symbol is enough since update operation always has one argument.

Use one more description name -> updateSymbol, or better one.

1150

No need to pass currentLocation. It can be obtained from converter.

1151

symbolVector is from assignmentStmtVariable. You can move the code of getting the updateSymbol inside the callee.

peixin added inline comments.Jul 5 2022, 3:57 AM
flang/lib/Lower/OpenMP.cpp
303

I didn't mean add the inline attribute. What I mean is that remove this function and move the code into genOmpAtomicUpdateStatement.

Addressed comments

peixin accepted this revision.Jul 14 2022, 5:30 AM

LGTM except for a few nits.

flang/lib/Lower/OpenMP.cpp
1150

Nit: Add one empty line after 1149.

1151

Ni: Remove the empty line.

1153

Nit

1154

Ni: Remove the empty line.

1160

tiv means type of induction variable. It's not appropriate for update variable.

1161

Then you can remove the following:

tiv.push_back(varType);
locs.push_back(currentLocation);
This revision was not accepted when it landed; it landed in state Needs Review.Jul 14 2022, 5:52 AM
This revision was automatically updated to reflect the committed changes.
kazu added a subscriber: kazu.Jul 15 2022, 10:26 AM

I am getting:

/.../llvm-project/flang/lib/Lower/OpenMP.cpp:1134:21: error: variable 'updateSymbol' is used uninitialized whenever 'if' condition is false [-Werror,-Wsometimes-uninitialized]

If I understand the code correctly, updateSymbol is sometimes initialized. Then, we always dereference the pointer later in the function:

converter.bindSymbol(*updateSymbol, val);

I could silence the warning with:

const Fortran::semantics::Symbol *updateSymbol = nullptr;

but that wouldn't fix the fundamental problem. Would you mind taking a look? Thanks!

I am getting:

/.../llvm-project/flang/lib/Lower/OpenMP.cpp:1134:21: error: variable 'updateSymbol' is used uninitialized whenever 'if' condition is false [-Werror,-Wsometimes-uninitialized]

If I understand the code correctly, updateSymbol is sometimes initialized. Then, we always dereference the pointer later in the function:

converter.bindSymbol(*updateSymbol, val);

I could silence the warning with:

const Fortran::semantics::Symbol *updateSymbol = nullptr;

but that wouldn't fix the fundamental problem. Would you mind taking a look? Thanks!

Thanks @kazu for reaching out. I have put a potential fix at https://reviews.llvm.org/D129914.

@peixin @kiranchandramohan Could you take a quick look at the fix? The issue is failing some builds with [-Werror,-Wsometimes-uninitialized]