[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