Skip to content

[OpenMP] Missing implicit otherwise clause in metadirective. #127113

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 28, 2025

Conversation

zahiraam
Copy link
Contributor

@zahiraam zahiraam commented Feb 13, 2025

Compiling this:
int main() {
#pragma omp metadirective when(use r= {condition(0)}
: parallel for)
for (int i=0; i<10; i++)
;
}`

is generating an error:
error: expected expression
The compiler is interpreting this as if it's compiling a #pragma omp metadirective with no otherwise clause.
In the OMP5.2 specs chapter 7.4 it's mentioned that:
If no otherwise clause is specified the effect is as if one was specified without an associated directive variant.
This patch fixes the issue.

@zahiraam zahiraam marked this pull request as ready for review February 14, 2025 12:30
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" flang:openmp clang:openmp OpenMP related changes to Clang labels Feb 14, 2025
@llvmbot
Copy link
Member

llvmbot commented Feb 14, 2025

@llvm/pr-subscribers-flang-openmp

@llvm/pr-subscribers-clang

Author: Zahira Ammarguellat (zahiraam)

Changes

Compiling this:
int main() {
#pragma omp metadirective when(use r= {condition(0)}
: parallel for)
for (int i=0; i&lt;10; i++)
;
}`

is generating an error:
error: expected expression
The compiler is interpreting this as if it's compiling a #pragma omp metadirective with no otherwise clause.
In the OMP5.2 specs chapter 7.4 it's mentioned that:
If no otherwise clause is specified the effect is as if one was specified without an associated directive variant.
This patch fixes the issue.


Full diff: https://github.com/llvm/llvm-project/pull/127113.diff

4 Files Affected:

  • (modified) clang/lib/Parse/ParseOpenMP.cpp (+6)
  • (modified) clang/test/OpenMP/metadirective_ast_print.c (+18)
  • (added) clang/test/OpenMP/metadirective_otherwise.cpp (+72)
  • (modified) llvm/include/llvm/Frontend/OpenMP/OMPContext.h (+1-1)
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index a455659ca8f2c..0f68d4002ad8e 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -2882,6 +2882,12 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
           /*ReadDirectiveWithinMetadirective=*/true);
       break;
     }
+    // If no match is found and no otherwise clause is present, skip
+    // OMP5.2 Chapter 7.4: If no otherwise clause is specified the effect is as
+    // if one was specified without an associated directive variant.
+    if (BestIdx == -1 && Idx == 1) {
+      SkipUntil(tok::annot_pragma_openmp_end);
+    }
     break;
   }
   case OMPD_threadprivate: {
diff --git a/clang/test/OpenMP/metadirective_ast_print.c b/clang/test/OpenMP/metadirective_ast_print.c
index d9ff7e7645216..06991c6f06a02 100644
--- a/clang/test/OpenMP/metadirective_ast_print.c
+++ b/clang/test/OpenMP/metadirective_ast_print.c
@@ -77,6 +77,24 @@ void foo(void) {
                                : parallel) default(nothing)
   for (int i = 0; i < 16; i++)
     ;
+
+#pragma omp metadirective when(user = {condition(0)}	\
+			       : parallel for) otherwise()
+  for (int i=0; i<10; i++)
+    ;
+#pragma omp metadirective when(user = {condition(0)}	\
+			       : parallel for)
+  for (int i=0; i<10; i++)
+    ;
+
+#pragma omp metadirective when(user = {condition(1)}	\
+			       : parallel for) otherwise()
+  for (int i=0; i<10; i++)
+    ;
+#pragma omp metadirective when(user = {condition(1)}	\
+			       : parallel for)
+  for (int i=0; i<10; i++)
+    ;
 }
 
 // CHECK: void bar(void);
diff --git a/clang/test/OpenMP/metadirective_otherwise.cpp b/clang/test/OpenMP/metadirective_otherwise.cpp
new file mode 100644
index 0000000000000..50c9fe8a2b0e7
--- /dev/null
+++ b/clang/test/OpenMP/metadirective_otherwise.cpp
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-linux -emit-llvm %s -o - | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+void func1() {
+#pragma omp metadirective when(user = {condition(0)}	\
+			       : parallel for) otherwise()
+  for (int i = 0; i < 100; i++)
+    ;
+
+#pragma omp metadirective when(user = {condition(0)}	\
+			       : parallel for)
+  for (int i = 0; i < 100; i++)
+    ;
+}
+
+// CHECK-LABEL: define dso_local void @_Z5func1v()
+// CHECK:       entry
+// CHECK-NEXT:    [[I:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[I1:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store i32 0, ptr [[I]], align 4
+// CHECK-NEXT:    br label %[[FOR_COND:.*]]
+// CHECK:       [[FOR_COND]]:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[I]], align 4
+// CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[TMP0]], 100
+// CHECK-NEXT:    br i1 [[CMP]], label %[[FOR_BODY:.*]], label %[[FOR_END:.*]]
+// CHECK:       [[FOR_BODY]]:
+// CHECK-NEXT:    br label %[[FOR_INC:.*]]
+// CHECK:       [[FOR_INC]]:
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[I]], align 4
+// CHECK-NEXT:    [[INC:%.*]] = add nsw i32 [[TMP1]], 1
+// CHECK-NEXT:    store i32 [[INC]], ptr [[I]], align 4
+// CHECK-NEXT:    br label %[[FOR_COND]], !llvm.loop [[LOOP3:![0-9]+]]
+// CHECK:       [[FOR_END]]:
+// CHECK-NEXT:    store i32 0, ptr [[I1]], align 4
+// CHECK-NEXT:    br label %[[FOR_COND2:.*]]
+// CHECK:       [[FOR_COND2]]:
+// CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[I1]], align 4
+// CHECK-NEXT:    [[CMP3:%.*]] = icmp slt i32 [[TMP2]], 100
+// CHECK-NEXT:    br i1 [[CMP3]], label %[[FOR_BODY4:.*]], label %[[FOR_END7:.*]]
+// CHECK:       [[FOR_BODY4]]:
+// CHECK-NEXT:    br label %[[FOR_INC5:.*]]
+// CHECK:       [[FOR_INC5]]:
+// CHECK-NEXT:    [[TMP3:%.*]] = load i32, ptr [[I1]], align 4
+// CHECK-NEXT:    [[INC6:%.*]] = add nsw i32 [[TMP3]], 1
+// CHECK-NEXT:    store i32 [[INC6]], ptr [[I1]], align 4
+// CHECK-NEXT:    br label %[[FOR_COND2]], !llvm.loop [[LOOP5:![0-9]+]]
+// CHECK:       [[FOR_END7]]:
+// CHECK-NEXT:    ret void
+
+void func2() {
+#pragma omp metadirective when(user = {condition(1)}	\
+			       : parallel for) otherwise()
+  for (int i = 0; i < 100; i++)
+    ;
+
+#pragma omp metadirective when(user = {condition(1)}	\
+			       : parallel for)
+  for (int i = 0; i < 100; i++)
+    ;
+}
+
+// CHECK-LABEL: define dso_local void @_Z5func2v()
+// CHECK:       entry
+// CHECK-NEXT:    call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB2:[0-9]+]], i32 0, ptr @_Z5func2v.omp_outlined)
+// CHECK-NEXT:    call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB2]], i32 0, ptr @_Z5func2v.omp_outlined.1)
+// CHECK-NEXT:    ret void
+
+
+#endif
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPContext.h b/llvm/include/llvm/Frontend/OpenMP/OMPContext.h
index a501eaf2356ff..26163fdb4b63d 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMPContext.h
+++ b/llvm/include/llvm/Frontend/OpenMP/OMPContext.h
@@ -188,7 +188,7 @@ bool isVariantApplicableInContext(const VariantMatchInfo &VMI,
                                   bool DeviceSetOnly = false);
 
 /// Return the index (into \p VMIs) of the variant with the highest score
-/// from the ones applicble in \p Ctx. See llvm::isVariantApplicableInContext.
+/// from the ones applicable in \p Ctx. See llvm::isVariantApplicableInContext.
 int getBestVariantMatchForContext(const SmallVectorImpl<VariantMatchInfo> &VMIs,
                                   const OMPContext &Ctx);
 

Comment on lines 2888 to 2890
if (BestIdx == -1 && Idx == 1) {
SkipUntil(tok::annot_pragma_openmp_end);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure skipUntil is good here, since you may miss some junk at the end of the directive

Copy link
Contributor Author

@zahiraam zahiraam Feb 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this enough to not miss the potential upcoming tokens?

Copy link

github-actions bot commented Feb 17, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

// OMP5.2 Chapter 7.4: If no otherwise clause is specified the effect is as
// if one was specified without an associated directive variant.
if (BestIdx == -1 && Idx == 1) {
SkipUntil(tok::annot_pragma_openmp_end,tok::identifier);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You still losing some data, SkipUntil does not work here

Comment on lines 2888 to 2891
if (BestIdx == -1 && Idx == 1) {
ConsumeAnnotationToken();
return StmtEmpty();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a test for the situation where you have extra tokens at this point? Or only tok::annot_pragma_openmp_end is expected here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line #89 of OpenMP/metadirective_ast_print.c show this situation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add an assertion here, that the next expected token is tok::annot_pragma_openmp_end?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The next expected token should be kw_for no?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, before ConsumeAnnotationToken();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In all cases I am seeing, at this point Tok=annot_pragma_openmp_end and NextToken = kw_for. Asserting here would not work! But doesn't it make sense to have the kw_for right at the end of the pragma?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, check that Tok=annot_pragma_openmp_end, this is what I meant

@zahiraam
Copy link
Contributor Author

@alexey-bataev Thanks for the reviews.

@zahiraam zahiraam merged commit 26fc3aa into llvm:main Feb 28, 2025
11 checks passed
cheezeburglar pushed a commit to cheezeburglar/llvm-project that referenced this pull request Feb 28, 2025
…7113)

Compiling this:
 `int main() {`
 ` #pragma omp metadirective when(use r= {condition(0)}`
`: parallel for)`
  `for (int i=0; i<10; i++)`
  ;
}`

is generating an error:
`error: expected expression`
The compiler is interpreting this as if it's compiling a `#pragma omp
metadirective` with no `otherwise` clause.
In the OMP5.2 specs chapter 7.4 it's mentioned that: 
`If no otherwise clause is specified the effect is as if one was
specified without an associated directive variant.`
This patch fixes the issue.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:openmp OpenMP related changes to Clang clang Clang issues not falling into any other category flang:openmp
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants