https://github.com/aobolensk updated 
https://github.com/llvm/llvm-project/pull/233671

>From 19f43db687f175908974776191dc36e19d9d8990 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <[email protected]>
Date: Tue, 20 Oct 2026 06:34:44 +0200
Subject: [PATCH] [CIR] Narrow blanket -fopenmp NYI guards to OGCG conditions

Ordinary code compiled with -fopenmp hit errorNYI on every assignment, inc/dec, 
member access and global reference
---
 clang/include/clang/CIR/MissingFeatures.h     |  2 +
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp          | 22 +++--
 clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp   |  6 +-
 clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp    |  6 +-
 clang/lib/CIR/CodeGen/CIRGenModule.cpp        | 11 +--
 clang/lib/CIR/CodeGen/CIRGenOpenMPRuntime.cpp | 33 ++++++++
 clang/lib/CIR/CodeGen/CIRGenOpenMPRuntime.h   |  6 ++
 .../CIR/CodeGenOpenMP/non-openmp-code.cpp     | 80 +++++++++++++++++++
 8 files changed, 146 insertions(+), 20 deletions(-)
 create mode 100644 clang/test/CIR/CodeGenOpenMP/non-openmp-code.cpp

diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index 0ff6c6d44d191..0a3c594e1a8bf 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -274,6 +274,8 @@ struct MissingFeatures {
   static bool msvcBuiltins() { return false; }
   static bool openCL() { return false; }
   static bool openMP() { return false; }
+  static bool openMPLastprivateConditional() { return false; }
+  static bool openMPNontemporalDecl() { return false; }
   static bool sycl() { return false; }
   static bool opTBAA() { return false; }
   static bool peepholeProtection() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 9072a22cef52b..b790e2e73cdfd 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -463,8 +463,17 @@ static LValue emitGlobalVarDeclLValue(CIRGenFunction &cgf, 
const Expr *e,
 
   // Check if the variable is marked as declare target with link clause in
   // device codegen.
-  if (cgf.getLangOpts().OpenMP)
-    cgf.cgm.errorNYI(e->getSourceRange(), "emitGlobalVarDeclLValue: OpenMP");
+  if (cgf.getLangOpts().OpenMPIsTargetDevice) {
+    std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> res =
+        OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(vd);
+    if (res && (*res == OMPDeclareTargetDeclAttr::MT_Link ||
+                ((*res == OMPDeclareTargetDeclAttr::MT_To ||
+                  *res == OMPDeclareTargetDeclAttr::MT_Enter) &&
+                 cgf.cgm.getOpenMPRuntime().hasRequiresUnifiedSharedMemory())))
+      cgf.cgm.errorNYI(e->getSourceRange(),
+                       "emitGlobalVarDeclLValue: OpenMP declare target "
+                       "indirect access");
+  }
 
   // Traditional LLVM codegen handles thread local separately, CIR handles
   // as part of getAddrOfGlobalVar.
@@ -1906,7 +1915,9 @@ LValue CIRGenFunction::emitMemberExpr(const MemberExpr 
*e) {
       // If the member was explicitly marked as nontemporal, mark it as
       // nontemporal. If the base lvalue is marked as nontemporal, mark access
       // to children as nontemporal too.
-      cgm.errorNYI(e->getSourceRange(), "emitMemberExpr: OpenMP");
+      assert(!cir::MissingFeatures::openMPNontemporalDecl());
+      if (baseLV.isNontemporal())
+        lv.setNontemporal(true);
     }
     return lv;
   }
@@ -2272,10 +2283,7 @@ LValue CIRGenFunction::emitBinaryOperatorLValue(const 
BinaryOperator *e) {
     else
       emitStoreThroughLValue(rv, lv);
 
-    if (getLangOpts().OpenMP) {
-      cgm.errorNYI(e->getSourceRange(), "openmp");
-      return {};
-    }
+    assert(!cir::MissingFeatures::openMPLastprivateConditional());
 
     return lv;
   }
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
index 7dd24a6d076e8..a17c3c340a417 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
@@ -1086,8 +1086,7 @@ LValue CIRGenFunction::emitComplexAssignmentLValue(const 
BinaryOperator *e) {
 
   mlir::Value value; // ignored
   LValue lvalue = ComplexExprEmitter(*this).emitBinAssignLValue(e, value);
-  if (getLangOpts().OpenMP)
-    cgm.errorNYI("emitComplexAssignmentLValue OpenMP");
+  assert(!cir::MissingFeatures::openMPLastprivateConditional());
 
   return lvalue;
 }
@@ -1143,8 +1142,7 @@ mlir::Value 
CIRGenFunction::emitComplexPrePostIncDec(const UnaryOperator *e,
   // Store the updated result through the lvalue.
   emitStoreOfComplex(loc, incVal, lv, /*isInit=*/false);
 
-  if (getLangOpts().OpenMP)
-    cgm.errorNYI(loc, "emitComplexPrePostIncDec OpenMP");
+  assert(!cir::MissingFeatures::openMPLastprivateConditional());
 
   // If this is a postinc, return the value read from memory, otherwise use the
   // updated value.
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 2082963025238..7173feda7759f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -627,8 +627,7 @@ class ScalarExprEmitter : public 
StmtVisitor<ScalarExprEmitter, mlir::Value> {
   mlir::Value emitFixedPointIncDec(const UnaryOperator *e, mlir::Value value,
                                    QualType type);
   mlir::Value emitScalarPrePostIncDec(const UnaryOperator *e, LValue lv) {
-    if (cgf.getLangOpts().OpenMP)
-      cgf.cgm.errorNYI(e->getSourceRange(), "inc/dec OpenMP");
+    assert(!cir::MissingFeatures::openMPLastprivateConditional());
 
     QualType type = e->getSubExpr()->getType();
 
@@ -1731,8 +1730,7 @@ LValue ScalarExprEmitter::emitCompoundAssignLValue(
   else
     cgf.emitStoreThroughLValue(RValue::get(result), lhsLV);
 
-  if (cgf.getLangOpts().OpenMP)
-    cgf.cgm.errorNYI(e->getSourceRange(), "openmp");
+  assert(!cir::MissingFeatures::openMPLastprivateConditional());
 
   return lhsLV;
 }
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp 
b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 614a731158e45..d1a748d86777f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -1023,8 +1023,8 @@ LangAS CIRGenModule::getGlobalVarAddressSpace(const 
VarDecl *d) {
     return LangAS::cuda_device;
   }
 
-  if (langOpts.OpenMP)
-    errorNYI("OpenMP global address space");
+  if (langOpts.OpenMP && d && d->hasAttr<OMPAllocateDeclAttr>())
+    errorNYI(d->getSourceRange(), "OpenMP global address space");
 
   return getTargetCIRGenInfo().getGlobalVarAddressSpace(*this, d);
 }
@@ -1253,7 +1253,9 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef mangledName, 
mlir::Type ty,
     assert(!cir::MissingFeatures::opGlobalWeakRef());
 
     assert(!cir::MissingFeatures::setDLLStorageClass());
-    assert(!cir::MissingFeatures::openMP());
+
+    if (langOpts.OpenMP && !langOpts.OpenMPSimd && d)
+      getOpenMPRuntime().registerTargetGlobalVariable(d);
 
     if (entry.getSymType() == ty &&
         cir::normalizeDefaultAddressSpace(entryCIRAS) ==
@@ -1329,8 +1331,7 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef mangledName, 
mlir::Type ty,
   // Handle things which are present even on external declarations.
   if (d) {
     if (langOpts.OpenMP && !langOpts.OpenMPSimd)
-      errorNYI(d->getSourceRange(),
-               "getOrCreateCIRGlobal: OpenMP target global variable");
+      getOpenMPRuntime().registerTargetGlobalVariable(d);
 
     gv.setAlignmentAttr(getSize(astContext.getDeclAlign(d)));
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenMPRuntime.cpp 
b/clang/lib/CIR/CodeGen/CIRGenOpenMPRuntime.cpp
index 93ec2248f76eb..db747fa112ebc 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenMPRuntime.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenMPRuntime.cpp
@@ -16,6 +16,7 @@
 #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
 #include "mlir/Dialect/OpenMP/OpenMPInterfaces.h"
 #include "clang/AST/OpenMPClause.h"
+#include "clang/CIR/MissingFeatures.h"
 
 using namespace clang;
 using namespace clang::CIRGen;
@@ -172,6 +173,38 @@ bool CIRGenOpenMPRuntime::markAsGlobalTarget(GlobalDecl 
gd) {
   return !alreadyEmittedTargetDecls.insert(d).second;
 }
 
+// Mirrors CGOpenMPRuntime::registerTargetGlobalVariable.
+void CIRGenOpenMPRuntime::registerTargetGlobalVariable(const VarDecl *vd) {
+  if (cgm.getLangOpts().OMPTargetTriples.empty() &&
+      !cgm.getLangOpts().OpenMPIsTargetDevice)
+    return;
+
+  std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> res =
+      OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(vd);
+
+  if (res && *res != OMPDeclareTargetDeclAttr::MT_Link &&
+      vd->hasExternalStorage())
+    return;
+
+  if (res && *res == OMPDeclareTargetDeclAttr::MT_Local)
+    return;
+
+  if (!res) {
+    // OGCG records non-target variables emitted in device code.
+    assert(!cir::MissingFeatures::openMP());
+    return;
+  }
+
+  cgm.errorNYI(vd->getSourceRange(),
+               "registerTargetGlobalVariable: declare target variable");
+}
+
+bool CIRGenOpenMPRuntime::hasRequiresUnifiedSharedMemory() const {
+  // OGCG also sets this from '#pragma omp requires unified_shared_memory'.
+  assert(!cir::MissingFeatures::openMP());
+  return cgm.getLangOpts().OpenMPForceUSM;
+}
+
 void CIRGenOpenMPRuntime::emitDeclareTargetFunction(const FunctionDecl *fd,
                                                     cir::FuncOp funcOp) {
   const auto *attr = fd->getAttr<OMPDeclareTargetDeclAttr>();
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenMPRuntime.h 
b/clang/lib/CIR/CodeGen/CIRGenOpenMPRuntime.h
index d22200512e483..fb368e06c5b2a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenMPRuntime.h
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenMPRuntime.h
@@ -48,6 +48,12 @@ class CIRGenOpenMPRuntime {
   /// handled and should be skipped.
   bool markAsGlobalTarget(GlobalDecl gd);
 
+  /// Register a global variable that may need an offload entry.
+  void registerTargetGlobalVariable(const VarDecl *vd);
+
+  /// Return whether unified shared memory is required.
+  bool hasRequiresUnifiedSharedMemory() const;
+
   /// If the function has an OMPDeclareTargetDeclAttr, set the corresponding
   /// omp.declare_target attribute on the emitted cir.func op.
   void emitDeclareTargetFunction(const FunctionDecl *fd, cir::FuncOp funcOp);
diff --git a/clang/test/CIR/CodeGenOpenMP/non-openmp-code.cpp 
b/clang/test/CIR/CodeGenOpenMP/non-openmp-code.cpp
new file mode 100644
index 0000000000000..43a009073a76f
--- /dev/null
+++ b/clang/test/CIR/CodeGenOpenMP/non-openmp-code.cpp
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -fopenmp -triple x86_64-unknown-linux-gnu -fclangir 
-emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa -triple 
x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t-offload.cir
+// RUN: FileCheck --input-file=%t-offload.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -fopenmp -triple x86_64-unknown-linux-gnu -fclangir 
-emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefixes=LLVM,LLVMCIR
+// RUN: %clang_cc1 -fopenmp -triple x86_64-unknown-linux-gnu -emit-llvm %s -o 
%t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefixes=LLVM,OGCG
+
+// Ordinary code compiled with -fopenmp.
+
+int g;
+
+// CIR: cir.global external @g = #cir.int<0> : !s32i
+// LLVM: @g = global i32 0
+
+struct S {
+  int x;
+};
+
+void scalar_ops(S *s, int v) {
+  g = v;
+  g += v;
+  ++g;
+  s->x = g;
+}
+
+// CIR: cir.func{{.*}} @_Z10scalar_opsP1Si
+// CIR:   %[[G:.*]] = cir.get_global @g : !cir.ptr<!s32i>
+// CIR:   cir.store{{.*}} %{{.*}}, %[[G]] : !s32i, !cir.ptr<!s32i>
+// CIR:   %[[G1:.*]] = cir.get_global @g : !cir.ptr<!s32i>
+// CIR:   %[[G1_VAL:.*]] = cir.load{{.*}} %[[G1]] : !cir.ptr<!s32i>, !s32i
+// CIR:   %[[ADD:.*]] = cir.add nsw %[[G1_VAL]], %{{.*}} : !s32i
+// CIR:   cir.store{{.*}} %[[ADD]], %[[G1]] : !s32i, !cir.ptr<!s32i>
+// CIR:   %[[G2:.*]] = cir.get_global @g : !cir.ptr<!s32i>
+// CIR:   %[[G2_VAL:.*]] = cir.load{{.*}} %[[G2]] : !cir.ptr<!s32i>, !s32i
+// CIR:   %[[INC:.*]] = cir.inc nsw %[[G2_VAL]] : !s32i
+// CIR:   cir.store{{.*}} %[[INC]], %[[G2]] : !s32i, !cir.ptr<!s32i>
+// CIR:   %[[X:.*]] = cir.get_member %{{.*}}[0] {name = "x"} : 
!cir.ptr<!rec_S> -> !cir.ptr<!s32i>
+// CIR:   cir.store{{.*}} %{{.*}}, %[[X]] : !s32i, !cir.ptr<!s32i>
+
+// LLVM: define{{.*}} void @_Z10scalar_opsP1Si
+// LLVM:   store i32 %{{.*}}, ptr @g
+// LLVM:   %[[G1:.*]] = load i32, ptr @g
+// LLVM:   %[[ADD:.*]] = add nsw i32 %[[G1]], %{{.*}}
+// LLVM:   store i32 %[[ADD]], ptr @g
+// LLVM:   %[[G2:.*]] = load i32, ptr @g
+// LLVM:   %[[INC:.*]] = add nsw i32 %[[G2]], 1
+// LLVM:   store i32 %[[INC]], ptr @g
+// LLVM:   %[[X:.*]] = getelementptr inbounds nuw %struct.S, ptr %{{.*}}, i32 
0, i32 0
+// LLVM:   store i32 %{{.*}}, ptr %[[X]]
+
+void complex_ops(float _Complex *c, float _Complex v) {
+  *c = v;
+  ++*c;
+}
+
+// CIR: cir.func{{.*}} @_Z11complex_opsPCfS_
+// CIR:   %[[V:.*]] = cir.load align(4) %{{.*}} : 
!cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
+// CIR:   %[[C_PTR:.*]] = cir.load deref{{.*}} %{{.*}} : 
!cir.ptr<!cir.ptr<!cir.complex<!cir.float>>>, !cir.ptr<!cir.complex<!cir.float>>
+// CIR:   cir.store{{.*}} %[[V]], %[[C_PTR]] : !cir.complex<!cir.float>, 
!cir.ptr<!cir.complex<!cir.float>>
+// CIR:   %[[C_PTR2:.*]] = cir.load deref{{.*}} %{{.*}} : 
!cir.ptr<!cir.ptr<!cir.complex<!cir.float>>>, !cir.ptr<!cir.complex<!cir.float>>
+// CIR:   %[[C:.*]] = cir.load{{.*}} %[[C_PTR2]] : 
!cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
+// CIR:   %[[REAL:.*]] = cir.complex.real %[[C]] : !cir.complex<!cir.float> -> 
!cir.float
+// CIR:   %[[IMAG:.*]] = cir.complex.imag %[[C]] : !cir.complex<!cir.float> -> 
!cir.float
+// CIR:   %[[INC:.*]] = cir.fadd %[[REAL]], %{{.*}} : !cir.float
+// CIR:   %[[RES:.*]] = cir.complex.create %[[INC]], %[[IMAG]] : !cir.float -> 
!cir.complex<!cir.float>
+// CIR:   cir.store{{.*}} %[[RES]], %{{.*}} : !cir.complex<!cir.float>, 
!cir.ptr<!cir.complex<!cir.float>>
+
+// LLVMCIR: define{{.*}} void @_Z11complex_opsPCfS_
+// LLVMCIR:   store { float, float } %{{.*}}, ptr %{{.*}}
+// LLVMCIR:   %[[REAL:.*]] = extractvalue { float, float } %{{.*}}, 0
+// LLVMCIR:   %[[INC:.*]] = fadd float %[[REAL]], 1.000000e+00
+// LLVMCIR:   store { float, float } %{{.*}}, ptr %{{.*}}
+
+// OGCG: define{{.*}} void @_Z11complex_opsPCfS_
+// OGCG:   store float %{{.*}}, ptr %{{.*}}
+// OGCG:   store float %{{.*}}, ptr %{{.*}}
+// OGCG:   %[[REAL:.*]] = load float, ptr %{{.*}}
+// OGCG:   %[[INC:.*]] = fadd float %[[REAL]], 1.000000e+00

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to