Author: Konstantinos Parasyris
Date: 2026-10-05T22:58:17Z
New Revision: 546e4f93c36bb8e9e383cac71972c293e0f08998

URL: 
https://github.com/llvm/llvm-project/commit/546e4f93c36bb8e9e383cac71972c293e0f08998
DIFF: 
https://github.com/llvm/llvm-project/commit/546e4f93c36bb8e9e383cac71972c293e0f08998.diff

LOG: [CIR] Lower language address spaces nested in record members (#228934)

TargetLowering now derives from RecordRewritingTypeConverter, so it
rebuilds records whose members reach a language address space and keeps
the rest. This fixes "member type mismatch" for OpenCL and SYCL records
with address-space qualified pointer members.

Added: 
    clang/test/CIR/CodeGenOpenCL/record-address-space.cl
    clang/test/CIR/CodeGenSYCL/record-address-space.cpp

Modified: 
    clang/lib/CIR/Dialect/Transforms/RecordTypeConverter.cpp
    clang/lib/CIR/Dialect/Transforms/RecordTypeConverter.h
    clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CIR/Dialect/Transforms/RecordTypeConverter.cpp 
b/clang/lib/CIR/Dialect/Transforms/RecordTypeConverter.cpp
index 52c355c340519..8f14bada8957c 100644
--- a/clang/lib/CIR/Dialect/Transforms/RecordTypeConverter.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/RecordTypeConverter.cpp
@@ -108,8 +108,58 @@ 
RecordRewritingTypeConverter::convertRecordMemberTypes(cir::RecordType type) {
   return loweredMemberTypes;
 }
 
+bool RecordRewritingTypeConverter::reachesChangingType(
+    mlir::Type type, llvm::SmallPtrSetImpl<mlir::Type> &visiting) const {
+  if (typeMayChange(type))
+    return true;
+
+  // The sub-element walk skips record members. Stop on cycles.
+  if (auto rt = mlir::dyn_cast<cir::RecordType>(type)) {
+    if (!visiting.insert(type).second)
+      return false;
+    for (mlir::Type member : rt.getMembers())
+      if (reachesChangingType(member, visiting))
+        return true;
+    if (auto u = mlir::dyn_cast<cir::UnionType>(type))
+      if (mlir::Type pad = u.getPadding())
+        return reachesChangingType(pad, visiting);
+    return false;
+  }
+
+  bool found = false;
+  type.walkImmediateSubElements([](mlir::Attribute) {},
+                                [&](mlir::Type sub) {
+                                  found = found ||
+                                          reachesChangingType(sub, visiting);
+                                });
+  return found;
+}
+
+bool RecordRewritingTypeConverter::recordNeedsConversion(cir::RecordType type) 
{
+  {
+    std::shared_lock<decltype(recordNeedsConversionMutex)> lock(
+        recordNeedsConversionMutex);
+    auto it = recordNeedsConversionCache.find(type);
+    if (it != recordNeedsConversionCache.end())
+      return it->second;
+  }
+
+  // Nested results may be partial inside a cycle, so cache only this one.
+  llvm::SmallPtrSet<mlir::Type, 8> visiting;
+  bool result = reachesChangingType(type, visiting);
+
+  std::unique_lock<decltype(recordNeedsConversionMutex)> lock(
+      recordNeedsConversionMutex);
+  recordNeedsConversionCache[type] = result;
+  return result;
+}
+
 cir::RecordType
 RecordRewritingTypeConverter::convertRecordType(cir::RecordType type) {
+  // Keep records that reach no changing type, including through nested ones.
+  if (!recordNeedsConversion(type))
+    return type;
+
   // Unnamed record types can't be referred to recursively, so we can just
   // convert this one. It also doesn't have uniqueness problems, so we can
   // just do a conversion on it.

diff  --git a/clang/lib/CIR/Dialect/Transforms/RecordTypeConverter.h 
b/clang/lib/CIR/Dialect/Transforms/RecordTypeConverter.h
index 1b7b1fbc1ad34..569a96a604e33 100644
--- a/clang/lib/CIR/Dialect/Transforms/RecordTypeConverter.h
+++ b/clang/lib/CIR/Dialect/Transforms/RecordTypeConverter.h
@@ -17,6 +17,7 @@
 #include "mlir/Transforms/DialectConversion.h"
 #include "clang/CIR/Dialect/IR/CIRTypes.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/RWMutex.h"
 
@@ -36,6 +37,8 @@ namespace cir {
 /// Subclasses add conversions for the types they rewrite. The type converter
 /// tries the most recently added conversion first, so a subclass can also
 /// replace one of the conversions registered here.
+///
+/// Every record is rebuilt unless typeMayChange() is overridden.
 class RecordRewritingTypeConverter : public mlir::TypeConverter {
 public:
   explicit RecordRewritingTypeConverter(mlir::MLIRContext &context);
@@ -44,7 +47,15 @@ class RecordRewritingTypeConverter : public 
mlir::TypeConverter {
   /// Remove the temporary name of every record rebuilt by this converter.
   void restoreRecordTypeNames();
 
+protected:
+  /// Whether \p type itself, ignoring nested types, may change. Records are
+  /// rebuilt only if some type they reach returns true.
+  virtual bool typeMayChange(mlir::Type type) const { return true; }
+
 private:
+  bool recordNeedsConversion(cir::RecordType type);
+  bool reachesChangingType(mlir::Type type,
+                           llvm::SmallPtrSetImpl<mlir::Type> &visiting) const;
   cir::RecordType convertRecordType(cir::RecordType type);
   llvm::SmallVector<mlir::Type> convertRecordMemberTypes(cir::RecordType type);
   llvm::SmallVector<cir::RecordType> &getCurrentThreadRecursiveStack();
@@ -64,6 +75,10 @@ class RecordRewritingTypeConverter : public 
mlir::TypeConverter {
   // functions.
   llvm::SmallVector<cir::RecordType> convertedRecordTypes;
   llvm::sys::SmartRWMutex<true> recordTypeMutex;
+
+  // Cached results of recordNeedsConversion().
+  llvm::DenseMap<mlir::Type, bool> recordNeedsConversionCache;
+  llvm::sys::SmartRWMutex<true> recordNeedsConversionMutex;
 };
 
 } // namespace cir

diff  --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp 
b/clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp
index 769df5572f285..76ca7114ee5ce 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering.cpp
@@ -10,9 +10,11 @@
 //
 
//===----------------------------------------------------------------------===//
 
+#include "RecordTypeConverter.h"
 #include "TargetLowering/LowerModule.h"
 #include "TargetLowering/TargetLoweringInfo.h"
 
+#include "mlir/IR/AttrTypeSubElements.h"
 #include "mlir/IR/PatternMatch.h"
 #include "mlir/Support/LLVM.h"
 #include "mlir/Transforms/DialectConversion.h"
@@ -38,13 +40,72 @@ struct TargetLoweringPass
   void runOnOperation() override;
 };
 
+/// Converts LangAddressSpaceAttr → TargetAddressSpaceAttr inside types,
+/// rebuilding only records that reach a language address space.
+class TargetLoweringTypeConverter : public cir::RecordRewritingTypeConverter {
+public:
+  TargetLoweringTypeConverter(mlir::MLIRContext &ctx,
+                              const cir::TargetLoweringInfo &targetInfo)
+      : RecordRewritingTypeConverter(ctx), targetInfo(targetInfo) {
+    addConversion([this](cir::PointerType type) -> mlir::Type {
+      mlir::Type pointee = convertType(type.getPointee());
+      if (!pointee)
+        return {};
+      mlir::ptr::MemorySpaceAttrInterface addrSpace = type.getAddrSpace();
+      if (auto langAS =
+              mlir::dyn_cast_if_present<cir::LangAddressSpaceAttr>(addrSpace))
+        addrSpace = lowerAddrSpace(type.getContext(), langAS);
+      return cir::PointerType::get(type.getContext(), pointee, addrSpace);
+    });
+  }
+
+  mlir::ptr::MemorySpaceAttrInterface
+  lowerAddrSpace(mlir::MLIRContext *ctx,
+                 cir::LangAddressSpaceAttr langAS) const {
+    unsigned targetAS =
+        targetInfo.getTargetAddrSpaceFromCIRAddrSpace(langAS.getValue());
+    if (targetAS == 0)
+      return {};
+    return cir::TargetAddressSpaceAttr::get(ctx, targetAS);
+  }
+
+  /// Convert the types nested in \p attr, e.g. the type of a constant.
+  mlir::Attribute convertAttr(mlir::Attribute attr) const {
+    return attrReplacer.replace(attr);
+  }
+
+protected:
+  bool typeMayChange(mlir::Type type) const override {
+    auto ptrTy = mlir::dyn_cast<cir::PointerType>(type);
+    return ptrTy && mlir::isa_and_present<cir::LangAddressSpaceAttr>(
+                        ptrTy.getAddrSpace());
+  }
+
+private:
+  const cir::TargetLoweringInfo &targetInfo;
+  mutable mlir::AttrTypeReplacer attrReplacer = [this] {
+    mlir::AttrTypeReplacer replacer;
+    replacer.addReplacement(
+        [this](mlir::Type type)
+            -> std::optional<std::pair<mlir::Type, mlir::WalkResult>> {
+          mlir::Type converted = convertType(type);
+          if (!converted)
+            return std::nullopt;
+          // Already converted; don't walk into it.
+          return std::make_pair(converted, mlir::WalkResult::skip());
+        });
+    return replacer;
+  }();
+};
+
 /// A generic target lowering pattern that matches any CIR op whose operand or
 /// result types need address space conversion. Clones the op with converted
 /// types.
 class CIRGenericTargetLoweringPattern : public mlir::ConversionPattern {
 public:
-  CIRGenericTargetLoweringPattern(mlir::MLIRContext *context,
-                                  const mlir::TypeConverter &typeConverter)
+  CIRGenericTargetLoweringPattern(
+      mlir::MLIRContext *context,
+      const TargetLoweringTypeConverter &typeConverter)
       : mlir::ConversionPattern(typeConverter, MatchAnyOpTypeTag(),
                                 /*benefit=*/1, context) {}
 
@@ -73,9 +134,7 @@ class CIRGenericTargetLoweringPattern : public 
mlir::ConversionPattern {
     mlir::OperationState loweredOpState(op->getLoc(), op->getName());
     loweredOpState.addOperands(operands);
 
-    // Preserve auxiliary metadata verbatim. Convert only inherent TypeAttrs 
and
-    // pointer constants so address-space-bearing operation semantics (e.g.
-    // AllocaOp's allocaType) stay in sync with the converted result types.
+    // Preserve auxiliary metadata verbatim.
     loweredOpState.propertiesAttr = op->getPropertiesAsAttribute();
     
loweredOpState.addAttributes(op->getDiscardableAttrDictionary().getValue());
 
@@ -96,15 +155,13 @@ class CIRGenericTargetLoweringPattern : public 
mlir::ConversionPattern {
     }
 
     mlir::Operation *loweredOp = rewriter.create(loweredOpState);
+    // Keep inherent attributes (e.g. allocaType, constants) in sync with the
+    // converted types.
+    const auto *tlTypeConverter =
+        static_cast<const TargetLoweringTypeConverter *>(typeConverter);
     loweredOp->getName().walkInherentAttrs(
         loweredOp, [&](llvm::StringRef, mlir::Attribute &attr) {
-          if (auto typeAttr = mlir::dyn_cast<mlir::TypeAttr>(attr))
-            attr = mlir::TypeAttr::get(
-                typeConverter->convertType(typeAttr.getValue()));
-          else if (auto ptrAttr = mlir::dyn_cast<cir::ConstPtrAttr>(attr))
-            attr = cir::ConstPtrAttr::get(
-                typeConverter->convertType(ptrAttr.getType()),
-                ptrAttr.getValue());
+          attr = tlTypeConverter->convertAttr(attr);
         });
     rewriter.replaceOp(op, loweredOp);
     return mlir::success();
@@ -116,34 +173,26 @@ class CIRGenericTargetLoweringPattern : public 
mlir::ConversionPattern {
 /// TypeConverter won't reach it automatically.
 class CIRGlobalOpTargetLowering
     : public mlir::OpConversionPattern<cir::GlobalOp> {
-  const cir::TargetLoweringInfo &targetInfo;
-
 public:
   CIRGlobalOpTargetLowering(mlir::MLIRContext *context,
-                            const mlir::TypeConverter &typeConverter,
-                            const cir::TargetLoweringInfo &targetInfo)
+                            const TargetLoweringTypeConverter &typeConverter)
       : mlir::OpConversionPattern<cir::GlobalOp>(typeConverter, context,
-                                                 /*benefit=*/1),
-        targetInfo(targetInfo) {}
+                                                 /*benefit=*/1) {}
 
   mlir::LogicalResult
   matchAndRewrite(cir::GlobalOp op, OpAdaptor adaptor,
                   mlir::ConversionPatternRewriter &rewriter) const override {
-    mlir::Type loweredSymTy = getTypeConverter()->convertType(op.getSymType());
+    const auto *typeConverter =
+        static_cast<const TargetLoweringTypeConverter *>(getTypeConverter());
+    mlir::Type loweredSymTy = typeConverter->convertType(op.getSymType());
     if (!loweredSymTy)
       return mlir::failure();
 
     // Convert the addr_space attribute.
     mlir::ptr::MemorySpaceAttrInterface addrSpace = op.getAddrSpaceAttr();
     if (auto langAS =
-            mlir::dyn_cast_if_present<cir::LangAddressSpaceAttr>(addrSpace)) {
-      unsigned targetAS =
-          targetInfo.getTargetAddrSpaceFromCIRAddrSpace(langAS.getValue());
-      addrSpace =
-          targetAS == 0
-              ? nullptr
-              : cir::TargetAddressSpaceAttr::get(op.getContext(), targetAS);
-    }
+            mlir::dyn_cast_if_present<cir::LangAddressSpaceAttr>(addrSpace))
+      addrSpace = typeConverter->lowerAddrSpace(op.getContext(), langAS);
 
     // Only rewrite if something actually changed.
     if (loweredSymTy == op.getSymType() && addrSpace == op.getAddrSpaceAttr())
@@ -152,6 +201,8 @@ class CIRGlobalOpTargetLowering
     auto newOp = mlir::cast<cir::GlobalOp>(rewriter.clone(*op.getOperation()));
     newOp.setSymType(loweredSymTy);
     newOp.setAddrSpaceAttr(addrSpace);
+    if (mlir::Attribute init = newOp.getInitialValueAttr())
+      newOp.setInitialValueAttr(typeConverter->convertAttr(init));
     rewriter.replaceOp(op, newOp);
     return mlir::success();
   }
@@ -218,55 +269,6 @@ static void convertSyncScopeIfPresent(mlir::Operation *op,
   }
 }
 
-/// Prepare the type converter for the target lowering pass.
-/// Converts LangAddressSpaceAttr → TargetAddressSpaceAttr inside pointer 
types.
-static void
-prepareTargetLoweringTypeConverter(mlir::TypeConverter &converter,
-                                   const cir::TargetLoweringInfo &targetInfo) {
-  converter.addConversion([](mlir::Type type) { return type; });
-
-  converter.addConversion([&converter,
-                           &targetInfo](cir::PointerType type) -> mlir::Type {
-    mlir::Type pointee = converter.convertType(type.getPointee());
-    if (!pointee)
-      return {};
-    auto addrSpace = type.getAddrSpace();
-    if (auto langAS =
-            mlir::dyn_cast_if_present<cir::LangAddressSpaceAttr>(addrSpace)) {
-      unsigned targetAS =
-          targetInfo.getTargetAddrSpaceFromCIRAddrSpace(langAS.getValue());
-      addrSpace =
-          targetAS == 0
-              ? nullptr
-              : cir::TargetAddressSpaceAttr::get(type.getContext(), targetAS);
-    }
-    return cir::PointerType::get(type.getContext(), pointee, addrSpace);
-  });
-
-  converter.addConversion([&converter](cir::ArrayType type) -> mlir::Type {
-    mlir::Type loweredElementType =
-        converter.convertType(type.getElementType());
-    if (!loweredElementType)
-      return {};
-    return cir::ArrayType::get(loweredElementType, type.getSize());
-  });
-
-  converter.addConversion([&converter](cir::FuncType type) -> mlir::Type {
-    llvm::SmallVector<mlir::Type> loweredInputTypes;
-    loweredInputTypes.reserve(type.getNumInputs());
-    if (mlir::failed(
-            converter.convertTypes(type.getInputs(), loweredInputTypes)))
-      return {};
-
-    mlir::Type loweredReturnType = converter.convertType(type.getReturnType());
-    if (!loweredReturnType)
-      return {};
-
-    return cir::FuncType::get(loweredInputTypes, loweredReturnType,
-                              /*isVarArg=*/type.getVarArg());
-  });
-}
-
 static void
 populateTargetLoweringConversionTarget(mlir::ConversionTarget &target,
                                        const mlir::TypeConverter &tc) {
@@ -311,12 +313,10 @@ void TargetLoweringPass::runOnOperation() {
   });
 
   // Address space conversion: LangAddressSpaceAttr → TargetAddressSpaceAttr.
-  mlir::TypeConverter typeConverter;
-  prepareTargetLoweringTypeConverter(typeConverter, targetInfo);
+  TargetLoweringTypeConverter typeConverter(*mod.getContext(), targetInfo);
 
   mlir::RewritePatternSet patterns(mod.getContext());
-  patterns.add<CIRGlobalOpTargetLowering>(mod.getContext(), typeConverter,
-                                          targetInfo);
+  patterns.add<CIRGlobalOpTargetLowering>(mod.getContext(), typeConverter);
   patterns.add<CIRFuncOpTargetLowering>(typeConverter, mod.getContext());
   patterns.add<CIRGenericTargetLoweringPattern>(mod.getContext(),
                                                 typeConverter);
@@ -330,6 +330,8 @@ void TargetLoweringPass::runOnOperation() {
 
   if (failed(mlir::applyPartialConversion(ops, target, std::move(patterns))))
     signalPassFailure();
+
+  typeConverter.restoreRecordTypeNames();
 }
 
 std::unique_ptr<Pass> mlir::createTargetLoweringPass() {

diff  --git a/clang/test/CIR/CodeGenOpenCL/record-address-space.cl 
b/clang/test/CIR/CodeGenOpenCL/record-address-space.cl
new file mode 100644
index 0000000000000..8ce869a47a3b1
--- /dev/null
+++ b/clang/test/CIR/CodeGenOpenCL/record-address-space.cl
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 -triple spirv64-unknown-unknown -cl-std=CL2.0 -fclangir \
+// RUN:   -emit-cir -mmlir --mlir-print-ir-before=cir-target-lowering %s \
+// RUN:   -o %t.cir 2> %t.pre.cir
+// RUN: FileCheck %s --check-prefix=PRE --input-file=%t.pre.cir
+// RUN: FileCheck %s --check-prefix=POST --input-file=%t.cir
+// RUN: %clang_cc1 -triple spirv64-unknown-unknown -cl-std=CL2.0 -fclangir \
+// RUN:   -emit-llvm -O0 %s -o %t-cir.ll
+// RUN: FileCheck %s --check-prefixes=LLVM,CIR-LLVM --input-file=%t-cir.ll
+// RUN: %clang_cc1 -triple spirv64-unknown-unknown -cl-std=CL2.0 \
+// RUN:   -emit-llvm -O0 %s -o %t.ll
+// RUN: FileCheck %s --check-prefixes=LLVM,OGCG --input-file=%t.ll
+
+// Language address spaces in record members are lowered; other records are
+// kept.
+
+struct S { __global int *p; int n; };
+struct Outer { struct S s; __local int *lp; };
+struct Node { __global struct Node *next; int v; };
+union U { __global int *p; long l; };
+struct Plain { int a; float b; };
+
+// PRE-DAG: !rec_S = !cir.struct<"S" {data !cir.ptr<!s32i, 
lang_address_space(offload_global)>, data !s32i}>
+// PRE-DAG: !rec_Outer = !cir.struct<"Outer" {data !rec_S, data 
!cir.ptr<!s32i, lang_address_space(offload_local)>}>
+// PRE-DAG: !rec_Node = !cir.struct<"Node" {data !cir.ptr<!cir.struct<"Node">, 
lang_address_space(offload_global)>, data !s32i}>
+// PRE-DAG: !rec_U = !cir.union<"U" {data !cir.ptr<!s32i, 
lang_address_space(offload_global)>, data !s64i}>
+// PRE-DAG: !rec_Plain = !cir.struct<"Plain" {data !s32i, data !cir.float}>
+
+// POST-DAG: !rec_S = !cir.struct<"S" {data !cir.ptr<!s32i, 
target_address_space(1)>, data !s32i}>
+// POST-DAG: !rec_Outer = !cir.struct<"Outer" {data !rec_S, data 
!cir.ptr<!s32i, target_address_space(3)>}>
+// POST-DAG: !rec_Node = !cir.struct<"Node" {data 
!cir.ptr<!cir.struct<"Node">, target_address_space(1)>, data !s32i}>
+// POST-DAG: !rec_U = !cir.union<"U" {data !cir.ptr<!s32i, 
target_address_space(1)>, data !s64i}>
+// POST-DAG: !rec_Plain = !cir.struct<"Plain" {data !s32i, data !cir.float}>
+
+// LLVM-DAG: %struct.S = type { ptr addrspace(1), i32 }
+// LLVM-DAG: %struct.Outer = type { %struct.S, ptr addrspace(3) }
+// LLVM-DAG: %struct.Node = type { ptr addrspace(1), i32 }
+// LLVM-DAG: %union.U = type { ptr addrspace(1) }
+// LLVM-DAG: %struct.Plain = type { i32, float }
+
+__global int gi;
+__global struct S gs = {&gi, 4};
+
+// The initializer type follows the record.
+
+// POST: cir.global external target_address_space(1) @gs = 
#cir.const_record<{#cir.global_view<@gi> : !cir.ptr<!s32i, 
target_address_space(1)>, #cir.int<4> : !s32i}> : !rec_S
+
+// CIR-LLVM: @gs = addrspace(1) global %struct.S { ptr addrspace(1) @gi, i32 4 
}, align 8
+// OGCG: @gs = addrspace(1) global { ptr addrspace(1), i32, [4 x i8] } { ptr 
addrspace(1) @gi, i32 4, [4 x i8] zeroinitializer }, align 8
+
+kernel void k(__global int *g, __local int *l, __global struct Node *n) {
+  struct S s;
+  s.p = g;
+  struct Outer o;
+  o.lp = l;
+  struct Node node;
+  node.next = n;
+  union U u;
+  u.p = g;
+  struct Plain plain;
+  plain.a = 1;
+}
+
+// POST: cir.get_member %{{.*}}[0] {name = "p"} : !cir.ptr<!rec_S> -> 
!cir.ptr<!cir.ptr<!s32i, target_address_space(1)>>
+// POST: cir.get_member %{{.*}}[1] {name = "lp"} : !cir.ptr<!rec_Outer> -> 
!cir.ptr<!cir.ptr<!s32i, target_address_space(3)>>
+// POST: cir.get_member %{{.*}}[0] {name = "next"} : !cir.ptr<!rec_Node> -> 
!cir.ptr<!cir.ptr<!rec_Node, target_address_space(1)>>
+// POST: cir.get_member %{{.*}}[0] {name = "p"} : !cir.ptr<!rec_U> -> 
!cir.ptr<!cir.ptr<!s32i, target_address_space(1)>>
+// POST: cir.get_member %{{.*}}[0] {name = "a"} : !cir.ptr<!rec_Plain> -> 
!cir.ptr<!s32i>
+
+// LLVM: %[[P:.*]] = getelementptr inbounds nuw %struct.S, ptr %{{.*}}, i32 0, 
i32 0
+// LLVM: store ptr addrspace(1) %{{.*}}, ptr %[[P]], align 8
+// LLVM: %[[LP:.*]] = getelementptr inbounds nuw %struct.Outer, ptr %{{.*}}, 
i32 0, i32 1
+// LLVM: store ptr addrspace(3) %{{.*}}, ptr %[[LP]], align 8
+// LLVM: %[[NEXT:.*]] = getelementptr inbounds nuw %struct.Node, ptr %{{.*}}, 
i32 0, i32 0
+// LLVM: store ptr addrspace(1) %{{.*}}, ptr %[[NEXT]], align 8
+// LLVM: store ptr addrspace(1) %{{.*}}, ptr %{{.*}}, align 8
+// LLVM: %[[A:.*]] = getelementptr inbounds nuw %struct.Plain, ptr %{{.*}}, 
i32 0, i32 0
+// LLVM: store i32 1, ptr %[[A]], align 4

diff  --git a/clang/test/CIR/CodeGenSYCL/record-address-space.cpp 
b/clang/test/CIR/CodeGenSYCL/record-address-space.cpp
new file mode 100644
index 0000000000000..292aab806d942
--- /dev/null
+++ b/clang/test/CIR/CodeGenSYCL/record-address-space.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -std=c++20 -fsycl-is-device -triple spirv64-unknown-unknown 
\
+// RUN:   -fclangir -emit-cir -mmlir 
--mlir-print-ir-before=cir-target-lowering \
+// RUN:   %s -o %t.cir 2> %t.pre.cir
+// RUN: FileCheck %s --check-prefix=PRE --input-file=%t.pre.cir
+// RUN: FileCheck %s --check-prefix=POST --input-file=%t.cir
+// RUN: %clang_cc1 -std=c++20 -fsycl-is-device -triple spirv64-unknown-unknown 
\
+// RUN:   -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck %s --check-prefix=LLVM --input-file=%t-cir.ll
+// RUN: %clang_cc1 -std=c++20 -fsycl-is-device -triple spirv64-unknown-unknown 
\
+// RUN:   -emit-llvm %s -o %t.ll
+// RUN: FileCheck %s --check-prefix=LLVM --input-file=%t.ll
+
+// Language address spaces in record members are lowered.
+
+struct S {
+  __attribute__((opencl_global)) int *p;
+  int n;
+};
+
+// PRE: !rec_S = !cir.struct<"S" {data !cir.ptr<!s32i, 
lang_address_space(offload_global)>, data !s32i}>
+// POST: !rec_S = !cir.struct<"S" {data !cir.ptr<!s32i, 
target_address_space(1)>, data !s32i}>
+// LLVM: %struct.S = type { ptr addrspace(1), i32 }
+
+[[clang::sycl_external]] void store_member(__attribute__((opencl_global)) int 
*g) {
+  S s;
+  s.p = g;
+}
+
+// POST-LABEL: cir.func {{.*}}@_Z12store_memberPU3AS1i
+// POST: cir.get_member %{{.*}}[0] {name = "p"} : !cir.ptr<!rec_S> -> 
!cir.ptr<!cir.ptr<!s32i, target_address_space(1)>>
+
+// LLVM-LABEL: define {{.*}}@_Z12store_memberPU3AS1i
+// LLVM: %[[P:.*]] = getelementptr inbounds nuw %struct.S, ptr {{.*}}, i32 0, 
i32 0
+// LLVM: store ptr addrspace(1) %{{.*}}, ptr {{.*}}%[[P]], align 8


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

Reply via email to