[clang] [CIR] Lower constant NTTP objects (PR #194496)

Erich Keane via cfe-commits cfe-commits at lists.llvm.org
Mon Apr 27 16:56:36 PDT 2026


https://github.com/erichkeane created https://github.com/llvm/llvm-project/pull/194496

Like my previous patch, this just stores an NTTP object as a global (using the same code, with 1 level of indrection slipped off), and initializes it as a const.  This patch also fleshes out the CIRGenExprConstant.cpp area, leaving just 2 'NYI's in the area, 1 of which is the MSGuidAttr again.

>From 57be7430d9e405db5dd80b8976e86603a8815bb3 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Mon, 27 Apr 2026 16:47:50 -0700
Subject: [PATCH] [CIR] Lower constant NTTP objects

Like my previous patch, this just stores an NTTP object as a global
(using the same code, with 1 level of indrection slipped off), and
initializes it as a const.  This patch also fleshes out the
CIRGenExprConstant.cpp area, leaving just 2 'NYI's in the area, 1 of
which is the MSGuidAttr again.
---
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp          |  3 +-
 clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp  | 16 ++++---
 clang/lib/CIR/CodeGen/CIRGenModule.cpp        |  6 +--
 clang/lib/CIR/CodeGen/CIRGenModule.h          |  2 +-
 .../test/CIR/CodeGen/temp-param-obj-decl.cpp  | 43 +++++++++++++++++--
 5 files changed, 55 insertions(+), 15 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index dc1d5185189bf..26ced070de8ba 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -1062,7 +1062,8 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) {
 
   if (const auto *tpo = dyn_cast<TemplateParamObjectDecl>(nd)) {
     CharUnits alignment = cgm.getNaturalTypeAlignment(tpo->getType());
-    cir::GetGlobalOp atpo = cgm.getAddrOfTemplateParamObject(tpo);
+    cir::GetGlobalOp atpo =
+        builder.createGetGlobal(cgm.getAddrOfTemplateParamObject(tpo));
     assert(!MissingFeatures::addressSpace() &&
            "Do an address space conversion if necessary");
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
index a8b24fb686088..49920a2741aa2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
@@ -1411,12 +1411,16 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) {
       }
     }
 
-    // Classic codegen handles MSGuidDecl,UnnamedGlobalConstantDecl, and
-    // TemplateParamObjectDecl, but it can also fall through from VarDecl,
-    // in which case it silently returns nullptr. For now, let's emit an
-    // error to see what cases we need to handle.
-    cgm.errorNYI(d->getSourceRange(),
-                 "ConstantLValueEmitter: unhandled value decl");
+    if (isa<MSGuidDecl>(d))
+      cgm.errorNYI(d->getSourceRange(), "ConstantLValueEmitter: MSGuidDecl");
+
+    if (const auto *gcd = dyn_cast<UnnamedGlobalConstantDecl>(d))
+      cgm.errorNYI(d->getSourceRange(),
+                   "ConstantLValueEmitter: Unnamed global constant");
+
+    if (const auto *tpo = dyn_cast<TemplateParamObjectDecl>(d))
+      cgm.getBuilder().getGlobalViewAttr(cgm.getAddrOfTemplateParamObject(tpo));
+
     return {};
   }
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 1f35f55669ff7..7d719600a6025 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -3570,14 +3570,14 @@ CIRGenModule::getAddrOfGlobalTemporary(const MaterializeTemporaryExpr *mte,
   return cv;
 }
 
-cir::GetGlobalOp
+cir::GlobalOp
 CIRGenModule::getAddrOfTemplateParamObject(const TemplateParamObjectDecl *tpo) {
   StringRef name = getMangledName(tpo);
   CharUnits alignment = getNaturalTypeAlignment(tpo->getType());
 
   if (auto globalOp =
           mlir::dyn_cast_or_null<cir::GlobalOp>(getGlobalValue(name)))
-    return builder.createGetGlobal(globalOp);
+    return globalOp;
 
   ConstantEmitter emitter(*this);
   assert(!cir::MissingFeatures::addressSpace() &&
@@ -3610,7 +3610,7 @@ CIRGenModule::getAddrOfTemplateParamObject(const TemplateParamObjectDecl *tpo) {
 
   insertGlobalSymbol(globalOp);
 
-  return builder.createGetGlobal(globalOp);
+  return globalOp;
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 299346dc2de3f..b2c630ca7defd 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -358,7 +358,7 @@ class CIRGenModule : public CIRGenTypeCache {
   cir::GlobalViewAttr getAddrOfGlobalVarAttr(const VarDecl *d);
 
   /// Get the GlobalOp of a template parameter object.
-  cir::GetGlobalOp
+  cir::GlobalOp
   getAddrOfTemplateParamObject(const TemplateParamObjectDecl *tpo);
 
   CharUnits computeNonVirtualBaseClassOffset(
diff --git a/clang/test/CIR/CodeGen/temp-param-obj-decl.cpp b/clang/test/CIR/CodeGen/temp-param-obj-decl.cpp
index 8437af739268a..f815cf6ee99da 100644
--- a/clang/test/CIR/CodeGen/temp-param-obj-decl.cpp
+++ b/clang/test/CIR/CodeGen/temp-param-obj-decl.cpp
@@ -7,11 +7,46 @@
 
 struct HasMem { int x;};
 
-// CIR: cir.global "private" constant linkonce_odr comdat @_ZTAXtl6HasMemLi1EEE = #cir.const_record<{#cir.int<1> : !s32i}> : !rec_HasMem
-// CIR: cir.global "private" constant linkonce_odr comdat @_ZTAXtl6HasMemLi2EEE = #cir.const_record<{#cir.int<2> : !s32i}> : !rec_HasMem
+// CIR-DAG: cir.global "private" constant linkonce_odr comdat @_ZTAXtl6HasMemLi3EEE = #cir.const_record<{#cir.int<3> : !s32i}> : !rec_HasMem
+
+// LLVM-BOTH-DAG: @_ZTAXtl6HasMemLi1EEE = linkonce_odr constant %struct.HasMem { i32 1 }, comdat
+// LLVM-BOTH-DAG: @_ZTAXtl6HasMemLi2EEE = linkonce_odr constant %struct.HasMem { i32 2 }, comdat
+// LLVM-BOTH-DAG: @_ZTAXtl6HasMemLi3EEE = linkonce_odr constant %struct.HasMem { i32 3 }, comdat
+
+// LLVM-DAG: @ptr = global ptr null
+// OGCG-DAG: @ptr = global ptr @_ZTAXtl6HasMemLi3EEE
+
+template <HasMem m>
+constexpr const HasMem *get_ptr() { return &m; }
+
+const auto *ptr = get_ptr<HasMem{3}>();
+
+// CIR-LABEL: cir.func {{.*}}@_Z7get_ptrIXtl6HasMemLi3EEEEPKS0_v()
+// CIR:  %[[RET_ALLOCA:.*]] = cir.alloca !cir.ptr<!rec_HasMem>, !cir.ptr<!cir.ptr<!rec_HasMem>>
+// CIR:  %[[GET_GLOB:.*]] = cir.get_global @_ZTAXtl6HasMemLi3EEE : !cir.ptr<!rec_HasMem>
+// CIR:  cir.store %[[GET_GLOB]], %[[RET_ALLOCA]]
+// CIR:  %[[RET_LOAD:.*]] = cir.load %[[RET_ALLOCA]] : !cir.ptr<!cir.ptr<!rec_HasMem>>, !cir.ptr<!rec_HasMem>
+// CIR:  cir.return %[[RET_LOAD]] : !cir.ptr<!rec_HasMem>
+//
+// LLVM-LABEL: define {{.*}}@_Z7get_ptrIXtl6HasMemLi3EEEEPKS0_v()
+// LLVM: %[[RET_ALLOCA:.*]] = alloca ptr
+// LLVM: store ptr @_ZTAXtl6HasMemLi3EEE, ptr %[[RET_ALLOCA]]
+// LLVM: %[[RET_LOAD:.*]] = load ptr, ptr %[[RET_ALLOCA]]
+// LLVM: ret ptr %[[RET_LOAD]]
+//
+// CIR-DAG: cir.global external @ptr = #cir.ptr<null> : !cir.ptr<!rec_HasMem>
+// CIR-LABEL: cir.func {{.*}}@__cxx_global_var_init
+// CIR:   %[[GET_GLOB:.*]] = cir.get_global @ptr : !cir.ptr<!cir.ptr<!rec_HasMem>>
+// CIR:   %[[CALL:.*]] = cir.call @_Z7get_ptrIXtl6HasMemLi3EEEEPKS0_v() : ()
+// CIR:   cir.store {{.*}}%[[CALL]], %[[GET_GLOB]] : !cir.ptr<!rec_HasMem>, !cir.ptr<!cir.ptr<!rec_HasMem>>
+//
+// LLVM-LABEL: define {{.*}}@__cxx_global_var_init
+// LLVM:   %[[CALL:.*]] = call{{.*}} @_Z7get_ptrIXtl6HasMemLi3EEEEPKS0_v()
+// LLVM:   store ptr %[[CALL]], ptr @ptr
+
+// CIR-DAG: cir.global "private" constant linkonce_odr comdat @_ZTAXtl6HasMemLi1EEE = #cir.const_record<{#cir.int<1> : !s32i}> : !rec_HasMem
+// CIR-DAG: cir.global "private" constant linkonce_odr comdat @_ZTAXtl6HasMemLi2EEE = #cir.const_record<{#cir.int<2> : !s32i}> : !rec_HasMem
 
-// LLVM-BOTH: @_ZTAXtl6HasMemLi1EEE = linkonce_odr constant %struct.HasMem { i32 1 }, comdat
-// LLVM-BOTH: @_ZTAXtl6HasMemLi2EEE = linkonce_odr constant %struct.HasMem { i32 2 }, comdat
 template<HasMem m>
 int get_x() { return m.x; }
 // CIR-LABEL: cir.func {{.*}}@_Z5get_xIXtl6HasMemLi1EEEEiv()



More information about the cfe-commits mailing list