This is an archive of the discontinued LLVM Phabricator instance.

[OpenMP][WIP] atomic update only evaluate once for expression having side effect
AbandonedPublic

Authored by cchen on Dec 9 2019, 1:34 PM.

Details

Reviewers
ABataev
jdoerfert
Summary

This patch is for pointing out that we might need to check if the
expression in atomic update having any side effect. In the past we
always only evaluate an expression once, for example:

int cnt = 0;
int foo() {
  return ++cnt;
}

void bar() {
  int iarr[100];
#pragma omp atomic capture
  iarr[foo(), foo(), 0]  = iarr[foo(), foo(), 0] + 1;
}

For now, the result of cnt is 2, however, we probably want cnt to be 4
or we might want to tell user that we only evaluate the expression once
as diagnosis message.

Actually, atomic capture have the exact same issue, but the purpose of
this patch to expose the issue. After the discussion, I might send another
patch to fix the issue.

Event Timeline

cchen created this revision.Dec 9 2019, 1:34 PM
Herald added a project: Restricted Project. · View Herald Transcript
cchen edited the summary of this revision. (Show Details)Dec 9 2019, 1:35 PM
cchen added a project: Restricted Project.
cchen added subscribers: dreachem, sandoval.

It is against the standard, I assume. According to standard, During the execution of an atomic region, multiple syntactic occurrences of x must designate the same storage location.. In your case, this is not so. I assume it would be better to implement the diagnostic here that the code is not OpenMP compliant.

• For forms that allow multiple occurrences of x, the number of times that x is evaluated is unspecified.

x here is iarr[foo(), foo(), 0], if I'm not mistaken. Assuming not, any multiple of 2 is a fine amount of evaluations for foo.

I'd vote for a warning here.

cchen edited the summary of this revision. (Show Details)Dec 9 2019, 2:18 PM
cchen added a comment.Dec 9 2019, 2:20 PM
This comment was removed by cchen.
cchen added a comment.Dec 9 2019, 2:25 PM

Oops, accidentally remove my own comment. I'm not sure why iarr[foo(), foo(), 0] violate the rule since it will be evaluated as iarr[0], and the counter foo() modified is also in the same location for both left hand side and right hand side.

Oops, accidentally remove my own comment. I'm not sure why iarr[foo(), foo(), 0] violate the rule since it will be evaluated as iarr[0], and the counter foo() modified is also in the same location for both left hand side and right hand side.

It's not a violation but it taps into the unspecified behavior, which in combination with side effects seems to be worth a warning.

So my reasoning is:

x := iarr[foo(), foo(), 0]

which is fine on its own. Using it in the atomic update of the form,

x = x + 1

also fine.

However, the standard says the number of times x is evaluated is unspecified.
Thus, transforming the above to

x += 1

should be valid. So should be,

t = &x; *t = *t + 1

and even

x = (x, x, x, x+1)

cchen added a comment.Dec 9 2019, 2:42 PM

@jdoerfert , thanks for your explanation, it's really clear and helpful. I'll add a warning message in another patch.

cchen abandoned this revision.Dec 9 2019, 2:44 PM

Oops, accidentally remove my own comment. I'm not sure why iarr[foo(), foo(), 0] violate the rule since it will be evaluated as iarr[0], and the counter foo() modified is also in the same location for both left hand side and right hand side.

It's not a violation but it taps into the unspecified behavior, which in combination with side effects seems to be worth a warning.

So my reasoning is:

x := iarr[foo(), foo(), 0]

which is fine on its own. Using it in the atomic update of the form,

x = x + 1

also fine.

However, the standard says the number of times x is evaluated is unspecified.
Thus, transforming the above to

x += 1

should be valid. So should be,

t = &x; *t = *t + 1

and even

x = (x, x, x, x+1)

Agree, missed that he used commas instead of array expressions.