https://github.com/RiverDave updated 
https://github.com/llvm/llvm-project/pull/161028

>From 8c38500340087d2954be7068d8899d6db9090039 Mon Sep 17 00:00:00 2001
From: David Rivera <davidriv...@gmail.com>
Date: Sat, 27 Sep 2025 19:14:52 -0400
Subject: [PATCH 1/6] [CIR] Upstream `AddressSpace` support for `PointerType`

---
 .../CIR/Dialect/Builder/CIRBaseBuilder.h      |  16 ++-
 clang/include/clang/CIR/Dialect/IR/CIRAttrs.h |   1 +
 .../include/clang/CIR/Dialect/IR/CIRAttrs.td  |  41 ++++++
 .../clang/CIR/Dialect/IR/CIREnumAttr.td       |  24 ++++
 clang/include/clang/CIR/Dialect/IR/CIRTypes.h |  38 +++++
 .../include/clang/CIR/Dialect/IR/CIRTypes.td  |  62 +++++---
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp          |   3 +-
 clang/lib/CIR/CodeGen/CIRGenTypeCache.h       |   6 +
 clang/lib/CIR/CodeGen/CIRGenTypes.cpp         |   2 +-
 clang/lib/CIR/CodeGen/TargetInfo.h            |   2 +
 clang/lib/CIR/Dialect/IR/CIRAttrs.cpp         |   9 ++
 clang/lib/CIR/Dialect/IR/CIRTypes.cpp         | 133 +++++++++++++++---
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  19 ++-
 clang/test/CIR/IR/invalid-addrspace.cir       |  36 +++++
 clang/test/CIR/address-space.c                |  22 +++
 15 files changed, 370 insertions(+), 44 deletions(-)
 create mode 100644 clang/test/CIR/IR/invalid-addrspace.cir
 create mode 100644 clang/test/CIR/address-space.c

diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h 
b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index 3f83c302176c0..6206628a9213c 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -129,8 +129,20 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
     return cir::PointerType::get(ty);
   }
 
-  cir::PointerType getVoidPtrTy() {
-    return getPointerTo(cir::VoidType::get(getContext()));
+  cir::PointerType getPointerTo(mlir::Type ty, cir::AddressSpace as) {
+    return cir::PointerType::get(ty, as);
+  }
+
+  cir::PointerType getPointerTo(mlir::Type ty, clang::LangAS langAS) {
+    return getPointerTo(ty, cir::toCIRAddressSpace(langAS));
+  }
+
+  cir::PointerType getVoidPtrTy(clang::LangAS langAS = clang::LangAS::Default) 
{
+    return getPointerTo(cir::VoidType::get(getContext()), langAS);
+  }
+
+  cir::PointerType getVoidPtrTy(cir::AddressSpace as) {
+    return getPointerTo(cir::VoidType::get(getContext()), as);
   }
 
   cir::BoolAttr getCIRBoolAttr(bool state) {
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.h 
b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.h
index 925a9a87e267f..03a6a97dc8c2e 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.h
@@ -15,6 +15,7 @@
 
 #include "mlir/IR/Attributes.h"
 #include "mlir/IR/BuiltinAttributeInterfaces.h"
+#include "clang/Basic/AddressSpaces.h"
 
 #include "clang/CIR/Dialect/IR/CIROpsEnums.h"
 
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td 
b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index f8358de9a1eb9..01dd2106136ab 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -601,6 +601,47 @@ def CIR_VTableAttr : CIR_Attr<"VTable", "vtable", 
[TypedAttrInterface]> {
   }];
 }
 
+//===----------------------------------------------------------------------===//
+// AddressSpaceAttr
+//===----------------------------------------------------------------------===//
+
+def CIR_AddressSpaceAttr : CIR_EnumAttr<CIR_AddressSpace, "address_space"> {
+  let builders = [AttrBuilder<(ins "clang::LangAS":$langAS), [{
+      return $_get($_ctxt, cir::toCIRAddressSpace(langAS));
+    }]>];
+
+  let assemblyFormat = [{
+    `` custom<AddressSpaceValue>($value)
+  }];
+
+  let defaultValue = "cir::AddressSpace::Default";
+
+  let extraClassDeclaration = [{
+    bool isLang() const;
+    bool isTarget() const;
+    unsigned getTargetValue() const;
+    unsigned getAsUnsignedValue() const;
+  }];
+
+  let extraClassDefinition = [{
+    unsigned $cppClass::getAsUnsignedValue() const {
+      return static_cast<unsigned>(getValue());
+    }
+
+    bool $cppClass::isLang() const {
+      return cir::isLangAddressSpace(getValue());
+    }
+
+    bool $cppClass::isTarget() const {
+      return cir::isTargetAddressSpace(getValue());
+    }
+
+    unsigned $cppClass::getTargetValue() const {
+      return cir::getTargetAddressSpaceValue(getValue());
+    }
+  }];
+}
+
 
//===----------------------------------------------------------------------===//
 // ConstComplexAttr
 
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td 
b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
index 98b8a31d2a18a..6566b8e771a75 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
@@ -35,4 +35,28 @@ class CIR_DefaultValuedEnumParameter<EnumAttrInfo info, 
string value = "">
   let defaultValue = value;
 }
 
+def CIR_AddressSpace
+    : CIR_I32EnumAttr<
+          "AddressSpace", "address space kind",
+          [I32EnumAttrCase<"Default", 0, "default">,
+           I32EnumAttrCase<"OffloadPrivate", 1, "offload_private">,
+           I32EnumAttrCase<"OffloadLocal", 2, "offload_local">,
+           I32EnumAttrCase<"OffloadGlobal", 3, "offload_global">,
+           I32EnumAttrCase<"OffloadConstant", 4, "offload_constant">,
+           I32EnumAttrCase<"OffloadGeneric", 5, "offload_generic">,
+           I32EnumAttrCase<"Target", 6, "target">]> {
+  let description = [{
+    The `address_space` attribute is used to represent address spaces for
+    pointer types in CIR. It provides a unified model on top of `clang::LangAS`
+    and simplifies the representation of address spaces.
+
+    The `value` parameter is an extensible enum, which encodes target address
+    space as an offset to the last language address space. For that reason, the
+    attribute is implemented as custom AddressSpaceAttr, which provides custom
+    printer and parser for the `value` parameter.
+  }];
+
+  let genSpecializedAttr = 0;
+}
+
 #endif // CLANG_CIR_DIALECT_IR_CIRENUMATTR_TD
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h 
b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
index bfa165cdd945e..6a2b02ce46cd6 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
@@ -16,6 +16,8 @@
 #include "mlir/IR/BuiltinAttributes.h"
 #include "mlir/IR/Types.h"
 #include "mlir/Interfaces/DataLayoutInterfaces.h"
+#include "clang/Basic/AddressSpaces.h"
+#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
 #include "clang/CIR/Interfaces/CIRTypeInterfaces.h"
 
 namespace cir {
@@ -35,6 +37,42 @@ bool isValidFundamentalIntWidth(unsigned width);
 /// void, or abstract types.
 bool isSized(mlir::Type ty);
 
+//===----------------------------------------------------------------------===//
+// AddressSpace helpers
+//===----------------------------------------------------------------------===//
+
+cir::AddressSpace toCIRAddressSpace(clang::LangAS langAS);
+
+constexpr unsigned getAsUnsignedValue(cir::AddressSpace as) {
+  return static_cast<unsigned>(as);
+}
+
+inline constexpr unsigned targetAddressSpaceOffset =
+    cir::getMaxEnumValForAddressSpace();
+
+// Target address space is used for target-specific address spaces that are not
+// part of the enum. Its value is represented as an offset from the maximum
+// value of the enum. Make sure that it is always the last enum value.
+static_assert(getAsUnsignedValue(cir::AddressSpace::Target) ==
+                  cir::getMaxEnumValForAddressSpace(),
+              "Target address space must be the last enum value");
+
+constexpr bool isTargetAddressSpace(cir::AddressSpace as) {
+  return getAsUnsignedValue(as) >= cir::getMaxEnumValForAddressSpace();
+}
+
+constexpr bool isLangAddressSpace(cir::AddressSpace as) {
+  return !isTargetAddressSpace(as);
+}
+
+constexpr unsigned getTargetAddressSpaceValue(cir::AddressSpace as) {
+  assert(isTargetAddressSpace(as) && "expected target address space");
+  return getAsUnsignedValue(as) - targetAddressSpaceOffset;
+}
+
+constexpr cir::AddressSpace computeTargetAddressSpace(unsigned v) {
+  return static_cast<cir::AddressSpace>(v + targetAddressSpaceOffset);
+}
 } // namespace cir
 
 
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td 
b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index 4eec34cb299ab..13edfc5143650 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -14,10 +14,12 @@
 #define CLANG_CIR_DIALECT_IR_CIRTYPES_TD
 
 include "clang/CIR/Dialect/IR/CIRDialect.td"
+include "clang/CIR/Dialect/IR/CIREnumAttr.td"
 include "clang/CIR/Dialect/IR/CIRTypeConstraints.td"
 include "clang/CIR/Interfaces/CIRTypeInterfaces.td"
 include "mlir/Interfaces/DataLayoutInterfaces.td"
 include "mlir/IR/AttrTypeBase.td"
+include "mlir/IR/EnumAttr.td"
 
 
//===----------------------------------------------------------------------===//
 // CIR Types
@@ -226,31 +228,57 @@ def CIR_PointerType : CIR_Type<"Pointer", "ptr", [
 ]> {
   let summary = "CIR pointer type";
   let description = [{
-    The `!cir.ptr` type represents C and C++ pointer types and C++ reference
-    types, other than pointers-to-members.  The `pointee` type is the type
-    pointed to.
+    The `!cir.ptr` type is a typed pointer type. It is used to represent
+    pointers to objects in C/C++. The type of the pointed-to object is given by
+    the `pointee` parameter. The `addrSpace` parameter is an optional address
+    space attribute that specifies the address space of the pointer. If not
+    specified, the pointer is assumed to be in the default address space.
 
-    TODO(CIR): The address space attribute is not yet implemented.
-  }];
+    The `!cir.ptr` type can point to any type, including fundamental types,
+    records, arrays, vectors, functions, and other pointers. It can also point
+    to incomplete types, such as incomplete records.
 
-  let parameters = (ins "mlir::Type":$pointee);
+    Note: Data-member pointers and method pointers are represented by
+    `!cir.data_member` and `!cir.method` types, respectively not by
+    `!cir.ptr` type.
 
-  let builders = [
-    TypeBuilderWithInferredContext<(ins "mlir::Type":$pointee), [{
-      return $_get(pointee.getContext(), pointee);
-    }]>,
-    TypeBuilder<(ins "mlir::Type":$pointee), [{
-      return $_get($_ctxt, pointee);
-    }]>
-  ];
+    Examples:
 
-  let assemblyFormat = [{
-    `<` $pointee  `>`
+    ```mlir
+    !cir.ptr<!cir.int<u, 8>>
+    !cir.ptr<!cir.float>
+    !cir.ptr<!cir.record<struct "MyStruct">>
+    !cir.ptr<!cir.record<struct "MyStruct">, addrspace(offload_private)>
+    !cir.ptr<!cir.int<u, 8>, addrspace(target<1>)>
+    ```
   }];
 
-  let genVerifyDecl = 1;
+  let parameters = (ins "mlir::Type":$pointee,
+      CIR_DefaultValuedEnumParameter<CIR_AddressSpace,
+                                     "cir::AddressSpace::Default">:$addrSpace);
 
   let skipDefaultBuilders = 1;
+  let builders = [TypeBuilderWithInferredContext<
+                      (ins "mlir::Type":$pointee,
+                          CArg<"cir::AddressSpace",
+                               "cir::AddressSpace::Default">:$addrSpace),
+                      [{
+        return $_get(pointee.getContext(), pointee, addrSpace);
+    }]>,
+                  TypeBuilder<
+                      (ins "mlir::Type":$pointee,
+                          CArg<"cir::AddressSpace",
+                               "cir::AddressSpace::Default">:$addrSpace),
+                      [{
+        return $_get($_ctxt, pointee, addrSpace);
+    }]>];
+
+  let assemblyFormat = [{
+    `<`
+      $pointee
+      ( `,` `addrspace` `(` custom<AddressSpaceValue>($addrSpace)^ `)` )?
+    `>`
+  }];
 
   let extraClassDeclaration = [{
     template <typename ...Types>
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index fa68ad931ba74..44626bbdd1dfa 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -2053,7 +2053,8 @@ mlir::Value CIRGenFunction::emitAlloca(StringRef name, 
mlir::Type ty,
   // layout like original CodeGen. The data layout awareness should be done in
   // the lowering pass instead.
   assert(!cir::MissingFeatures::addressSpace());
-  cir::PointerType localVarPtrTy = builder.getPointerTo(ty);
+  cir::PointerType localVarPtrTy =
+      builder.getPointerTo(ty, getCIRAllocaAddressSpace());
   mlir::IntegerAttr alignIntAttr = cgm.getSize(alignment);
 
   mlir::Value addr;
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h 
b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
index cc3ce09be4f95..b95f0404eb8d9 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
+++ b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
@@ -73,6 +73,8 @@ struct CIRGenTypeCache {
   /// The alignment of size_t.
   unsigned char SizeAlignInBytes;
 
+  cir::AddressSpace cirAllocaAddressSpace;
+
   clang::CharUnits getSizeAlign() const {
     return clang::CharUnits::fromQuantity(SizeAlignInBytes);
   }
@@ -80,6 +82,10 @@ struct CIRGenTypeCache {
   clang::CharUnits getPointerAlign() const {
     return clang::CharUnits::fromQuantity(PointerAlignInBytes);
   }
+
+  cir::AddressSpace getCIRAllocaAddressSpace() const {
+    return cirAllocaAddressSpace;
+  }
 };
 
 } // namespace clang::CIRGen
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp 
b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index bb24933a22ed7..e65896a9ff109 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -417,7 +417,7 @@ mlir::Type CIRGenTypes::convertType(QualType type) {
 
     mlir::Type pointeeType = convertType(elemTy);
 
-    resultType = builder.getPointerTo(pointeeType);
+    resultType = builder.getPointerTo(pointeeType, elemTy.getAddressSpace());
     break;
   }
 
diff --git a/clang/lib/CIR/CodeGen/TargetInfo.h 
b/clang/lib/CIR/CodeGen/TargetInfo.h
index a5c548aa2c7c4..1c3ba0b9971b3 100644
--- a/clang/lib/CIR/CodeGen/TargetInfo.h
+++ b/clang/lib/CIR/CodeGen/TargetInfo.h
@@ -32,6 +32,8 @@ bool isEmptyFieldForLayout(const ASTContext &context, const 
FieldDecl *fd);
 /// if the [[no_unique_address]] attribute would have made them empty.
 bool isEmptyRecordForLayout(const ASTContext &context, QualType t);
 
+class CIRGenFunction;
+
 class TargetCIRGenInfo {
   std::unique_ptr<ABIInfo> info;
 
diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp 
b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
index 95faad6746955..ac3e08c880614 100644
--- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -43,6 +43,15 @@ parseFloatLiteral(mlir::AsmParser &parser,
                   mlir::FailureOr<llvm::APFloat> &value,
                   cir::FPTypeInterface fpType);
 
+//===----------------------------------------------------------------------===//
+// AddressSpaceAttr
+//===----------------------------------------------------------------------===//
+
+mlir::ParseResult parseAddressSpaceValue(mlir::AsmParser &p,
+                                         cir::AddressSpace &addrSpace);
+
+void printAddressSpaceValue(mlir::AsmPrinter &p, cir::AddressSpace addrSpace);
+
 static mlir::ParseResult parseConstPtr(mlir::AsmParser &parser,
                                        mlir::IntegerAttr &value);
 
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp 
b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index 35b4513c5789f..32254fb1e21c1 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -38,6 +38,26 @@ parseFuncTypeParams(mlir::AsmParser &p, 
llvm::SmallVector<mlir::Type> &params,
 static void printFuncTypeParams(mlir::AsmPrinter &p,
                                 mlir::ArrayRef<mlir::Type> params,
                                 bool isVarArg);
+//===----------------------------------------------------------------------===//
+// CIR Custom Parser/Printer Signatures
+//===----------------------------------------------------------------------===//
+
+static mlir::ParseResult
+parseFuncTypeParams(mlir::AsmParser &p, llvm::SmallVector<mlir::Type> &params,
+                    bool &isVarArg);
+
+static void printFuncTypeParams(mlir::AsmPrinter &p,
+                                mlir::ArrayRef<mlir::Type> params,
+                                bool isVarArg);
+
+//===----------------------------------------------------------------------===//
+// AddressSpace
+//===----------------------------------------------------------------------===//
+
+mlir::ParseResult parseAddressSpaceValue(mlir::AsmParser &p,
+                                         cir::AddressSpace &addrSpace);
+
+void printAddressSpaceValue(mlir::AsmPrinter &p, cir::AddressSpace addrSpace);
 
 
//===----------------------------------------------------------------------===//
 // Get autogenerated stuff
@@ -297,6 +317,20 @@ bool RecordType::isLayoutIdentical(const RecordType 
&other) {
 // Data Layout information for types
 
//===----------------------------------------------------------------------===//
 
+llvm::TypeSize
+PointerType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
+                               ::mlir::DataLayoutEntryListRef params) const {
+  // FIXME: improve this in face of address spaces
+  return llvm::TypeSize::getFixed(64);
+}
+
+uint64_t
+PointerType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
+                             ::mlir::DataLayoutEntryListRef params) const {
+  // FIXME: improve this in face of address spaces
+  return 8;
+}
+
 llvm::TypeSize
 RecordType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
                               mlir::DataLayoutEntryListRef params) const {
@@ -766,30 +800,93 @@ mlir::LogicalResult cir::VectorType::verify(
 }
 
 
//===----------------------------------------------------------------------===//
-// PointerType Definitions
-//===----------------------------------------------------------------------===//
-
-llvm::TypeSize
-PointerType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
-                               ::mlir::DataLayoutEntryListRef params) const {
-  // FIXME: improve this in face of address spaces
-  return llvm::TypeSize::getFixed(64);
+// AddressSpace definitions
+//===----------------------------------------------------------------------===//
+
+cir::AddressSpace cir::toCIRAddressSpace(clang::LangAS langAS) {
+  using clang::LangAS;
+  switch (langAS) {
+  case LangAS::Default:
+    return AddressSpace::Default;
+  case LangAS::opencl_global:
+    return AddressSpace::OffloadGlobal;
+  case LangAS::opencl_local:
+  case LangAS::cuda_shared:
+    // Local means local among the work-group (OpenCL) or block (CUDA).
+    // All threads inside the kernel can access local memory.
+    return AddressSpace::OffloadLocal;
+  case LangAS::cuda_device:
+    return AddressSpace::OffloadGlobal;
+  case LangAS::opencl_constant:
+  case LangAS::cuda_constant:
+    return AddressSpace::OffloadConstant;
+  case LangAS::opencl_private:
+    return AddressSpace::OffloadPrivate;
+  case LangAS::opencl_generic:
+    return AddressSpace::OffloadGeneric;
+  case LangAS::opencl_global_device:
+  case LangAS::opencl_global_host:
+  case LangAS::sycl_global:
+  case LangAS::sycl_global_device:
+  case LangAS::sycl_global_host:
+  case LangAS::sycl_local:
+  case LangAS::sycl_private:
+  case LangAS::ptr32_sptr:
+  case LangAS::ptr32_uptr:
+  case LangAS::ptr64:
+  case LangAS::hlsl_groupshared:
+  case LangAS::wasm_funcref:
+    llvm_unreachable("NYI");
+  default:
+    // Target address space offset arithmetics
+    return static_cast<cir::AddressSpace>(clang::toTargetAddressSpace(langAS) +
+                                          cir::getMaxEnumValForAddressSpace());
+  }
 }
 
-uint64_t
-PointerType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
-                             ::mlir::DataLayoutEntryListRef params) const {
-  // FIXME: improve this in face of address spaces
-  return 8;
-}
+mlir::ParseResult parseAddressSpaceValue(mlir::AsmParser &p,
+                                         cir::AddressSpace &addrSpace) {
+  llvm::SMLoc loc = p.getCurrentLocation();
+  mlir::FailureOr<cir::AddressSpace> result =
+      mlir::FieldParser<cir::AddressSpace>::parse(p);
+  if (mlir::failed(result))
+    return p.emitError(loc, "expected address space keyword");
+
+  // Address space is either a target address space or a regular one.
+  // - If it is a target address space, we expect a value to follow in the form
+  // of `<value>`, where value is an integer that represents the target address
+  // space value. This value is kept in the address space enum as an offset
+  // from the maximum address space value, which is defined in
+  // `cir::getMaxEnumValForAddressSpace()`. This allows us to use
+  // the same enum for both regular and target address spaces.
+  // - Otherwise, we just use the parsed value.
+  if (cir::isTargetAddressSpace(result.value())) {
+    if (p.parseLess())
+      return p.emitError(loc, "expected '<' after target address space");
+
+    int64_t targetValue;
+    if (p.parseInteger(targetValue) || p.parseGreater())
+      return p.emitError(loc, "expected target address space value");
+
+    addrSpace = cir::computeTargetAddressSpace(targetValue);
+  } else {
+    addrSpace = result.value();
+  }
 
-mlir::LogicalResult
-PointerType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
-                    mlir::Type pointee) {
-  // TODO(CIR): Verification of the address space goes here.
   return mlir::success();
 }
 
+// Prints the address space value in the form of:
+// - `target<value>` for target address spaces
+// - or just the address space name for regular address spaces.
+void printAddressSpaceValue(mlir::AsmPrinter &p, cir::AddressSpace addrSpace) {
+  if (cir::isTargetAddressSpace(addrSpace))
+    p << cir::stringifyEnum(cir::AddressSpace::Target) << '<'
+      << cir::getTargetAddressSpaceValue(addrSpace) << '>';
+  else
+    p << cir::stringifyEnum(addrSpace);
+}
+
 
//===----------------------------------------------------------------------===//
 // CIR Dialect
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 22f069d9cead0..9a1b85a9e8790 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2305,14 +2305,23 @@ mlir::LogicalResult 
CIRToLLVMSelectOpLowering::matchAndRewrite(
   return mlir::success();
 }
 
+static unsigned
+getTargetAddrSpaceFromCIRAddrSpace(cir::AddressSpace addrSpace) {
+  if (addrSpace == cir::AddressSpace::Default)
+    return 0; // Default address space is always 0 in LLVM.
+
+  if (cir::isTargetAddressSpace(addrSpace))
+    return cir::getTargetAddressSpaceValue(addrSpace);
+
+  llvm_unreachable("CIR AS map is not available");
+}
+
 static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
                                  mlir::DataLayout &dataLayout) {
   converter.addConversion([&](cir::PointerType type) -> mlir::Type {
-    // Drop pointee type since LLVM dialect only allows opaque pointers.
-    assert(!cir::MissingFeatures::addressSpace());
-    unsigned targetAS = 0;
-
-    return mlir::LLVM::LLVMPointerType::get(type.getContext(), targetAS);
+    unsigned addrSpace =
+        getTargetAddrSpaceFromCIRAddrSpace(type.getAddrSpace());
+    return mlir::LLVM::LLVMPointerType::get(type.getContext(), addrSpace);
   });
   converter.addConversion([&](cir::VPtrType type) -> mlir::Type {
     assert(!cir::MissingFeatures::addressSpace());
diff --git a/clang/test/CIR/IR/invalid-addrspace.cir 
b/clang/test/CIR/IR/invalid-addrspace.cir
new file mode 100644
index 0000000000000..369c7c0a45388
--- /dev/null
+++ b/clang/test/CIR/IR/invalid-addrspace.cir
@@ -0,0 +1,36 @@
+// RUN: cir-opt %s -verify-diagnostics -split-input-file
+
+// -----
+
+!u64i = !cir.int<u, 64>
+// expected-error@below {{expected address space keyword}}
+// expected-error@below {{expected keyword for address space kind}}
+cir.func @address_space1(%p : !cir.ptr<!u64i, addrspace()>) {
+  cir.return
+}
+
+// -----
+
+!u64i = !cir.int<u, 64>
+// expected-error@below {{expected target address space value}}
+// expected-error@below {{expected integer value}}
+cir.func @address_space2(%p : !cir.ptr<!u64i, addrspace(target<>)>) {
+  cir.return
+}
+
+// -----
+
+!u64i = !cir.int<u, 64>
+// expected-error@below {{expected '<'}}
+cir.func @address_space3(%p : !cir.ptr<!u64i, addrspace(target)>) {
+  cir.return
+}
+
+// -----
+
+!u64i = !cir.int<u, 64>
+// expected-error@below {{expected one of [default, offload_private, 
offload_local, offload_global, offload_constant, offload_generic, target] for 
address space kind, got: foobar}}
+// expected-error@below {{expected address space keyword}}
+cir.func @address_space4(%p : !cir.ptr<!u64i, addrspace(foobar)>) {
+  cir.return
+}
diff --git a/clang/test/CIR/address-space.c b/clang/test/CIR/address-space.c
new file mode 100644
index 0000000000000..d131fb84d98dc
--- /dev/null
+++ b/clang/test/CIR/address-space.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -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 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
%t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
+
+// CIR: cir.func dso_local {{@.*foo.*}}(%arg0: !cir.ptr<!s32i, 
addrspace(target<1>)>
+// LLVM: define dso_local void @foo(ptr addrspace(1) %0)
+void foo(int __attribute__((address_space(1))) *arg) {
+  return;
+}
+
+// CIR: cir.func dso_local {{@.*bar.*}}(%arg0: !cir.ptr<!s32i, 
addrspace(target<0>)>
+// LLVM: define dso_local void @bar(ptr %0)
+void bar(int __attribute__((address_space(0))) *arg) {
+  return;
+}
+
+// CIR: cir.func dso_local {{@.*baz.*}}(%arg0: !cir.ptr<!s32i>
+// LLVM: define dso_local void @baz(ptr %0)
+void baz(int *arg) {
+  return;
+}

>From feff1350baae490feb0cba502c2bbcfebbaa3740 Mon Sep 17 00:00:00 2001
From: David Rivera <davidriv...@gmail.com>
Date: Sun, 28 Sep 2025 17:17:17 -0400
Subject: [PATCH 2/6] Fix formatting on td files

---
 .../include/clang/CIR/Dialect/IR/CIRAttrs.td  | 10 +++---
 .../clang/CIR/Dialect/IR/CIREnumAttr.td       | 20 ++++++------
 .../include/clang/CIR/Dialect/IR/CIRTypes.td  | 32 ++++++++++---------
 3 files changed, 33 insertions(+), 29 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td 
b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 01dd2106136ab..69b4dd2143449 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -605,13 +605,15 @@ def CIR_VTableAttr : CIR_Attr<"VTable", "vtable", 
[TypedAttrInterface]> {
 // AddressSpaceAttr
 
//===----------------------------------------------------------------------===//
 
-def CIR_AddressSpaceAttr : CIR_EnumAttr<CIR_AddressSpace, "address_space"> {
-  let builders = [AttrBuilder<(ins "clang::LangAS":$langAS), [{
+def CIR_AddressSpaceAttr :  CIR_EnumAttr<CIR_AddressSpace, "address_space"> {
+  let builders = [
+    AttrBuilder<(ins "clang::LangAS":$langAS), [{
       return $_get($_ctxt, cir::toCIRAddressSpace(langAS));
-    }]>];
+    }]>
+  ];
 
   let assemblyFormat = [{
-    `` custom<AddressSpaceValue>($value)
+    `(` custom<AddressSpaceValue>($value) `)`
   }];
 
   let defaultValue = "cir::AddressSpace::Default";
diff --git a/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td 
b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
index 6566b8e771a75..01b2a34c1e663 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
@@ -35,16 +35,16 @@ class CIR_DefaultValuedEnumParameter<EnumAttrInfo info, 
string value = "">
   let defaultValue = value;
 }
 
-def CIR_AddressSpace
-    : CIR_I32EnumAttr<
-          "AddressSpace", "address space kind",
-          [I32EnumAttrCase<"Default", 0, "default">,
-           I32EnumAttrCase<"OffloadPrivate", 1, "offload_private">,
-           I32EnumAttrCase<"OffloadLocal", 2, "offload_local">,
-           I32EnumAttrCase<"OffloadGlobal", 3, "offload_global">,
-           I32EnumAttrCase<"OffloadConstant", 4, "offload_constant">,
-           I32EnumAttrCase<"OffloadGeneric", 5, "offload_generic">,
-           I32EnumAttrCase<"Target", 6, "target">]> {
+def CIR_AddressSpace : CIR_I32EnumAttr<
+  "AddressSpace", "address space kind", [
+  I32EnumAttrCase<"Default", 0, "default">,
+  I32EnumAttrCase<"OffloadPrivate", 1, "offload_private">,
+  I32EnumAttrCase<"OffloadLocal", 2, "offload_local">,
+  I32EnumAttrCase<"OffloadGlobal", 3, "offload_global">,
+  I32EnumAttrCase<"OffloadConstant", 4, "offload_constant">,
+  I32EnumAttrCase<"OffloadGeneric", 5, "offload_generic">,
+  I32EnumAttrCase<"Target", 6, "target">
+]> {
   let description = [{
     The `address_space` attribute is used to represent address spaces for
     pointer types in CIR. It provides a unified model on top of `clang::LangAS`
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td 
b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index 13edfc5143650..55f452bd4c27d 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -253,30 +253,32 @@ def CIR_PointerType : CIR_Type<"Pointer", "ptr", [
     ```
   }];
 
-  let parameters = (ins "mlir::Type":$pointee,
-      CIR_DefaultValuedEnumParameter<CIR_AddressSpace,
-                                     "cir::AddressSpace::Default">:$addrSpace);
+  let parameters = (ins
+    "mlir::Type":$pointee,
+    CIR_DefaultValuedEnumParameter<
+      CIR_AddressSpace,
+      "cir::AddressSpace::Default"
+    >:$addrSpace
+  );
 
   let skipDefaultBuilders = 1;
-  let builders = [TypeBuilderWithInferredContext<
-                      (ins "mlir::Type":$pointee,
-                          CArg<"cir::AddressSpace",
-                               "cir::AddressSpace::Default">:$addrSpace),
-                      [{
+  let builders = [
+    TypeBuilderWithInferredContext<(ins
+      "mlir::Type":$pointee,
+      CArg<"cir::AddressSpace", "cir::AddressSpace::Default">:$addrSpace), [{
         return $_get(pointee.getContext(), pointee, addrSpace);
     }]>,
-                  TypeBuilder<
-                      (ins "mlir::Type":$pointee,
-                          CArg<"cir::AddressSpace",
-                               "cir::AddressSpace::Default">:$addrSpace),
-                      [{
+    TypeBuilder<(ins
+      "mlir::Type":$pointee,
+      CArg<"cir::AddressSpace", "cir::AddressSpace::Default">:$addrSpace), [{
         return $_get($_ctxt, pointee, addrSpace);
-    }]>];
+    }]>
+  ];
 
   let assemblyFormat = [{
     `<`
       $pointee
-      ( `,` `addrspace` `(` custom<AddressSpaceValue>($addrSpace)^ `)` )?
+      ( `,` `addrspace` `(` `` custom<AddressSpaceValue>($addrSpace)^ `)` )?
     `>`
   }];
 

>From dce6d6153a7c4c1e638bc0de6390b738433a65bc Mon Sep 17 00:00:00 2001
From: David Rivera <davidriv...@gmail.com>
Date: Tue, 30 Sep 2025 13:44:51 -0400
Subject: [PATCH 3/6] Address first round of comments

---
 .../include/clang/CIR/Dialect/IR/CIRAttrs.td  | 32 +++++++++++++++++++
 .../clang/CIR/Dialect/IR/CIREnumAttr.td       |  5 ---
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp          |  1 -
 clang/lib/CIR/CodeGen/CIRGenModule.cpp        |  1 +
 clang/lib/CIR/CodeGen/TargetInfo.h            |  7 ++--
 clang/lib/CIR/Dialect/IR/CIRTypes.cpp         |  4 +--
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  2 +-
 clang/test/CIR/{ => CodeGen}/address-space.c  |  8 +++++
 8 files changed, 49 insertions(+), 11 deletions(-)
 rename clang/test/CIR/{ => CodeGen}/address-space.c (65%)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td 
b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 69b4dd2143449..786158411fb10 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -606,6 +606,38 @@ def CIR_VTableAttr : CIR_Attr<"VTable", "vtable", 
[TypedAttrInterface]> {
 
//===----------------------------------------------------------------------===//
 
 def CIR_AddressSpaceAttr :  CIR_EnumAttr<CIR_AddressSpace, "address_space"> {
+  let summary = "Attribute representing memory address spaces";
+  let description = [{
+    Represents different memory address spaces for pointer types.
+    Address spaces distinguish between different types of memory regions,
+    such as global, local, or constant memory.
+
+    The `value` parameter is an extensible enum, which encodes target address
+    space as an offset to the last language address space. For that reason, the
+    attribute is implemented as custom AddressSpaceAttr, which provides custom
+    printer and parser for the `value` parameter.
+
+    CIR supports two categories:
+    - Language address spaces: Predefined spaces like `offload_global`,
+      `offload_constant`, `offload_private` for offload programming models
+    - Target address spaces: Numeric spaces `target<N>` for target-specific
+      memory regions, where N is the address space number
+
+    Examples:
+    ```mlir
+    // Default address space (implicit)
+    !cir.ptr<!s32i>
+    
+    // Language-defined offload address spaces  
+    !cir.ptr<!s32i, addrspace(offload_global)>
+    !cir.ptr<!s32i, addrspace(offload_constant)>
+    !cir.ptr<!s32i, addrspace(offload_private)>
+    
+    // Target-specific numeric address spaces
+    !cir.ptr<!s32i, addrspace(target<1>)>
+    !cir.ptr<!s32i, addrspace(target<10>)>
+    ```
+  }];
   let builders = [
     AttrBuilder<(ins "clang::LangAS":$langAS), [{
       return $_get($_ctxt, cir::toCIRAddressSpace(langAS));
diff --git a/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td 
b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
index 01b2a34c1e663..93ad8781a079a 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
@@ -49,11 +49,6 @@ def CIR_AddressSpace : CIR_I32EnumAttr<
     The `address_space` attribute is used to represent address spaces for
     pointer types in CIR. It provides a unified model on top of `clang::LangAS`
     and simplifies the representation of address spaces.
-
-    The `value` parameter is an extensible enum, which encodes target address
-    space as an offset to the last language address space. For that reason, the
-    attribute is implemented as custom AddressSpaceAttr, which provides custom
-    printer and parser for the `value` parameter.
   }];
 
   let genSpecializedAttr = 0;
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 44626bbdd1dfa..158f1617a46db 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -2052,7 +2052,6 @@ mlir::Value CIRGenFunction::emitAlloca(StringRef name, 
mlir::Type ty,
   // CIR uses its own alloca address space rather than follow the target data
   // layout like original CodeGen. The data layout awareness should be done in
   // the lowering pass instead.
-  assert(!cir::MissingFeatures::addressSpace());
   cir::PointerType localVarPtrTy =
       builder.getPointerTo(ty, getCIRAllocaAddressSpace());
   mlir::IntegerAttr alignIntAttr = cgm.getSize(alignment);
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp 
b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 2bd2729f0b0fb..dc615316dd634 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -76,6 +76,7 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext,
   SInt128Ty = cir::IntType::get(&getMLIRContext(), 128, /*isSigned=*/true);
   UInt8Ty = cir::IntType::get(&getMLIRContext(), 8, /*isSigned=*/false);
   UInt8PtrTy = cir::PointerType::get(UInt8Ty);
+  cirAllocaAddressSpace = getTargetCIRGenInfo().getCIRAllocaAddressSpace();
   UInt16Ty = cir::IntType::get(&getMLIRContext(), 16, /*isSigned=*/false);
   UInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/false);
   UInt64Ty = cir::IntType::get(&getMLIRContext(), 64, /*isSigned=*/false);
diff --git a/clang/lib/CIR/CodeGen/TargetInfo.h 
b/clang/lib/CIR/CodeGen/TargetInfo.h
index 1c3ba0b9971b3..180dfa329cba4 100644
--- a/clang/lib/CIR/CodeGen/TargetInfo.h
+++ b/clang/lib/CIR/CodeGen/TargetInfo.h
@@ -32,8 +32,6 @@ bool isEmptyFieldForLayout(const ASTContext &context, const 
FieldDecl *fd);
 /// if the [[no_unique_address]] attribute would have made them empty.
 bool isEmptyRecordForLayout(const ASTContext &context, QualType t);
 
-class CIRGenFunction;
-
 class TargetCIRGenInfo {
   std::unique_ptr<ABIInfo> info;
 
@@ -45,6 +43,11 @@ class TargetCIRGenInfo {
   /// Returns ABI info helper for the target.
   const ABIInfo &getABIInfo() const { return *info; }
 
+  /// Get the CIR address space for alloca.
+  virtual cir::AddressSpace getCIRAllocaAddressSpace() const {
+    return cir::AddressSpace::Default;
+  }
+
   /// Determine whether a call to an unprototyped functions under
   /// the given calling convention should use the variadic
   /// convention or the non-variadic convention.
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp 
b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index 32254fb1e21c1..b5cec89a51966 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -852,13 +852,13 @@ mlir::ParseResult parseAddressSpaceValue(mlir::AsmParser 
&p,
   if (mlir::failed(result))
     return p.emitError(loc, "expected address space keyword");
 
-  // Address space is either a target address space or a regular one.
+  // Address space is either a target address space or a language-specific one.
   // - If it is a target address space, we expect a value to follow in the form
   // of `<value>`, where value is an integer that represents the target address
   // space value. This value is kept in the address space enum as an offset
   // from the maximum address space value, which is defined in
   // `cir::getMaxEnumValForAddressSpace()`. This allows us to use
-  // the same enum for both regular and target address spaces.
+  // the same enum for both language-specific and target address spaces.
   // - Otherwise, we just use the parsed value.
   if (cir::isTargetAddressSpace(result.value())) {
     if (p.parseLess())
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 9a1b85a9e8790..2b157856e744f 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2313,7 +2313,7 @@ getTargetAddrSpaceFromCIRAddrSpace(cir::AddressSpace 
addrSpace) {
   if (cir::isTargetAddressSpace(addrSpace))
     return cir::getTargetAddressSpaceValue(addrSpace);
 
-  llvm_unreachable("CIR AS map is not available");
+  llvm_unreachable("CIR target lowering is NYI");
 }
 
 static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
diff --git a/clang/test/CIR/address-space.c 
b/clang/test/CIR/CodeGen/address-space.c
similarity index 65%
rename from clang/test/CIR/address-space.c
rename to clang/test/CIR/CodeGen/address-space.c
index d131fb84d98dc..c67640eb5051a 100644
--- a/clang/test/CIR/address-space.c
+++ b/clang/test/CIR/CodeGen/address-space.c
@@ -2,21 +2,29 @@
 // RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
%t.ll
 // RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
 
+// Test address space 1
 // CIR: cir.func dso_local {{@.*foo.*}}(%arg0: !cir.ptr<!s32i, 
addrspace(target<1>)>
 // LLVM: define dso_local void @foo(ptr addrspace(1) %0)
+// OGCG: define dso_local void @foo(ptr addrspace(1) noundef %arg)
 void foo(int __attribute__((address_space(1))) *arg) {
   return;
 }
 
+// Test explicit address space 0 (should be same as default)
 // CIR: cir.func dso_local {{@.*bar.*}}(%arg0: !cir.ptr<!s32i, 
addrspace(target<0>)>
 // LLVM: define dso_local void @bar(ptr %0)
+// OGCG: define dso_local void @bar(ptr noundef %arg)
 void bar(int __attribute__((address_space(0))) *arg) {
   return;
 }
 
+// Test default address space (no attribute)
 // CIR: cir.func dso_local {{@.*baz.*}}(%arg0: !cir.ptr<!s32i>
 // LLVM: define dso_local void @baz(ptr %0)
+// OGCG: define dso_local void @baz(ptr noundef %arg)
 void baz(int *arg) {
   return;
 }

>From 89366183451ad93cf558aa5680a82426040d79a4 Mon Sep 17 00:00:00 2001
From: David Rivera <davidriv...@gmail.com>
Date: Wed, 1 Oct 2025 16:41:59 -0400
Subject: [PATCH 4/6] Refactor address space handling to use
 TargetAddressSpaceAttr and update related functionality

---
 .../CIR/Dialect/Builder/CIRBaseBuilder.h      |  17 ++-
 .../include/clang/CIR/Dialect/IR/CIRAttrs.td  |  69 ++--------
 .../clang/CIR/Dialect/IR/CIREnumAttr.td       |  19 ---
 clang/include/clang/CIR/Dialect/IR/CIRTypes.h |  34 +----
 .../include/clang/CIR/Dialect/IR/CIRTypes.td  |  15 +--
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp          |   2 +-
 clang/lib/CIR/CodeGen/CIRGenModule.cpp        |   2 +-
 clang/lib/CIR/CodeGen/CIRGenTypeCache.h       |   7 +-
 clang/lib/CIR/CodeGen/TargetInfo.h            |   7 +-
 clang/lib/CIR/Dialect/IR/CIRAttrs.cpp         |   7 +-
 clang/lib/CIR/Dialect/IR/CIRTypes.cpp         | 120 ++++++------------
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  15 +--
 clang/test/CIR/CodeGen/address-space.c        |   8 +-
 clang/test/CIR/IR/invalid-addrspace.cir       |  23 +---
 14 files changed, 95 insertions(+), 250 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h 
b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index 6206628a9213c..b875fac9b7969 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -10,6 +10,7 @@
 #define LLVM_CLANG_CIR_DIALECT_BUILDER_CIRBASEBUILDER_H
 
 #include "clang/AST/CharUnits.h"
+#include "clang/Basic/AddressSpaces.h"
 #include "clang/CIR/Dialect/IR/CIRAttrs.h"
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
 #include "clang/CIR/Dialect/IR/CIRTypes.h"
@@ -129,19 +130,29 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
     return cir::PointerType::get(ty);
   }
 
-  cir::PointerType getPointerTo(mlir::Type ty, cir::AddressSpace as) {
+  cir::PointerType getPointerTo(mlir::Type ty, cir::TargetAddressSpaceAttr as) 
{
     return cir::PointerType::get(ty, as);
   }
 
   cir::PointerType getPointerTo(mlir::Type ty, clang::LangAS langAS) {
-    return getPointerTo(ty, cir::toCIRAddressSpace(langAS));
+    if (langAS == clang::LangAS::Default) // Default address space.
+      return getPointerTo(ty);
+
+    if (clang::isTargetAddressSpace(langAS)) {
+      unsigned addrSpace = clang::toTargetAddressSpace(langAS);
+      auto asAttr = cir::TargetAddressSpaceAttr::get(
+          getContext(), getUI32IntegerAttr(addrSpace));
+      return getPointerTo(ty, asAttr);
+    }
+
+    llvm_unreachable("language-specific address spaces NYI");
   }
 
   cir::PointerType getVoidPtrTy(clang::LangAS langAS = clang::LangAS::Default) 
{
     return getPointerTo(cir::VoidType::get(getContext()), langAS);
   }
 
-  cir::PointerType getVoidPtrTy(cir::AddressSpace as) {
+  cir::PointerType getVoidPtrTy(cir::TargetAddressSpaceAttr as) {
     return getPointerTo(cir::VoidType::get(getContext()), as);
   }
 
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td 
b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 786158411fb10..6a0a2bde7368a 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -602,78 +602,25 @@ def CIR_VTableAttr : CIR_Attr<"VTable", "vtable", 
[TypedAttrInterface]> {
 }
 
 
//===----------------------------------------------------------------------===//
-// AddressSpaceAttr
+// TargetAddressSpaceAttr
 
//===----------------------------------------------------------------------===//
 
-def CIR_AddressSpaceAttr :  CIR_EnumAttr<CIR_AddressSpace, "address_space"> {
-  let summary = "Attribute representing memory address spaces";
+def CIR_TargetAddressSpaceAttr : CIR_Attr< "TargetAddressSpace",
+                                         "target_address_space"> {
+  let summary = "Attribute representing a target-specific numeric address 
space";
   let description = [{
-    Represents different memory address spaces for pointer types.
-    Address spaces distinguish between different types of memory regions,
-    such as global, local, or constant memory.
+    Represents a target-specific numeric address space for pointer types.
 
-    The `value` parameter is an extensible enum, which encodes target address
-    space as an offset to the last language address space. For that reason, the
-    attribute is implemented as custom AddressSpaceAttr, which provides custom
-    printer and parser for the `value` parameter.
-
-    CIR supports two categories:
-    - Language address spaces: Predefined spaces like `offload_global`,
-      `offload_constant`, `offload_private` for offload programming models
-    - Target address spaces: Numeric spaces `target<N>` for target-specific
-      memory regions, where N is the address space number
-
-    Examples:
+    Example:
     ```mlir
-    // Default address space (implicit)
-    !cir.ptr<!s32i>
-    
-    // Language-defined offload address spaces  
-    !cir.ptr<!s32i, addrspace(offload_global)>
-    !cir.ptr<!s32i, addrspace(offload_constant)>
-    !cir.ptr<!s32i, addrspace(offload_private)>
-    
     // Target-specific numeric address spaces
     !cir.ptr<!s32i, addrspace(target<1>)>
     !cir.ptr<!s32i, addrspace(target<10>)>
     ```
   }];
-  let builders = [
-    AttrBuilder<(ins "clang::LangAS":$langAS), [{
-      return $_get($_ctxt, cir::toCIRAddressSpace(langAS));
-    }]>
-  ];
-
-  let assemblyFormat = [{
-    `(` custom<AddressSpaceValue>($value) `)`
-  }];
-
-  let defaultValue = "cir::AddressSpace::Default";
-
-  let extraClassDeclaration = [{
-    bool isLang() const;
-    bool isTarget() const;
-    unsigned getTargetValue() const;
-    unsigned getAsUnsignedValue() const;
-  }];
 
-  let extraClassDefinition = [{
-    unsigned $cppClass::getAsUnsignedValue() const {
-      return static_cast<unsigned>(getValue());
-    }
-
-    bool $cppClass::isLang() const {
-      return cir::isLangAddressSpace(getValue());
-    }
-
-    bool $cppClass::isTarget() const {
-      return cir::isTargetAddressSpace(getValue());
-    }
-
-    unsigned $cppClass::getTargetValue() const {
-      return cir::getTargetAddressSpaceValue(getValue());
-    }
-  }];
+  let parameters = (ins "mlir::IntegerAttr":$value);
+  let assemblyFormat = "`<` `target` `<` $value `>` `>`";
 }
 
 
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td 
b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
index 93ad8781a079a..98b8a31d2a18a 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
@@ -35,23 +35,4 @@ class CIR_DefaultValuedEnumParameter<EnumAttrInfo info, 
string value = "">
   let defaultValue = value;
 }
 
-def CIR_AddressSpace : CIR_I32EnumAttr<
-  "AddressSpace", "address space kind", [
-  I32EnumAttrCase<"Default", 0, "default">,
-  I32EnumAttrCase<"OffloadPrivate", 1, "offload_private">,
-  I32EnumAttrCase<"OffloadLocal", 2, "offload_local">,
-  I32EnumAttrCase<"OffloadGlobal", 3, "offload_global">,
-  I32EnumAttrCase<"OffloadConstant", 4, "offload_constant">,
-  I32EnumAttrCase<"OffloadGeneric", 5, "offload_generic">,
-  I32EnumAttrCase<"Target", 6, "target">
-]> {
-  let description = [{
-    The `address_space` attribute is used to represent address spaces for
-    pointer types in CIR. It provides a unified model on top of `clang::LangAS`
-    and simplifies the representation of address spaces.
-  }];
-
-  let genSpecializedAttr = 0;
-}
-
 #endif // CLANG_CIR_DIALECT_IR_CIRENUMATTR_TD
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h 
b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
index 6a2b02ce46cd6..c1a063875f480 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
@@ -17,6 +17,7 @@
 #include "mlir/IR/Types.h"
 #include "mlir/Interfaces/DataLayoutInterfaces.h"
 #include "clang/Basic/AddressSpaces.h"
+#include "clang/CIR/Dialect/IR/CIRAttrs.h"
 #include "clang/CIR/Dialect/IR/CIROpsEnums.h"
 #include "clang/CIR/Interfaces/CIRTypeInterfaces.h"
 
@@ -41,38 +42,9 @@ bool isSized(mlir::Type ty);
 // AddressSpace helpers
 
//===----------------------------------------------------------------------===//
 
-cir::AddressSpace toCIRAddressSpace(clang::LangAS langAS);
+/// Returns the integer value of a CIR address space for LLVM.
+unsigned getTargetAddrSpaceFromAttr(cir::TargetAddressSpaceAttr attr);
 
-constexpr unsigned getAsUnsignedValue(cir::AddressSpace as) {
-  return static_cast<unsigned>(as);
-}
-
-inline constexpr unsigned targetAddressSpaceOffset =
-    cir::getMaxEnumValForAddressSpace();
-
-// Target address space is used for target-specific address spaces that are not
-// part of the enum. Its value is represented as an offset from the maximum
-// value of the enum. Make sure that it is always the last enum value.
-static_assert(getAsUnsignedValue(cir::AddressSpace::Target) ==
-                  cir::getMaxEnumValForAddressSpace(),
-              "Target address space must be the last enum value");
-
-constexpr bool isTargetAddressSpace(cir::AddressSpace as) {
-  return getAsUnsignedValue(as) >= cir::getMaxEnumValForAddressSpace();
-}
-
-constexpr bool isLangAddressSpace(cir::AddressSpace as) {
-  return !isTargetAddressSpace(as);
-}
-
-constexpr unsigned getTargetAddressSpaceValue(cir::AddressSpace as) {
-  assert(isTargetAddressSpace(as) && "expected target address space");
-  return getAsUnsignedValue(as) - targetAddressSpaceOffset;
-}
-
-constexpr cir::AddressSpace computeTargetAddressSpace(unsigned v) {
-  return static_cast<cir::AddressSpace>(v + targetAddressSpaceOffset);
-}
 } // namespace cir
 
 
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td 
b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index 55f452bd4c27d..e2f64f84d266f 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -248,16 +248,15 @@ def CIR_PointerType : CIR_Type<"Pointer", "ptr", [
     !cir.ptr<!cir.int<u, 8>>
     !cir.ptr<!cir.float>
     !cir.ptr<!cir.record<struct "MyStruct">>
-    !cir.ptr<!cir.record<struct "MyStruct">, addrspace(offload_private)>
-    !cir.ptr<!cir.int<u, 8>, addrspace(target<1>)>
+    !cir.ptr<!cir.int<u, 8>, target_address_space(1)>
+    !cir.ptr<!cir.record<struct "MyStruct">, target_address_space(5)>
     ```
   }];
 
   let parameters = (ins
     "mlir::Type":$pointee,
-    CIR_DefaultValuedEnumParameter<
-      CIR_AddressSpace,
-      "cir::AddressSpace::Default"
+    OptionalParameter<
+    "cir::TargetAddressSpaceAttr"
     >:$addrSpace
   );
 
@@ -265,12 +264,12 @@ def CIR_PointerType : CIR_Type<"Pointer", "ptr", [
   let builders = [
     TypeBuilderWithInferredContext<(ins
       "mlir::Type":$pointee,
-      CArg<"cir::AddressSpace", "cir::AddressSpace::Default">:$addrSpace), [{
+       CArg<"cir::TargetAddressSpaceAttr", "nullptr">:$addrSpace), [{
         return $_get(pointee.getContext(), pointee, addrSpace);
     }]>,
     TypeBuilder<(ins
       "mlir::Type":$pointee,
-      CArg<"cir::AddressSpace", "cir::AddressSpace::Default">:$addrSpace), [{
+      CArg<"cir::TargetAddressSpaceAttr", "nullptr">:$addrSpace), [{
         return $_get($_ctxt, pointee, addrSpace);
     }]>
   ];
@@ -278,7 +277,7 @@ def CIR_PointerType : CIR_Type<"Pointer", "ptr", [
   let assemblyFormat = [{
     `<`
       $pointee
-      ( `,` `addrspace` `(` `` custom<AddressSpaceValue>($addrSpace)^ `)` )?
+      ( `,` ` ` custom<TargetAddressSpace>($addrSpace)^ )?
     `>`
   }];
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 158f1617a46db..16cfc96022497 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -2053,7 +2053,7 @@ mlir::Value CIRGenFunction::emitAlloca(StringRef name, 
mlir::Type ty,
   // layout like original CodeGen. The data layout awareness should be done in
   // the lowering pass instead.
   cir::PointerType localVarPtrTy =
-      builder.getPointerTo(ty, getCIRAllocaAddressSpace());
+      builder.getPointerTo(ty, getASTAllocaAddressSpace());
   mlir::IntegerAttr alignIntAttr = cgm.getSize(alignment);
 
   mlir::Value addr;
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp 
b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index dc615316dd634..fc26d1f2e1f63 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -76,7 +76,7 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext,
   SInt128Ty = cir::IntType::get(&getMLIRContext(), 128, /*isSigned=*/true);
   UInt8Ty = cir::IntType::get(&getMLIRContext(), 8, /*isSigned=*/false);
   UInt8PtrTy = cir::PointerType::get(UInt8Ty);
-  cirAllocaAddressSpace = getTargetCIRGenInfo().getCIRAllocaAddressSpace();
+  ASTAllocaAddressSpace = getTargetCIRGenInfo().getASTAllocaAddressSpace();
   UInt16Ty = cir::IntType::get(&getMLIRContext(), 16, /*isSigned=*/false);
   UInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/false);
   UInt64Ty = cir::IntType::get(&getMLIRContext(), 64, /*isSigned=*/false);
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h 
b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
index b95f0404eb8d9..3e261c4b82fb4 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
+++ b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
@@ -14,6 +14,7 @@
 #define LLVM_CLANG_LIB_CIR_CIRGENTYPECACHE_H
 
 #include "clang/AST/CharUnits.h"
+#include "clang/Basic/AddressSpaces.h"
 #include "clang/CIR/Dialect/IR/CIRTypes.h"
 
 namespace clang::CIRGen {
@@ -73,7 +74,7 @@ struct CIRGenTypeCache {
   /// The alignment of size_t.
   unsigned char SizeAlignInBytes;
 
-  cir::AddressSpace cirAllocaAddressSpace;
+  LangAS ASTAllocaAddressSpace;
 
   clang::CharUnits getSizeAlign() const {
     return clang::CharUnits::fromQuantity(SizeAlignInBytes);
@@ -83,9 +84,7 @@ struct CIRGenTypeCache {
     return clang::CharUnits::fromQuantity(PointerAlignInBytes);
   }
 
-  cir::AddressSpace getCIRAllocaAddressSpace() const {
-    return cirAllocaAddressSpace;
-  }
+  LangAS getASTAllocaAddressSpace() const { return ASTAllocaAddressSpace; }
 };
 
 } // namespace clang::CIRGen
diff --git a/clang/lib/CIR/CodeGen/TargetInfo.h 
b/clang/lib/CIR/CodeGen/TargetInfo.h
index 180dfa329cba4..b23b0581b5c14 100644
--- a/clang/lib/CIR/CodeGen/TargetInfo.h
+++ b/clang/lib/CIR/CodeGen/TargetInfo.h
@@ -16,6 +16,7 @@
 
 #include "ABIInfo.h"
 #include "CIRGenTypes.h"
+#include "clang/Basic/AddressSpaces.h"
 
 #include <memory>
 #include <utility>
@@ -43,10 +44,8 @@ class TargetCIRGenInfo {
   /// Returns ABI info helper for the target.
   const ABIInfo &getABIInfo() const { return *info; }
 
-  /// Get the CIR address space for alloca.
-  virtual cir::AddressSpace getCIRAllocaAddressSpace() const {
-    return cir::AddressSpace::Default;
-  }
+  /// Get the AST address space for alloca.
+  virtual LangAS getASTAllocaAddressSpace() const { return LangAS::Default; }
 
   /// Determine whether a call to an unprototyped functions under
   /// the given calling convention should use the variadic
diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp 
b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
index ac3e08c880614..5ba05a04a56b1 100644
--- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -47,10 +47,11 @@ parseFloatLiteral(mlir::AsmParser &parser,
 // AddressSpaceAttr
 
//===----------------------------------------------------------------------===//
 
-mlir::ParseResult parseAddressSpaceValue(mlir::AsmParser &p,
-                                         cir::AddressSpace &addrSpace);
+mlir::ParseResult
+parseTargetAddressSpace(mlir::AsmParser &p, cir::TargetAddressSpaceAttr &attr);
 
-void printAddressSpaceValue(mlir::AsmPrinter &p, cir::AddressSpace addrSpace);
+void printTargetAddressSpace(mlir::AsmPrinter &p,
+                                    cir::TargetAddressSpaceAttr attr);
 
 static mlir::ParseResult parseConstPtr(mlir::AsmParser &parser,
                                        mlir::IntegerAttr &value);
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp 
b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index b5cec89a51966..b37fb9b0db18c 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -13,6 +13,7 @@
 #include "clang/CIR/Dialect/IR/CIRTypes.h"
 
 #include "mlir/IR/DialectImplementation.h"
+#include "clang/CIR/Dialect/IR/CIRAttrs.h"
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
 #include "clang/CIR/Dialect/IR/CIRTypesDetails.h"
 #include "clang/CIR/MissingFeatures.h"
@@ -54,10 +55,11 @@ static void printFuncTypeParams(mlir::AsmPrinter &p,
 // AddressSpace
 
//===----------------------------------------------------------------------===//
 
-mlir::ParseResult parseAddressSpaceValue(mlir::AsmParser &p,
-                                         cir::AddressSpace &addrSpace);
+mlir::ParseResult parseTargetAddressSpace(mlir::AsmParser &p,
+                                          cir::TargetAddressSpaceAttr &attr);
 
-void printAddressSpaceValue(mlir::AsmPrinter &p, cir::AddressSpace addrSpace);
+void printTargetAddressSpace(mlir::AsmPrinter &p,
+                             cir::TargetAddressSpaceAttr attr);
 
 
//===----------------------------------------------------------------------===//
 // Get autogenerated stuff
@@ -800,91 +802,45 @@ mlir::LogicalResult cir::VectorType::verify(
 }
 
 
//===----------------------------------------------------------------------===//
-// AddressSpace definitions
-//===----------------------------------------------------------------------===//
-
-cir::AddressSpace cir::toCIRAddressSpace(clang::LangAS langAS) {
-  using clang::LangAS;
-  switch (langAS) {
-  case LangAS::Default:
-    return AddressSpace::Default;
-  case LangAS::opencl_global:
-    return AddressSpace::OffloadGlobal;
-  case LangAS::opencl_local:
-  case LangAS::cuda_shared:
-    // Local means local among the work-group (OpenCL) or block (CUDA).
-    // All threads inside the kernel can access local memory.
-    return AddressSpace::OffloadLocal;
-  case LangAS::cuda_device:
-    return AddressSpace::OffloadGlobal;
-  case LangAS::opencl_constant:
-  case LangAS::cuda_constant:
-    return AddressSpace::OffloadConstant;
-  case LangAS::opencl_private:
-    return AddressSpace::OffloadPrivate;
-  case LangAS::opencl_generic:
-    return AddressSpace::OffloadGeneric;
-  case LangAS::opencl_global_device:
-  case LangAS::opencl_global_host:
-  case LangAS::sycl_global:
-  case LangAS::sycl_global_device:
-  case LangAS::sycl_global_host:
-  case LangAS::sycl_local:
-  case LangAS::sycl_private:
-  case LangAS::ptr32_sptr:
-  case LangAS::ptr32_uptr:
-  case LangAS::ptr64:
-  case LangAS::hlsl_groupshared:
-  case LangAS::wasm_funcref:
-    llvm_unreachable("NYI");
-  default:
-    // Target address space offset arithmetics
-    return static_cast<cir::AddressSpace>(clang::toTargetAddressSpace(langAS) +
-                                          cir::getMaxEnumValForAddressSpace());
-  }
+// TargetAddressSpace definitions
+//===----------------------------------------------------------------------===//
+
+// Convert from TargetAddressSpaceAttr to the actual integer address space.
+unsigned cir::getTargetAddrSpaceFromAttr(cir::TargetAddressSpaceAttr attr) {
+  if (!attr)
+    return 0; // Default address space is 0 in LLVM.
+  return attr.getValue().getUInt();
 }
 
-mlir::ParseResult parseAddressSpaceValue(mlir::AsmParser &p,
-                                         cir::AddressSpace &addrSpace) {
-  llvm::SMLoc loc = p.getCurrentLocation();
-  mlir::FailureOr<cir::AddressSpace> result =
-      mlir::FieldParser<cir::AddressSpace>::parse(p);
-  if (mlir::failed(result))
-    return p.emitError(loc, "expected address space keyword");
-
-  // Address space is either a target address space or a language-specific one.
-  // - If it is a target address space, we expect a value to follow in the form
-  // of `<value>`, where value is an integer that represents the target address
-  // space value. This value is kept in the address space enum as an offset
-  // from the maximum address space value, which is defined in
-  // `cir::getMaxEnumValForAddressSpace()`. This allows us to use
-  // the same enum for both language-specific and target address spaces.
-  // - Otherwise, we just use the parsed value.
-  if (cir::isTargetAddressSpace(result.value())) {
-    if (p.parseLess())
-      return p.emitError(loc, "expected '<' after target address space");
-
-    int64_t targetValue;
-    if (p.parseInteger(targetValue) || p.parseGreater())
-      return p.emitError(loc, "expected target address space value");
-
-    addrSpace = cir::computeTargetAddressSpace(targetValue);
-  } else {
-    addrSpace = result.value();
-  }
+mlir::ParseResult parseTargetAddressSpace(mlir::AsmParser &p,
+                                          cir::TargetAddressSpaceAttr &attr) {
+  if (failed(p.parseKeyword("target_address_space")))
+    return mlir::failure();
+
+  if (failed(p.parseLParen()))
+    return mlir::failure();
+
+  int64_t targetValue;
+  if (failed(p.parseInteger(targetValue)))
+    return p.emitError(p.getCurrentLocation(),
+                       "expected integer address space value");
+
+  if (failed(p.parseRParen()))
+    return p.emitError(p.getCurrentLocation(),
+                       "expected ')' after address space value");
 
+  mlir::MLIRContext *context = p.getBuilder().getContext();
+  auto intTy = mlir::IntegerType::get(context, 32);
+  attr = cir::TargetAddressSpaceAttr::get(
+      context, mlir::IntegerAttr::get(intTy, targetValue));
   return mlir::success();
 }
 
-// Prints the address space value in the form of:
-// - `target<value>` for target address spaces
-// - or just the address space name for regular address spaces.
-void printAddressSpaceValue(mlir::AsmPrinter &p, cir::AddressSpace addrSpace) {
-  if (cir::isTargetAddressSpace(addrSpace))
-    p << cir::stringifyEnum(cir::AddressSpace::Target) << '<'
-      << cir::getTargetAddressSpaceValue(addrSpace) << '>';
-  else
-    p << cir::stringifyEnum(addrSpace);
+// The custom printer for the `addrspace` parameter in `!cir.ptr`.
+// in the format of `target_address_space(N)`.
+void printTargetAddressSpace(mlir::AsmPrinter &p,
+                             cir::TargetAddressSpaceAttr attr) {
+  p << "target_address_space(" << attr.getValue().getUInt() << ")";
 }
 
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 2b157856e744f..82521f6567dc3 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -32,6 +32,7 @@
 #include "mlir/Transforms/DialectConversion.h"
 #include "clang/CIR/Dialect/IR/CIRAttrs.h"
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
+#include "clang/CIR/Dialect/IR/CIRTypes.h"
 #include "clang/CIR/Dialect/Passes.h"
 #include "clang/CIR/LoweringHelpers.h"
 #include "clang/CIR/MissingFeatures.h"
@@ -2305,22 +2306,10 @@ mlir::LogicalResult 
CIRToLLVMSelectOpLowering::matchAndRewrite(
   return mlir::success();
 }
 
-static unsigned
-getTargetAddrSpaceFromCIRAddrSpace(cir::AddressSpace addrSpace) {
-  if (addrSpace == cir::AddressSpace::Default)
-    return 0; // Default address space is always 0 in LLVM.
-
-  if (cir::isTargetAddressSpace(addrSpace))
-    return cir::getTargetAddressSpaceValue(addrSpace);
-
-  llvm_unreachable("CIR target lowering is NYI");
-}
-
 static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
                                  mlir::DataLayout &dataLayout) {
   converter.addConversion([&](cir::PointerType type) -> mlir::Type {
-    unsigned addrSpace =
-        getTargetAddrSpaceFromCIRAddrSpace(type.getAddrSpace());
+    unsigned addrSpace = cir::getTargetAddrSpaceFromAttr(type.getAddrSpace());
     return mlir::LLVM::LLVMPointerType::get(type.getContext(), addrSpace);
   });
   converter.addConversion([&](cir::VPtrType type) -> mlir::Type {
diff --git a/clang/test/CIR/CodeGen/address-space.c 
b/clang/test/CIR/CodeGen/address-space.c
index c67640eb5051a..ebb53df7305a6 100644
--- a/clang/test/CIR/CodeGen/address-space.c
+++ b/clang/test/CIR/CodeGen/address-space.c
@@ -6,7 +6,7 @@
 // RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
 
 // Test address space 1
-// CIR: cir.func dso_local {{@.*foo.*}}(%arg0: !cir.ptr<!s32i, 
addrspace(target<1>)>
+// CIR: cir.func dso_local @foo(%arg0: !cir.ptr<!s32i, target_address_space(1)>
 // LLVM: define dso_local void @foo(ptr addrspace(1) %0)
 // OGCG: define dso_local void @foo(ptr addrspace(1) noundef %arg)
 void foo(int __attribute__((address_space(1))) *arg) {
@@ -14,7 +14,7 @@ void foo(int __attribute__((address_space(1))) *arg) {
 }
 
 // Test explicit address space 0 (should be same as default)
-// CIR: cir.func dso_local {{@.*bar.*}}(%arg0: !cir.ptr<!s32i, 
addrspace(target<0>)>
+// CIR: cir.func dso_local @bar(%arg0: !cir.ptr<!s32i, target_address_space(0)>
 // LLVM: define dso_local void @bar(ptr %0)
 // OGCG: define dso_local void @bar(ptr noundef %arg)
 void bar(int __attribute__((address_space(0))) *arg) {
@@ -22,9 +22,9 @@ void bar(int __attribute__((address_space(0))) *arg) {
 }
 
 // Test default address space (no attribute)
-// CIR: cir.func dso_local {{@.*baz.*}}(%arg0: !cir.ptr<!s32i>
+// CIR: cir.func dso_local @baz(%arg0: !cir.ptr<!s32i>
 // LLVM: define dso_local void @baz(ptr %0)
 // OGCG: define dso_local void @baz(ptr noundef %arg)
 void baz(int *arg) {
   return;
-}
+}
\ No newline at end of file
diff --git a/clang/test/CIR/IR/invalid-addrspace.cir 
b/clang/test/CIR/IR/invalid-addrspace.cir
index 369c7c0a45388..8f188b840bdec 100644
--- a/clang/test/CIR/IR/invalid-addrspace.cir
+++ b/clang/test/CIR/IR/invalid-addrspace.cir
@@ -3,34 +3,25 @@
 // -----
 
 !u64i = !cir.int<u, 64>
-// expected-error@below {{expected address space keyword}}
-// expected-error@below {{expected keyword for address space kind}}
-cir.func @address_space1(%p : !cir.ptr<!u64i, addrspace()>) {
+// expected-error @below {{expected 'target_address_space'}}
+cir.func @address_space1(%p : !cir.ptr<!u64i, foobar>) {
   cir.return
 }
 
 // -----
 
 !u64i = !cir.int<u, 64>
-// expected-error@below {{expected target address space value}}
-// expected-error@below {{expected integer value}}
-cir.func @address_space2(%p : !cir.ptr<!u64i, addrspace(target<>)>) {
+// expected-error@below {{expected '('}}
+cir.func @address_space2(%p : !cir.ptr<!u64i, target_address_space>) {
   cir.return
 }
 
 // -----
 
 !u64i = !cir.int<u, 64>
-// expected-error@below {{expected '<'}}
-cir.func @address_space3(%p : !cir.ptr<!u64i, addrspace(target)>) {
+// expected-error@+2 {{expected integer value}}
+// expected-error@below {{expected integer address space value}}
+cir.func @address_space3(%p : !cir.ptr<!u64i, target_address_space()>) {
   cir.return
 }
 
-// -----
-
-!u64i = !cir.int<u, 64>
-// expected-error@below {{expected one of [default, offload_private, 
offload_local, offload_global, offload_constant, offload_generic, target] for 
address space kind, got: foobar}}
-// expected-error@below {{expected address space keyword}}
-cir.func @address_space4(%p : !cir.ptr<!u64i, addrspace(foobar)>) {
-  cir.return
-}

>From b5180ef0c6b9a9cb242773c464cc293e90c02572 Mon Sep 17 00:00:00 2001
From: David Rivera <davidriv...@gmail.com>
Date: Wed, 1 Oct 2025 17:06:43 -0400
Subject: [PATCH 5/6] fix formatting once again.

---
 clang/lib/CIR/Dialect/IR/CIRAttrs.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp 
b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
index 5ba05a04a56b1..3484c59df4ece 100644
--- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -47,11 +47,11 @@ parseFloatLiteral(mlir::AsmParser &parser,
 // AddressSpaceAttr
 
//===----------------------------------------------------------------------===//
 
-mlir::ParseResult
-parseTargetAddressSpace(mlir::AsmParser &p, cir::TargetAddressSpaceAttr &attr);
+mlir::ParseResult parseTargetAddressSpace(mlir::AsmParser &p,
+                                          cir::TargetAddressSpaceAttr &attr);
 
 void printTargetAddressSpace(mlir::AsmPrinter &p,
-                                    cir::TargetAddressSpaceAttr attr);
+                             cir::TargetAddressSpaceAttr attr);
 
 static mlir::ParseResult parseConstPtr(mlir::AsmParser &parser,
                                        mlir::IntegerAttr &value);

>From 6cf211b2276ee99b26cd34149d6be51bdb247c9c Mon Sep 17 00:00:00 2001
From: David Rivera <davidriv...@gmail.com>
Date: Thu, 2 Oct 2025 08:27:17 -0400
Subject: [PATCH 6/6] Apply 2nd round of suggestions

---
 clang/include/clang/CIR/Dialect/IR/CIRAttrs.td      | 9 +++++++--
 clang/include/clang/CIR/Dialect/IR/CIRTypes.h       | 7 -------
 clang/include/clang/CIR/Dialect/IR/CIRTypes.td      | 7 +------
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp                | 2 +-
 clang/lib/CIR/CodeGen/CIRGenModule.cpp              | 2 +-
 clang/lib/CIR/CodeGen/CIRGenTypeCache.h             | 6 ++++--
 clang/lib/CIR/CodeGen/TargetInfo.h                  | 8 ++++++--
 clang/lib/CIR/Dialect/IR/CIRTypes.cpp               | 7 -------
 clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 3 ++-
 clang/test/CIR/CodeGen/address-space.c              | 2 +-
 10 files changed, 23 insertions(+), 30 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td 
b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 6a0a2bde7368a..7714750a53d44 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -607,9 +607,14 @@ def CIR_VTableAttr : CIR_Attr<"VTable", "vtable", 
[TypedAttrInterface]> {
 
 def CIR_TargetAddressSpaceAttr : CIR_Attr< "TargetAddressSpace",
                                          "target_address_space"> {
-  let summary = "Attribute representing a target-specific numeric address 
space";
+  let summary = "Represents a target-specific numeric address space";
   let description = [{
-    Represents a target-specific numeric address space for pointer types.
+    The TargetAddressSpaceAttr represents a target-specific numeric address 
space,
+    corresponding to the LLVM IR `addressspace` qualifier and the clang
+     `address_space` attribute.
+    
+    A value of zero represents the default address space. The semantics of 
non-zero
+    address spaces are target-specific.
 
     Example:
     ```mlir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h 
b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
index c1a063875f480..45f646f1c9dfa 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
@@ -38,13 +38,6 @@ bool isValidFundamentalIntWidth(unsigned width);
 /// void, or abstract types.
 bool isSized(mlir::Type ty);
 
-//===----------------------------------------------------------------------===//
-// AddressSpace helpers
-//===----------------------------------------------------------------------===//
-
-/// Returns the integer value of a CIR address space for LLVM.
-unsigned getTargetAddrSpaceFromAttr(cir::TargetAddressSpaceAttr attr);
-
 } // namespace cir
 
 
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td 
b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index e2f64f84d266f..313184764f536 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -238,10 +238,6 @@ def CIR_PointerType : CIR_Type<"Pointer", "ptr", [
     records, arrays, vectors, functions, and other pointers. It can also point
     to incomplete types, such as incomplete records.
 
-    Note: Data-member pointers and method pointers are represented by
-    `!cir.data_member` and `!cir.method` types, respectively not by
-    `!cir.ptr` type.
-
     Examples:
 
     ```mlir
@@ -256,8 +252,7 @@ def CIR_PointerType : CIR_Type<"Pointer", "ptr", [
   let parameters = (ins
     "mlir::Type":$pointee,
     OptionalParameter<
-    "cir::TargetAddressSpaceAttr"
-    >:$addrSpace
+        "cir::TargetAddressSpaceAttr">:$addrSpace
   );
 
   let skipDefaultBuilders = 1;
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 16cfc96022497..158f1617a46db 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -2053,7 +2053,7 @@ mlir::Value CIRGenFunction::emitAlloca(StringRef name, 
mlir::Type ty,
   // layout like original CodeGen. The data layout awareness should be done in
   // the lowering pass instead.
   cir::PointerType localVarPtrTy =
-      builder.getPointerTo(ty, getASTAllocaAddressSpace());
+      builder.getPointerTo(ty, getCIRAllocaAddressSpace());
   mlir::IntegerAttr alignIntAttr = cgm.getSize(alignment);
 
   mlir::Value addr;
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp 
b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index fc26d1f2e1f63..dc615316dd634 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -76,7 +76,7 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext,
   SInt128Ty = cir::IntType::get(&getMLIRContext(), 128, /*isSigned=*/true);
   UInt8Ty = cir::IntType::get(&getMLIRContext(), 8, /*isSigned=*/false);
   UInt8PtrTy = cir::PointerType::get(UInt8Ty);
-  ASTAllocaAddressSpace = getTargetCIRGenInfo().getASTAllocaAddressSpace();
+  cirAllocaAddressSpace = getTargetCIRGenInfo().getCIRAllocaAddressSpace();
   UInt16Ty = cir::IntType::get(&getMLIRContext(), 16, /*isSigned=*/false);
   UInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/false);
   UInt64Ty = cir::IntType::get(&getMLIRContext(), 64, /*isSigned=*/false);
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h 
b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
index 3e261c4b82fb4..273ec7f06b4b5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
+++ b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
@@ -74,7 +74,7 @@ struct CIRGenTypeCache {
   /// The alignment of size_t.
   unsigned char SizeAlignInBytes;
 
-  LangAS ASTAllocaAddressSpace;
+  cir::TargetAddressSpaceAttr cirAllocaAddressSpace;
 
   clang::CharUnits getSizeAlign() const {
     return clang::CharUnits::fromQuantity(SizeAlignInBytes);
@@ -84,7 +84,9 @@ struct CIRGenTypeCache {
     return clang::CharUnits::fromQuantity(PointerAlignInBytes);
   }
 
-  LangAS getASTAllocaAddressSpace() const { return ASTAllocaAddressSpace; }
+  cir::TargetAddressSpaceAttr getCIRAllocaAddressSpace() const {
+    return cirAllocaAddressSpace;
+  }
 };
 
 } // namespace clang::CIRGen
diff --git a/clang/lib/CIR/CodeGen/TargetInfo.h 
b/clang/lib/CIR/CodeGen/TargetInfo.h
index b23b0581b5c14..91a5531208bbe 100644
--- a/clang/lib/CIR/CodeGen/TargetInfo.h
+++ b/clang/lib/CIR/CodeGen/TargetInfo.h
@@ -16,6 +16,8 @@
 
 #include "ABIInfo.h"
 #include "CIRGenTypes.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/IR/BuiltinTypes.h"
 #include "clang/Basic/AddressSpaces.h"
 
 #include <memory>
@@ -44,8 +46,10 @@ class TargetCIRGenInfo {
   /// Returns ABI info helper for the target.
   const ABIInfo &getABIInfo() const { return *info; }
 
-  /// Get the AST address space for alloca.
-  virtual LangAS getASTAllocaAddressSpace() const { return LangAS::Default; }
+  /// Get the address space for alloca.
+  virtual cir::TargetAddressSpaceAttr getCIRAllocaAddressSpace() const {
+    return nullptr;
+  }
 
   /// Determine whether a call to an unprototyped functions under
   /// the given calling convention should use the variadic
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp 
b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index b37fb9b0db18c..070ce41403857 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -805,13 +805,6 @@ mlir::LogicalResult cir::VectorType::verify(
 // TargetAddressSpace definitions
 
//===----------------------------------------------------------------------===//
 
-// Convert from TargetAddressSpaceAttr to the actual integer address space.
-unsigned cir::getTargetAddrSpaceFromAttr(cir::TargetAddressSpaceAttr attr) {
-  if (!attr)
-    return 0; // Default address space is 0 in LLVM.
-  return attr.getValue().getUInt();
-}
-
 mlir::ParseResult parseTargetAddressSpace(mlir::AsmParser &p,
                                           cir::TargetAddressSpaceAttr &attr) {
   if (failed(p.parseKeyword("target_address_space")))
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 82521f6567dc3..0aa18c8c017bc 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2309,7 +2309,8 @@ mlir::LogicalResult 
CIRToLLVMSelectOpLowering::matchAndRewrite(
 static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
                                  mlir::DataLayout &dataLayout) {
   converter.addConversion([&](cir::PointerType type) -> mlir::Type {
-    unsigned addrSpace = cir::getTargetAddrSpaceFromAttr(type.getAddrSpace());
+    unsigned addrSpace =
+        type.getAddrSpace() ? type.getAddrSpace().getValue().getUInt() : 0;
     return mlir::LLVM::LLVMPointerType::get(type.getContext(), addrSpace);
   });
   converter.addConversion([&](cir::VPtrType type) -> mlir::Type {
diff --git a/clang/test/CIR/CodeGen/address-space.c 
b/clang/test/CIR/CodeGen/address-space.c
index ebb53df7305a6..a334b8a2907e4 100644
--- a/clang/test/CIR/CodeGen/address-space.c
+++ b/clang/test/CIR/CodeGen/address-space.c
@@ -27,4 +27,4 @@ void bar(int __attribute__((address_space(0))) *arg) {
 // OGCG: define dso_local void @baz(ptr noundef %arg)
 void baz(int *arg) {
   return;
-}
\ No newline at end of file
+}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to