Skip to content

[CIR] Address Space support for GlobalOps - #179082

Merged
RiverDave merged 6 commits into
mainfrom
users/riverdave/as-for-globalops
Mar 20, 2026
Merged

RiverDave merged 6 commits into
mainfrom
users/riverdave/as-for-globalops

Conversation

@RiverDave

@RiverDave RiverDave commented Feb 1, 2026

Copy link
Copy Markdown
Contributor

Related: #179278, #160386

Extends cir.global to accept address space attributes. Globals can now specify either target_address_space(N) or lang_address_space(offload_*). Address spaces are also preserved throughout get_global ops.

@github-actions

github-actions Bot commented Feb 1, 2026

Copy link
Copy Markdown

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

@RiverDave
RiverDave force-pushed the users/riverdave/as-for-globalops branch from d6c59b4 to 9b1cff9 Compare February 1, 2026 01:35
@RiverDave
RiverDave marked this pull request as ready for review February 1, 2026 16:08
@llvmbot llvmbot added clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project labels Feb 1, 2026
@llvmbot

llvmbot commented Feb 1, 2026

Copy link
Copy Markdown
Member

@llvm/pr-subscribers-clangir

@llvm/pr-subscribers-clang

Author: David Rivera (RiverDave)

Changes

Extends cir.global to accept address space attributes. Globals can now specify either target_address_space(N) or lang_address_space(offload_*). Address spaces are also preserved throughout get_global ops.


Patch is 28.27 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/179082.diff

14 Files Affected:

  • (modified) clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h (+8-6)
  • (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+3)
  • (modified) clang/lib/CIR/CodeGen/CIRGenBuilder.h (+5-2)
  • (modified) clang/lib/CIR/CodeGen/CIRGenExpr.cpp (+2-2)
  • (modified) clang/lib/CIR/CodeGen/CIRGenModule.cpp (+51-12)
  • (modified) clang/lib/CIR/CodeGen/CIRGenModule.h (+16-4)
  • (modified) clang/lib/CIR/CodeGen/TargetInfo.cpp (+9)
  • (modified) clang/lib/CIR/CodeGen/TargetInfo.h (+7)
  • (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+21-2)
  • (modified) clang/lib/CIR/Dialect/IR/CIRTypes.cpp (+15)
  • (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+19-20)
  • (modified) clang/test/CIR/IR/address-space.cir (+30)
  • (modified) clang/test/CIR/IR/invalid-addrspace.cir (+20)
  • (added) clang/test/CIR/Lowering/global-address-space.cir (+46)
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index 345507d3402e9..5bfc9e38de0a4 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -18,6 +18,7 @@
 #include "llvm/ADT/STLForwardCompat.h"
 #include "llvm/Support/ErrorHandling.h"
 
+#include "mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.h"
 #include "mlir/IR/Builders.h"
 #include "mlir/IR/BuiltinAttributes.h"
 #include "mlir/IR/Location.h"
@@ -358,14 +359,15 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
     return CIRBaseBuilderTy::createStore(loc, flag, dst);
   }
 
-  [[nodiscard]] cir::GlobalOp createGlobal(mlir::ModuleOp mlirModule,
-                                           mlir::Location loc,
-                                           mlir::StringRef name,
-                                           mlir::Type type, bool isConstant,
-                                           cir::GlobalLinkageKind linkage) {
+  [[nodiscard]] cir::GlobalOp
+  createGlobal(mlir::ModuleOp mlirModule, mlir::Location loc,
+               mlir::StringRef name, mlir::Type type, bool isConstant,
+               cir::GlobalLinkageKind linkage,
+               mlir::ptr::MemorySpaceAttrInterface addrSpace) {
     mlir::OpBuilder::InsertionGuard guard(*this);
     setInsertionPointToStart(mlirModule.getBody());
-    return cir::GlobalOp::create(*this, loc, name, type, isConstant, linkage);
+    return cir::GlobalOp::create(*this, loc, name, type, isConstant, addrSpace,
+                                 linkage);
   }
 
   cir::GetMemberOp createGetMember(mlir::Location loc, mlir::Type resultTy,
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index fe35ab305f4ba..279bbd6513bdc 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2219,6 +2219,7 @@ def CIR_GlobalOp : CIR_Op<"global", [
                        OptionalAttr<StrAttr>:$sym_visibility,
                        TypeAttr:$sym_type,
                        CIR_GlobalLinkageKind:$linkage,
+                       OptionalAttr<MemorySpaceAttrInterface>:$addr_space,
                        OptionalAttr<CIR_TLSModel>:$tls_model,
                        OptionalAttr<AnyAttr>:$initial_value,
                        UnitAttr:$comdat,
@@ -2237,6 +2238,7 @@ def CIR_GlobalOp : CIR_Op<"global", [
     (`comdat` $comdat^)?
     ($tls_model^)?
     (`dso_local` $dso_local^)?
+    (` ` custom<GlobalAddressSpaceValue>($addr_space)^ )?
     $sym_name
     custom<GlobalOpTypeAndInitialValue>($sym_type, $initial_value,
                                         $ctorRegion, $dtorRegion)
@@ -2257,6 +2259,7 @@ def CIR_GlobalOp : CIR_Op<"global", [
       "llvm::StringRef":$sym_name,
       "mlir::Type":$sym_type,
       CArg<"bool", "false">:$isConstant,
+      CArg<"mlir::ptr::MemorySpaceAttrInterface", "{}">:$addrSpace,
       // CIR defaults to external linkage.
       CArg<"cir::GlobalLinkageKind",
            "cir::GlobalLinkageKind::ExternalLinkage">:$linkage,
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index dc1ce9a901381..785276a63221b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -12,6 +12,7 @@
 #include "Address.h"
 #include "CIRGenRecordLayout.h"
 #include "CIRGenTypeCache.h"
+#include "mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.h"
 #include "mlir/IR/Attributes.h"
 #include "mlir/IR/BuiltinAttributes.h"
 #include "mlir/Support/LLVM.h"
@@ -595,7 +596,8 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
   [[nodiscard]] cir::GlobalOp
   createVersionedGlobal(mlir::ModuleOp module, mlir::Location loc,
                         mlir::StringRef name, mlir::Type type, bool isConstant,
-                        cir::GlobalLinkageKind linkage) {
+                        cir::GlobalLinkageKind linkage,
+                        mlir::ptr::MemorySpaceAttrInterface addrSpace = {}) {
     // Create a unique name if the given name is already taken.
     std::string uniqueName;
     if (unsigned version = globalsVersioning[name.str()]++)
@@ -603,7 +605,8 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
     else
       uniqueName = name.str();
 
-    return createGlobal(module, loc, uniqueName, type, isConstant, linkage);
+    return createGlobal(module, loc, uniqueName, type, isConstant, linkage,
+                        addrSpace);
   }
 
   cir::StackSaveOp createStackSave(mlir::Location loc, mlir::Type ty) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index ce0e62164029a..ab41b20d1689d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -296,9 +296,9 @@ static LValue emitGlobalVarDeclLValue(CIRGenFunction &cgf, const Expr *e,
   // as part of getAddrOfGlobalVar.
   mlir::Value v = cgf.cgm.getAddrOfGlobalVar(vd);
 
-  assert(!cir::MissingFeatures::addressSpace());
   mlir::Type realVarTy = cgf.convertTypeForMem(vd->getType());
-  cir::PointerType realPtrTy = cgf.getBuilder().getPointerTo(realVarTy);
+  cir::PointerType realPtrTy = cir::PointerType::get(
+      realVarTy, mlir::cast<cir::PointerType>(v.getType()).getAddrSpace());
   if (realPtrTy != v.getType())
     v = cgf.getBuilder().createBitcast(v.getLoc(), v, realPtrTy);
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 61d84f197e6ec..c5b4cfc39b6c1 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -23,11 +23,13 @@
 #include "clang/Basic/SourceManager.h"
 #include "clang/CIR/Dialect/IR/CIRAttrs.h"
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
+#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
 #include "clang/CIR/Dialect/IR/CIRTypes.h"
 #include "clang/CIR/Interfaces/CIROpInterfaces.h"
 #include "clang/CIR/MissingFeatures.h"
 
 #include "CIRGenFunctionInfo.h"
+#include "mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.h"
 #include "mlir/IR/BuiltinOps.h"
 #include "mlir/IR/Location.h"
 #include "mlir/IR/MLIRContext.h"
@@ -522,10 +524,11 @@ mlir::Operation *CIRGenModule::getGlobalValue(StringRef name) {
   return mlir::SymbolTable::lookupSymbolIn(theModule, name);
 }
 
-cir::GlobalOp CIRGenModule::createGlobalOp(CIRGenModule &cgm,
-                                           mlir::Location loc, StringRef name,
-                                           mlir::Type t, bool isConstant,
-                                           mlir::Operation *insertPoint) {
+cir::GlobalOp
+CIRGenModule::createGlobalOp(CIRGenModule &cgm, mlir::Location loc,
+                             StringRef name, mlir::Type t, bool isConstant,
+                             mlir::ptr::MemorySpaceAttrInterface addrSpace,
+                             mlir::Operation *insertPoint) {
   cir::GlobalOp g;
   CIRGenBuilderTy &builder = cgm.getBuilder();
 
@@ -545,7 +548,7 @@ cir::GlobalOp CIRGenModule::createGlobalOp(CIRGenModule &cgm,
         builder.setInsertionPointToStart(cgm.getModule().getBody());
     }
 
-    g = cir::GlobalOp::create(builder, loc, name, t, isConstant);
+    g = cir::GlobalOp::create(builder, loc, name, t, isConstant, addrSpace);
     if (!insertPoint)
       cgm.lastGlobalOp = g;
 
@@ -594,6 +597,39 @@ std::optional<cir::SourceLanguage> CIRGenModule::getCIRSourceLanguage() const {
   return std::nullopt;
 }
 
+LangAS CIRGenModule::getGlobalVarAddressSpace(const VarDecl *d) {
+  if (langOpts.OpenCL) {
+    LangAS as = d ? d->getType().getAddressSpace() : LangAS::opencl_global;
+    assert(as == LangAS::opencl_global || as == LangAS::opencl_global_device ||
+           as == LangAS::opencl_global_host || as == LangAS::opencl_constant ||
+           as == LangAS::opencl_local || as >= LangAS::FirstTargetAddressSpace);
+    return as;
+  }
+
+  if (langOpts.SYCLIsDevice &&
+      (!d || d->getType().getAddressSpace() == LangAS::Default))
+    llvm_unreachable("NYI");
+
+  if (langOpts.CUDA && langOpts.CUDAIsDevice) {
+    if (d) {
+      if (d->hasAttr<CUDAConstantAttr>())
+        return LangAS::cuda_constant;
+      if (d->hasAttr<CUDASharedAttr>())
+        return LangAS::cuda_shared;
+      if (d->hasAttr<CUDADeviceAttr>())
+        return LangAS::cuda_device;
+      if (d->getType().isConstQualified())
+        return LangAS::cuda_constant;
+    }
+    return LangAS::cuda_device;
+  }
+
+  if (langOpts.OpenMP)
+    llvm_unreachable("NYI");
+
+  return getTargetCIRGenInfo().getGlobalVarAddressSpace(*this, d);
+}
+
 static void setLinkageForGV(cir::GlobalOp &gv, const NamedDecl *nd) {
   // Set linkage and visibility in case we never see a definition.
   LinkageInfo lv = nd->getLinkageAndVisibility();
@@ -632,7 +668,6 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef mangledName, mlir::Type ty,
   }
 
   if (entry) {
-    assert(!cir::MissingFeatures::addressSpace());
     assert(!cir::MissingFeatures::opGlobalWeakRef());
 
     assert(!cir::MissingFeatures::setDLLStorageClass());
@@ -651,6 +686,7 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef mangledName, mlir::Type ty,
       errorNYI(d->getSourceRange(), "global with conflicting type");
     }
 
+    // FIXME: Validate this
     // Address space check removed because it is unnecessary because CIR records
     // address space info in types.
 
@@ -660,6 +696,9 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef mangledName, mlir::Type ty,
       return entry;
   }
 
+  mlir::ptr::MemorySpaceAttrInterface declCIRAS = cir::toCIRAddressSpaceAttr(
+      &getMLIRContext(), getGlobalVarAddressSpace(d));
+
   mlir::Location loc = getLoc(d->getSourceRange());
 
   // Calculate constant storage flag before creating the global. This was moved
@@ -675,9 +714,9 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef mangledName, mlir::Type ty,
 
   // mlir::SymbolTable::Visibility::Public is the default, no need to explicitly
   // mark it as such.
-  cir::GlobalOp gv =
-      CIRGenModule::createGlobalOp(*this, loc, mangledName, ty, isConstant,
-                                   /*insertPoint=*/entry.getOperation());
+  cir::GlobalOp gv = CIRGenModule::createGlobalOp(
+      *this, loc, mangledName, ty, isConstant, declCIRAS,
+      /*insertPoint=*/entry.getOperation());
 
   // This is the first use or definition of a mangled name.  If there is a
   // deferred decl with this name, remember that we need to emit it at the end
@@ -760,7 +799,7 @@ mlir::Value CIRGenModule::getAddrOfGlobalVar(const VarDecl *d, mlir::Type ty,
 
   bool tlsAccess = d->getTLSKind() != VarDecl::TLS_None;
   cir::GlobalOp g = getOrCreateCIRGlobal(d, ty, isForDefinition);
-  mlir::Type ptrTy = builder.getPointerTo(g.getSymType());
+  mlir::Type ptrTy = builder.getPointerTo(g.getSymType(), g.getAddrSpaceAttr());
   return cir::GetGlobalOp::create(builder, getLoc(d->getSourceRange()), ptrTy,
                                   g.getSymNameAttr(), tlsAccess);
 }
@@ -770,8 +809,8 @@ cir::GlobalViewAttr CIRGenModule::getAddrOfGlobalVarAttr(const VarDecl *d) {
   mlir::Type ty = getTypes().convertTypeForMem(d->getType());
 
   cir::GlobalOp globalOp = getOrCreateCIRGlobal(d, ty, NotForDefinition);
-  assert(!cir::MissingFeatures::addressSpace());
-  cir::PointerType ptrTy = builder.getPointerTo(globalOp.getSymType());
+  cir::PointerType ptrTy =
+      builder.getPointerTo(globalOp.getSymType(), globalOp.getAddrSpaceAttr());
   return builder.getGlobalViewAttr(ptrTy, globalOp);
 }
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 3c4f35bacc4f9..10bc8ddd1809c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -25,6 +25,7 @@
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
 
 #include "TargetInfo.h"
+#include "mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.h"
 #include "mlir/IR/Builders.h"
 #include "mlir/IR/BuiltinOps.h"
 #include "mlir/IR/MLIRContext.h"
@@ -170,10 +171,11 @@ class CIRGenModule : public CIRGenTypeCache {
   cir::GlobalOp getOrCreateCIRGlobal(const VarDecl *d, mlir::Type ty,
                                      ForDefinition_t isForDefinition);
 
-  static cir::GlobalOp createGlobalOp(CIRGenModule &cgm, mlir::Location loc,
-                                      llvm::StringRef name, mlir::Type t,
-                                      bool isConstant = false,
-                                      mlir::Operation *insertPoint = nullptr);
+  static cir::GlobalOp
+  createGlobalOp(CIRGenModule &cgm, mlir::Location loc, llvm::StringRef name,
+                 mlir::Type t, bool isConstant = false,
+                 mlir::ptr::MemorySpaceAttrInterface addrSpace = {},
+                 mlir::Operation *insertPoint = nullptr);
 
   /// Add a global constructor or destructor to the module.
   /// The priority is optional, if not specified, the default priority is used.
@@ -697,6 +699,16 @@ class CIRGenModule : public CIRGenTypeCache {
 
   /// Map source language used to a CIR attribute.
   std::optional<cir::SourceLanguage> getCIRSourceLanguage() const;
+
+  /// Return the AST address space of the underlying global variable for D, as
+  /// determined by its declaration. Normally this is the same as the address
+  /// space of D's type, but in CUDA, address spaces are associated with
+  /// declarations, not types. If D is nullptr, return the default address
+  /// space for global variable.
+  ///
+  /// For languages without explicit address spaces, if D has default address
+  /// space, target-specific global or constant address space may be returned.
+  LangAS getGlobalVarAddressSpace(const VarDecl *decl);
 };
 } // namespace CIRGen
 
diff --git a/clang/lib/CIR/CodeGen/TargetInfo.cpp b/clang/lib/CIR/CodeGen/TargetInfo.cpp
index b009478695f1b..50b973591d925 100644
--- a/clang/lib/CIR/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CIR/CodeGen/TargetInfo.cpp
@@ -73,6 +73,15 @@ bool TargetCIRGenInfo::isNoProtoCallVariadic(
   return false;
 }
 
+clang::LangAS
+TargetCIRGenInfo::getGlobalVarAddressSpace(CIRGenModule &CGM,
+                                           const clang::VarDecl *D) const {
+  assert(!CGM.getLangOpts().OpenCL &&
+         !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) &&
+         "Address space agnostic languages only");
+  return D ? D->getType().getAddressSpace() : LangAS::Default;
+}
+
 mlir::Value TargetCIRGenInfo::performAddrSpaceCast(
     CIRGenFunction &cgf, mlir::Value v,
     mlir::ptr::MemorySpaceAttrInterface srcAS, mlir::Type destTy,
diff --git a/clang/lib/CIR/CodeGen/TargetInfo.h b/clang/lib/CIR/CodeGen/TargetInfo.h
index 25bde654810ad..6108fa456b2c7 100644
--- a/clang/lib/CIR/CodeGen/TargetInfo.h
+++ b/clang/lib/CIR/CodeGen/TargetInfo.h
@@ -48,6 +48,13 @@ class TargetCIRGenInfo {
   /// Returns ABI info helper for the target.
   const ABIInfo &getABIInfo() const { return *info; }
 
+  /// Get target favored AST address space of a global variable for languages
+  /// other than OpenCL and CUDA.
+  /// If \p D is nullptr, returns the default target favored address space
+  /// for global variable.
+  virtual clang::LangAS getGlobalVarAddressSpace(CIRGenModule &CGM,
+                                                 const clang::VarDecl *D) const;
+
   /// Get the address space for alloca.
   virtual mlir::ptr::MemorySpaceAttrInterface getCIRAllocaAddressSpace() const {
     return {};
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 7b9fc83403f71..024adecf866a6 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -278,6 +278,13 @@ static void printOmittedTerminatorRegion(mlir::OpAsmPrinter &printer,
                       /*printBlockTerminators=*/!omitRegionTerm(region));
 }
 
+mlir::OptionalParseResult
+parseGlobalAddressSpaceValue(mlir::AsmParser &p,
+                             mlir::ptr::MemorySpaceAttrInterface &attr);
+
+void printGlobalAddressSpaceValue(mlir::AsmPrinter &printer, cir::GlobalOp op,
+                                  mlir::ptr::MemorySpaceAttrInterface attr);
+
 //===----------------------------------------------------------------------===//
 // AllocaOp
 //===----------------------------------------------------------------------===//
@@ -1610,7 +1617,9 @@ mlir::LogicalResult cir::GlobalOp::verify() {
 
 void cir::GlobalOp::build(
     OpBuilder &odsBuilder, OperationState &odsState, llvm::StringRef sym_name,
-    mlir::Type sym_type, bool isConstant, cir::GlobalLinkageKind linkage,
+    mlir::Type sym_type, bool isConstant,
+    mlir::ptr::MemorySpaceAttrInterface addrSpace,
+    cir::GlobalLinkageKind linkage,
     function_ref<void(OpBuilder &, Location)> ctorBuilder,
     function_ref<void(OpBuilder &, Location)> dtorBuilder) {
   odsState.addAttribute(getSymNameAttrName(odsState.name),
@@ -1620,6 +1629,8 @@ void cir::GlobalOp::build(
   if (isConstant)
     odsState.addAttribute(getConstantAttrName(odsState.name),
                           odsBuilder.getUnitAttr());
+  if (addrSpace)
+    odsState.addAttribute(getAddrSpaceAttrName(odsState.name), addrSpace);
 
   cir::GlobalLinkageKindAttr linkageAttr =
       cir::GlobalLinkageKindAttr::get(odsBuilder.getContext(), linkage);
@@ -1773,9 +1784,10 @@ cir::GetGlobalOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
            << "' does not reference a valid cir.global or cir.func";
 
   mlir::Type symTy;
+  mlir::ptr::MemorySpaceAttrInterface symAddrSpaceAttr{};
   if (auto g = dyn_cast<GlobalOp>(op)) {
     symTy = g.getSymType();
-    assert(!cir::MissingFeatures::addressSpace());
+    symAddrSpaceAttr = g.getAddrSpaceAttr();
     // Verify that for thread local global access, the global needs to
     // be marked with tls bits.
     if (getTls() && !g.getTlsModel())
@@ -1792,6 +1804,13 @@ cir::GetGlobalOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
            << resultType.getPointee() << "' does not match type " << symTy
            << " of the global @" << getName();
 
+  if (symAddrSpaceAttr != resultType.getAddrSpace()) {
+    return emitOpError()
+           << "result type address space does not match the address "
+              "space of the global @"
+           << getName();
+  }
+
   return success();
 }
 
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index 42445a07864d8..a8f6ee6a0fda0 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -1057,6 +1057,21 @@ void printAddressSpaceValue(mlir::AsmPrinter &p,
   llvm_unreachable("unexpected address-space attribute kind");
 }
 
+mlir::OptionalParseResult
+parseGlobalAddressSpaceValue(mlir::AsmParser &p,
+                             mlir::ptr::MemorySpaceAttrInterface &attr) {
+
+  mlir::SMLoc loc = p.getCurrentLocation();
+  if (parseAddressSpaceValue(p, attr).failed())
+    return p.emitError(loc, "failed to parse Address Space Value for GlobalOp");
+  return mlir::success();
+}
+
+void printGlobalAddressSpaceValue(mlir::AsmPrinter &printer, cir::GlobalOp,
+                                  mlir::ptr::MemorySpaceAttrInterface attr) {
+  printAddressSpaceValue(printer, attr);
+}
+
 mlir::ptr::MemorySpaceAttrInterface
 cir::toCIRAddressSpaceAttr(mlir::MLIRContext *ctx, clang::LangAS langAS) {
   using clang::LangAS;
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 584d163e15073..c5d6e06b219ce 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -102,6 +102,21 @@ static mlir::Value createIntCast(mlir::OpBuilder &bld, mlir::Value src,
   return mlir::LLVM::BitcastOp::create(bld, loc, dstTy, src);
 }
 
+static unsigned
+getNumericASFromCIRAS(mlir::ptr::MemorySpaceAttrInterface asAttr,
+                      [[maybe_unused]] cir::LowerModule *lowerModule) {
+  if (!asAttr)
+    return 0; // default AS
+  if (auto targetAddrSpaceAttr =
+          mlir::dyn_cast_if_present<cir::TargetAddressSpaceAttr>(asAttr))
+    return targetAddrSpaceAttr.getValue();
+
+  if (mlir::isa_and_present<cir::LangAddressSpaceAttr>(asAttr))
+    llvm_unreachable("lowering LangAddressSpaceAttr NYI");
+
+  llvm_unreachable("unexpected address Space attribute kindI");
+}
+
 static mlir::LLVM::Visibility
 lowerCIRVisibi...
[truncated]

@RiverDave
RiverDave requested a review from koparasy February 1, 2026 16:15
@RiverDave
RiverDave force-pushed the users/riverdave/memspaceattr-for-asattr branch from 5cba86c to 415807a Compare February 4, 2026 20:10
@RiverDave
RiverDave force-pushed the users/riverdave/as-for-globalops branch 2 times, most recently from 4d76edd to 6121b91 Compare February 4, 2026 20:25
@RiverDave
RiverDave force-pushed the users/riverdave/memspaceattr-for-asattr branch from 415807a to 8fee86d Compare February 4, 2026 20:25

@bcardosolopes bcardosolopes left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Great! There are changes for CIRGen but no tests to exercise this paths (only cir to cir tests have been added), you should add some.

@koparasy koparasy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Shouldn't we have have tests also for CUDA address spaces?
Also some nits.

Comment thread clang/lib/CIR/CodeGen/CIRGenModule.cpp Outdated
Comment thread clang/lib/CIR/CodeGen/CIRGenModule.cpp Outdated
@RiverDave
RiverDave force-pushed the users/riverdave/memspaceattr-for-asattr branch from f043eb6 to f7be6a8 Compare February 26, 2026 04:19
@RiverDave
RiverDave force-pushed the users/riverdave/as-for-globalops branch from 6121b91 to 9e991a1 Compare February 26, 2026 22:23
@RiverDave

Copy link
Copy Markdown
Contributor Author

Shouldn't we have have tests also for CUDA address spaces? Also some nits.

Thanks for the feedback! I had the initial impression we had to override getGlobalVarAS for NVPTX but that wasn't necessary. note that so far I've added support for AST -> CIR lowering, lowering to LLVM IR with the proper AS should come (I hope) after #179084 lands.

@RiverDave

RiverDave commented Feb 26, 2026

Copy link
Copy Markdown
Contributor Author

Great! There are changes for CIRGen but no tests to exercise this paths (only cir to cir tests have been added), you should add some.

Good point - I've Added CUDA CIRGen coverage and Global Ops with Target AS to LLVM IR lowering.

@koparasy koparasy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM! Thanks for adding the tests.

Base automatically changed from users/riverdave/memspaceattr-for-asattr to main February 28, 2026 04:08
@RiverDave
RiverDave force-pushed the users/riverdave/as-for-globalops branch 2 times, most recently from 116805a to b89c142 Compare March 2, 2026 21:33
@github-actions

github-actions Bot commented Mar 2, 2026

Copy link
Copy Markdown

🐧 Linux x64 Test Results

  • 116227 tests passed
  • 3936 tests skipped

✅ The build succeeded and all tests passed.

@RiverDave

RiverDave commented Mar 10, 2026

Copy link
Copy Markdown
Contributor Author

gentle ping: @andykaylor @xlauko - I'd like to get the final stamping on this :)

Comment thread clang/lib/CIR/CodeGen/CIRGenModule.cpp Outdated
Comment thread clang/lib/CIR/CodeGen/CIRGenModule.cpp Outdated
Comment thread clang/lib/CIR/CodeGen/CIRGenModule.cpp
Comment thread clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

#include "Inputs/cuda.h"

// CHECK: cir.global external lang_address_space(offload_global) @i = #cir.int<0> : !s32i

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd like to see this lowered to LLVM IR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I was hoping for langAS lowering to happen in this PR:
#179084

Once this is approved, I'll finalize that one.

@andykaylor andykaylor left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lgtm

@RiverDave
RiverDave force-pushed the users/riverdave/as-for-globalops branch from e7c112a to c8ad0ac Compare March 20, 2026 17:08
@RiverDave
RiverDave merged commit 0ec6e1d into main Mar 20, 2026
10 checks passed
@RiverDave
RiverDave deleted the users/riverdave/as-for-globalops branch March 20, 2026 18:01
Aadarsh-Keshri pushed a commit to Aadarsh-Keshri/llvm-project that referenced this pull request Mar 28, 2026
Related: llvm#179278,
llvm#160386

Extends cir.global to accept address space attributes. Globals can now
specify either `target_address_space(N)` or
`lang_address_space(offload_*)`. Address spaces are also preserved
throughout get_global ops.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants