[clang] Implementing part of the lowering for the 'default' clause for the 'parallel' directive (PR #235537)
Pedro da Rosa Pinheiro via cfe-commits
cfe-commits at lists.llvm.org
Sun Oct 25 16:54:06 PDT 2026
https://github.com/pedropiin created https://github.com/llvm/llvm-project/pull/235537
## What
Both `none` and `shared` `default` clause kinds need no additional code generation. Yet they are blocked by NYI. This PR implements a more flexible barrier, allowing the use of the `default` clause with two of its kinds.
Additionally reordering the functions definitions in `CIRGenOpenMPClause.cpp` so that all methods are in alphabetic order.
I'm going to address the `private` and `firstprivate` clause kinds on a next PR, tackling part of the privatization logic.
Basing myself on the logic of my other related PRs #204999 and #202466 .
## Evidence
`python3 build/bin/llvm-lit -sv clang/test/CIR/CodeGenOpenMP/parallel.c`
```llvm-lit: /home/pedro/dev/projects/llvm-project-fork/llvm/utils/lit/lit/llvm/config.py:572: note: using clang: /home/pedro/dev/projects/llvm-project-fork/build/bin/clang
Testing Time: 0.04s
Total Discovered Tests: 1
Passed: 1 (100.00%)
```
`python3 build/bin/llvm-lit -sv clang/test/CIR/CodeGenOpenMP/not-yet-implemented.c`
```
llvm-lit: /home/pedro/dev/projects/llvm-project-fork/llvm/utils/lit/lit/llvm/config.py:572: note: using clang: /home/pedro/dev/projects/llvm-project-fork/build/bin/clang
Testing Time: 0.04s
Total Discovered Tests: 1
Passed: 1 (100.00%)
```
>From d13a4d9443833980b3d029260954c0c8cc8766e7 Mon Sep 17 00:00:00 2001
From: pedropiin <pedarosa04 at gmail.com>
Date: Sun, 25 Oct 2026 20:40:57 -0300
Subject: [PATCH] Implementing part of the lowering for the 'default' clause
for the 'parallel' directive
---
clang/lib/CIR/CodeGen/CIRGenOpenMPClause.cpp | 84 ++++++++++++-------
clang/lib/CIR/CodeGen/CIRGenOpenMPClause.h | 2 +
clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp | 8 +-
.../CIR/CodeGenOpenMP/not-yet-implemented.c | 8 ++
clang/test/CIR/CodeGenOpenMP/parallel.c | 79 +++++++++++++++++
5 files changed, 147 insertions(+), 34 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenMPClause.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenMPClause.cpp
index 2e64632f037c53..94eea7d007217f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenMPClause.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenMPClause.cpp
@@ -74,40 +74,26 @@ static mlir::Value emitMapInfoForVar(CIRGenFunction &cgf,
/*partial_map=*/builder.getBoolAttr(false));
}
-bool OpenMPClauseEmitter::emitProcBind(
- mlir::omp::ProcBindClauseOps &result) const {
- for (const OMPClause *clause : clauses) {
- const auto *pbc = dyn_cast<OMPProcBindClause>(clause);
- if (!pbc)
- continue;
-
- llvm::omp::ProcBindKind kind = pbc->getProcBindKind();
- assert(kind != llvm::omp::ProcBindKind::OMP_PROC_BIND_unknown &&
- "unknown proc-bind kind");
- // The 'default' kind has no dialect counterpart; leave the attribute unset.
- if (kind != llvm::omp::ProcBindKind::OMP_PROC_BIND_default)
- result.procBindKind = mlir::omp::ClauseProcBindKindAttr::get(
- builder.getContext(), mlir::omp::convertProcBindKind(kind));
- return true;
- }
- return false;
-}
-
-bool OpenMPClauseEmitter::emitNumThreads(
- mlir::omp::NumThreadsClauseOps &result) const {
+bool OpenMPClauseEmitter::emitDefault() const {
for (const OMPClause *clause : clauses) {
- const auto *ntc = dyn_cast<OMPNumThreadsClause>(clause);
- if (!ntc)
+ const auto *dc = dyn_cast<OMPDefaultClause>(clause);
+ if (!dc)
continue;
- for (const Expr *expr : ntc->getNumThreads()) {
- mlir::Value numThreadsValue = cgf.emitScalarExpr(expr);
- auto intType = builder.getIntegerType(32);
- numThreadsValue = builder.createBuiltinIntCast(numThreadsValue, intType);
- result.numThreadsVars.push_back(numThreadsValue);
+ switch (dc->getDefaultKind()) {
+ case llvm::omp::OMP_DEFAULT_none:
+ case llvm::omp::OMP_DEFAULT_shared:
+ return true;
+ case llvm::omp::OMP_DEFAULT_private:
+ case llvm::omp::OMP_DEFAULT_firstprivate:
+ case llvm::omp::OMP_DEFAULT_unknown:
+ const char *default_kind_name = clang::getOpenMPSimpleClauseTypeName(
+ llvm::omp::OMPC_default, static_cast<unsigned>(dc->getDefaultKind()));
+ cgm.errorNYI(dc->getBeginLoc(),
+ std::string("Lowering for the default clause with kind '") +
+ default_kind_name + ("' not yet implemented."));
+ return false;
}
-
- return true;
}
return false;
}
@@ -190,3 +176,41 @@ bool OpenMPClauseEmitter::emitMap(
}
return found;
}
+
+bool OpenMPClauseEmitter::emitNumThreads(
+ mlir::omp::NumThreadsClauseOps &result) const {
+ for (const OMPClause *clause : clauses) {
+ const auto *ntc = dyn_cast<OMPNumThreadsClause>(clause);
+ if (!ntc)
+ continue;
+
+ for (const Expr *expr : ntc->getNumThreads()) {
+ mlir::Value numThreadsValue = cgf.emitScalarExpr(expr);
+ auto intType = builder.getIntegerType(32);
+ numThreadsValue = builder.createBuiltinIntCast(numThreadsValue, intType);
+ result.numThreadsVars.push_back(numThreadsValue);
+ }
+
+ return true;
+ }
+ return false;
+}
+
+bool OpenMPClauseEmitter::emitProcBind(
+ mlir::omp::ProcBindClauseOps &result) const {
+ for (const OMPClause *clause : clauses) {
+ const auto *pbc = dyn_cast<OMPProcBindClause>(clause);
+ if (!pbc)
+ continue;
+
+ llvm::omp::ProcBindKind kind = pbc->getProcBindKind();
+ assert(kind != llvm::omp::ProcBindKind::OMP_PROC_BIND_unknown &&
+ "unknown proc-bind kind");
+ // The 'default' kind has no dialect counterpart; leave the attribute unset.
+ if (kind != llvm::omp::ProcBindKind::OMP_PROC_BIND_default)
+ result.procBindKind = mlir::omp::ClauseProcBindKindAttr::get(
+ builder.getContext(), mlir::omp::convertProcBindKind(kind));
+ return true;
+ }
+ return false;
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenMPClause.h b/clang/lib/CIR/CodeGen/CIRGenOpenMPClause.h
index a5dcbcb918c737..64930479071c74 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenMPClause.h
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenMPClause.h
@@ -40,6 +40,8 @@ class OpenMPClauseEmitter {
llvm::ArrayRef<const OMPClause *> clauses)
: cgf(cgf), cgm(cgm), builder(builder), loc(loc), clauses(clauses) {}
+ bool emitDefault() const;
+
bool emitIf(mlir::omp::IfClauseOps &result,
llvm::omp::Directive directiveName) const;
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp b/clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp
index 9d937f5ed67f90..c20c9d945ee8e8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp
@@ -57,15 +57,15 @@ emitParallelClauses(CIRGenFunction &cgf, CIRGenModule &cgm,
llvm::ArrayRef<const OMPClause *> clauses,
mlir::omp::ParallelOperands &clauseOps) {
OpenMPClauseEmitter ce(cgf, cgm, builder, loc, clauses);
+ ce.emitDefault();
ce.emitIf(clauseOps, llvm::omp::Directive::OMPD_parallel);
ce.emitNumThreads(clauseOps);
ce.emitProcBind(clauseOps);
return ce.emitNYI</*supported=*/OMPIfClause, OMPNumThreadsClause,
- OMPProcBindClause>(
+ OMPProcBindClause, OMPDefaultClause>(
/*nyi=*/OpenMPNYIClauseList<OMPAllocateClause, OMPCopyinClause,
- OMPDefaultClause, OMPFirstprivateClause,
- OMPPrivateClause, OMPReductionClause,
- OMPSharedClause>{},
+ OMPFirstprivateClause, OMPPrivateClause,
+ OMPReductionClause, OMPSharedClause>{},
llvm::omp::Directive::OMPD_parallel);
}
diff --git a/clang/test/CIR/CodeGenOpenMP/not-yet-implemented.c b/clang/test/CIR/CodeGenOpenMP/not-yet-implemented.c
index c4a97e2b76d05b..93881db2a6390a 100644
--- a/clang/test/CIR/CodeGenOpenMP/not-yet-implemented.c
+++ b/clang/test/CIR/CodeGenOpenMP/not-yet-implemented.c
@@ -29,4 +29,12 @@ void do_things() {
// expected-error at +1{{ClangIR code gen Not Yet Implemented: OpenMP synthesized 'firstprivate' clause from construct decomposition}}
#pragma omp target
{ i = 1; }
+
+ // expected-error at +1{{ClangIR code gen Not Yet Implemented: Lowering for the default clause with kind 'private' not yet implemented.}}
+#pragma omp parallel default(private)
+ {}
+
+ // expected-error at +1{{ClangIR code gen Not Yet Implemented: Lowering for the default clause with kind 'firstprivate' not yet implemented.}}
+#pragma omp parallel default(firstprivate)
+ {}
}
diff --git a/clang/test/CIR/CodeGenOpenMP/parallel.c b/clang/test/CIR/CodeGenOpenMP/parallel.c
index 6a9a349c59489f..caac29732eb3b0 100644
--- a/clang/test/CIR/CodeGenOpenMP/parallel.c
+++ b/clang/test/CIR/CodeGenOpenMP/parallel.c
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -fopenmp -triple x86_64-linux-gnu -emit-cir -fclangir %s -o - | FileCheck %s
+// CHECK: cir.global "private" constant cir_private @__const.default_parallel.arr {{.*}} !cir.array<!s32i x 1> align(4)
+
void before(int);
void during(int);
void after(int);
@@ -53,6 +55,83 @@ void parallel_with_operations() {
// CHECK-NEXT: omp.terminator
// CHECK-NEXT: }
}
+
+void default_parallel() {
+ // CHECK: cir.func {{.*}} @default_parallel
+
+ int x = 0;
+ int y = 0;
+ int *p = &y;
+ int arr[1] = {0}; // Checked at the beginning of the file.
+
+ // CHECK-NEXT: %[[X_ADDR:.*]] = cir.alloca "x"
+ // CHECK-NEXT: %[[Y_ADDR:.*]] = cir.alloca "y"
+ // CHECK-NEXT: %[[P_ADDR:.*]] = cir.alloca "p"
+ // CHECK-NEXT: %[[ARR_ADDR:.*]] = cir.alloca "arr"
+
+#pragma omp parallel default(none)
+ {}
+ // CHECK: omp.parallel {
+ // CHECK-NEXT: omp.terminator
+ // CHECK-NEXT: }
+
+#pragma omp parallel default(none)
+ {
+ int inside = 10;
+ }
+ // CHECK-NEXT: omp.parallel {
+ // CHECK-NEXT: %[[INSIDE_ADDR:.*]] = cir.alloca "inside"
+ // CHECK-NEXT: %[[TEN_ADDR:.*]] = cir.const #cir.int<10>
+ // CHECK-NEXT: cir.store align(4) %[[TEN_ADDR]], %[[INSIDE_ADDR]]
+ // CHECK-NEXT: omp.terminator
+ // CHECK-NEXT: }
+
+#pragma omp parallel default(shared)
+ {}
+ // CHECK-NEXT: omp.parallel {
+ // CHECK-NEXT: omp.terminator
+ // CHECK-NEXT: }
+
+#pragma omp parallel default(shared)
+ {
+ x += 5;
+ }
+ // CHECK-NEXT: omp.parallel {
+ // CHECK-NEXT: %[[FIVE_ADDR:.*]] = cir.const #cir.int<5>
+ // CHECK-NEXT: %[[PTR_X_ADDR:.*]] = cir.load align(4) %[[X_ADDR]]
+ // CHECK-NEXT: %[[INCREMENT_X_ADDR:.*]] = cir.add nsw %[[PTR_X_ADDR]], %[[FIVE_ADDR]]
+ // CHECK-NEXT: cir.store align(4) %[[INCREMENT_X_ADDR]], %[[X_ADDR]]
+ // CHECK-NEXT: omp.terminator
+ // CHECK-NEXT: }
+
+#pragma omp parallel default(shared)
+ {
+ arr[0] += x;
+ }
+ // CHECK-NEXT: omp.parallel {
+ // CHECK-NEXT: %[[PTR_X_ADDR:.*]] = cir.load align(4) %[[X_ADDR]]
+ // CHECK-NEXT: %[[ZERO_IDX_ADDR:.*]] = cir.const #cir.int<0>
+ // CHECK-NEXT: %[[ARR_ELEMENT_ADDR:.*]] = cir.get_element %[[ARR_ADDR]][%[[ZERO_IDX_ADDR]] : !s64i]
+ // CHECK-NEXT: %[[PTR_ARR_ELEMENT_ADDR:.*]] = cir.load align(4) %[[ARR_ELEMENT_ADDR]]
+ // CHECK-NEXT: %[[INCREMENT_ELEMENT_ADDR:.*]] = cir.add nsw %[[PTR_ARR_ELEMENT_ADDR]], %[[PTR_X_ADDR]]
+ // CHECK-NEXT: cir.store align(4) %[[INCREMENT_ELEMENT_ADDR]], %[[ARR_ELEMENT_ADDR]]
+ // CHECK-NEXT: omp.terminator
+ // CHECK-NEXT: }
+
+#pragma omp parallel default(shared)
+ {
+ *p += x;
+ }
+ // CHECK-NEXT: omp.parallel {
+ // CHECK-NEXT: %[[PTR_X_ADDR:.*]] = cir.load align(4) %[[X_ADDR]]
+ // CHECK-NEXT: %[[DEREF_P_ADDR:.*]] = cir.load deref align(8) %[[P_ADDR]]
+ // CHECK-NEXT: %[[LOAD_DEREF_P_ADDR:.*]] = cir.load align(4) %[[DEREF_P_ADDR]]
+ // CHECK-NEXT: %[[INCREMENT_P_ADDR:.*]] = cir.add nsw %[[LOAD_DEREF_P_ADDR]], %[[PTR_X_ADDR]]
+ // CHECK-NEXT: cir.store align(4) %[[INCREMENT_P_ADDR]], %[[DEREF_P_ADDR]]
+ // CHECK-NEXT: omp.terminator
+ // CHECK-NEXT: }
+}
+
void proc_bind_parallel() {
// CHECK: cir.func{{.*}}@proc_bind_parallel
#pragma omp parallel proc_bind(master)
More information about the cfe-commits
mailing list