https://github.com/Men-cotton updated 
https://github.com/llvm/llvm-project/pull/224239

>From 3999f6e6b4f3d7dd3142b921709fdd3a326c1ebf Mon Sep 17 00:00:00 2001
From: mencotton <[email protected]>
Date: Tue, 15 Sep 2026 20:52:07 +0900
Subject: [PATCH 1/2] [CIR] Reject language address spaces in DirectToLLVM
 pointer conversion

Reject unlowered language address spaces in pointer types when bypassing 
TargetLowering. Guard pointer-producing lowerings, including generated 
patterns, so failed conversions report legalization failures instead of 
silently selecting address space zero or constructing invalid LLVM operations.

Assisted-by: Codex / GPT-6
---
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  64 +++
 .../CIR/Lowering/unlowered-address-spaces.cir | 504 ++++++++++++++++++
 clang/utils/TableGen/CIRLoweringEmitter.cpp   |   2 +
 3 files changed, 570 insertions(+)

diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 66d87b7ee35c7..a8d9672cf0867 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -49,6 +49,7 @@
 #include "clang/CIR/LoweringHelpers.h"
 #include "clang/CIR/MissingFeatures.h"
 #include "clang/CIR/Passes.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/TypeSwitch.h"
@@ -2285,6 +2286,8 @@ mlir::LogicalResult 
CIRToLLVMBaseClassAddrOpLowering::matchAndRewrite(
     mlir::ConversionPatternRewriter &rewriter) const {
   const mlir::Type resultType =
       getTypeConverter()->convertType(baseClassOp.getType());
+  if (!resultType)
+    return mlir::failure();
   mlir::Value derivedAddr = adaptor.getSrcAddr();
   llvm::SmallVector<mlir::LLVM::GEPArg, 1> offset = {
       adaptor.getOffset().getZExtValue()};
@@ -2317,6 +2320,8 @@ mlir::LogicalResult 
CIRToLLVMDerivedClassAddrOpLowering::matchAndRewrite(
     mlir::ConversionPatternRewriter &rewriter) const {
   const mlir::Type resultType =
       getTypeConverter()->convertType(derivedClassOp.getType());
+  if (!resultType)
+    return mlir::failure();
   mlir::Value baseAddr = adaptor.getSrcAddr();
   // The offset is set in the operation as an unsigned value, but it must be
   // applied as a negative offset.
@@ -2391,6 +2396,8 @@ mlir::LogicalResult 
CIRToLLVMAllocaOpLowering::matchAndRewrite(
            << "NYI: lowering alloca of a type with no memory representation";
   mlir::Type resultTy =
       convertTypeForMemory(*getTypeConverter(), dataLayout, op.getType());
+  if (!resultTy)
+    return mlir::failure();
 
   assert(!cir::MissingFeatures::addressSpace());
   assert(!cir::MissingFeatures::opAllocaAnnotations());
@@ -2647,6 +2654,8 @@ mlir::LogicalResult 
CIRToLLVMFrameAddrOpLowering::matchAndRewrite(
     cir::FrameAddrOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
   const mlir::Type llvmPtrTy = getTypeConverter()->convertType(op.getType());
+  if (!llvmPtrTy)
+    return mlir::failure();
   replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm.frameaddress", 
llvmPtrTy,
                                    adaptor.getOperands());
   return mlir::success();
@@ -2669,6 +2678,8 @@ mlir::LogicalResult 
CIRToLLVMAddrOfReturnAddrOpLowering::matchAndRewrite(
     cir::AddrOfReturnAddrOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
   const mlir::Type llvmPtrTy = getTypeConverter()->convertType(op.getType());
+  if (!llvmPtrTy)
+    return mlir::failure();
   replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm.addressofreturnaddress",
                                    llvmPtrTy, adaptor.getOperands());
   return mlir::success();
@@ -3251,6 +3262,8 @@ mlir::LogicalResult 
CIRToLLVMGetGlobalOpLowering::matchAndRewrite(
   }
 
   mlir::Type type = getTypeConverter()->convertType(op.getType());
+  if (!type)
+    return mlir::failure();
   mlir::Operation *newop = mlir::LLVM::AddressOfOp::create(
       rewriter, op.getLoc(), type, op.getName());
 
@@ -4286,12 +4299,51 @@ mlir::LogicalResult 
CIRToLLVMSelectOpLowering::matchAndRewrite(
   return mlir::success();
 }
 
+static bool
+containsLangAddressSpace(mlir::Type type,
+                         llvm::SmallDenseSet<mlir::Type, 4> &visited) {
+  if (!visited.insert(type).second)
+    return false;
+
+  if (auto ptrTy = mlir::dyn_cast<cir::PointerType>(type))
+    return mlir::isa_and_present<cir::LangAddressSpaceAttr>(
+               ptrTy.getAddrSpace()) ||
+           containsLangAddressSpace(ptrTy.getPointee(), visited);
+  if (auto arrayTy = mlir::dyn_cast<cir::ArrayType>(type))
+    return containsLangAddressSpace(arrayTy.getElementType(), visited);
+  if (auto vectorTy = mlir::dyn_cast<cir::VectorType>(type))
+    return containsLangAddressSpace(vectorTy.getElementType(), visited);
+  if (auto funcTy = mlir::dyn_cast<cir::FuncType>(type))
+    return llvm::any_of(funcTy.getInputs(),
+                        [&](mlir::Type input) {
+                          return containsLangAddressSpace(input, visited);
+                        }) ||
+           containsLangAddressSpace(funcTy.getReturnType(), visited);
+  if (auto dataMemberTy = mlir::dyn_cast<cir::DataMemberType>(type))
+    return containsLangAddressSpace(dataMemberTy.getMemberTy(), visited);
+  if (auto methodTy = mlir::dyn_cast<cir::MethodType>(type))
+    return containsLangAddressSpace(methodTy.getMemberFuncTy(), visited);
+  if (auto recordTy = mlir::dyn_cast<cir::RecordType>(type))
+    return llvm::any_of(recordTy.getMembers(), [&](mlir::Type member) {
+      return containsLangAddressSpace(member, visited);
+    });
+  return false;
+}
+
+static bool containsLangAddressSpace(mlir::Type type) {
+  llvm::SmallDenseSet<mlir::Type, 4> visited;
+  return containsLangAddressSpace(type, visited);
+}
+
 static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
                                  mlir::DataLayout &dataLayout) {
   converter.addConversion([&](cir::PointerType type) -> mlir::Type {
     mlir::ptr::MemorySpaceAttrInterface addrSpaceAttr = type.getAddrSpace();
     unsigned numericAS = 0;
 
+    if (containsLangAddressSpace(type))
+      return {};
+
     if (auto targetAsAttr =
             mlir::dyn_cast_if_present<cir::TargetAddressSpaceAttr>(
                 addrSpaceAttr))
@@ -4327,6 +4379,8 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter 
&converter,
         intTy && intTy.isBitInt())
       return {};
     const mlir::Type ty = converter.convertType(type.getElementType());
+    if (!ty)
+      return {};
     return mlir::VectorType::get(type.getSize(), ty, {type.getIsScalable()});
   });
   converter.addConversion([&](cir::MatrixType type) -> mlir::Type {
@@ -4927,6 +4981,8 @@ mlir::LogicalResult 
CIRToLLVMGetMemberOpLowering::matchAndRewrite(
     cir::GetMemberOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
   mlir::Type llResTy = getTypeConverter()->convertType(op.getType());
+  if (!llResTy)
+    return mlir::failure();
   mlir::Type pointee = op.getAddrTy().getPointee();
 
   if (mlir::isa<cir::UnionType>(pointee)) {
@@ -5319,6 +5375,8 @@ mlir::LogicalResult 
CIRToLLVMVTableGetVirtualFnAddrOpLowering::matchAndRewrite(
     cir::VTableGetVirtualFnAddrOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
   mlir::Type targetType = getTypeConverter()->convertType(op.getType());
+  if (!targetType)
+    return mlir::failure();
   auto eltType = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());
   llvm::SmallVector<mlir::LLVM::GEPArg> offsets =
       llvm::SmallVector<mlir::LLVM::GEPArg>{op.getIndex()};
@@ -5332,6 +5390,8 @@ mlir::LogicalResult 
CIRToLLVMVTTAddrPointOpLowering::matchAndRewrite(
     cir::VTTAddrPointOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
   const mlir::Type resultType = getTypeConverter()->convertType(op.getType());
+  if (!resultType)
+    return mlir::failure();
   llvm::SmallVector<mlir::LLVM::GEPArg> offsets;
   mlir::Type eltType;
   mlir::Value llvmAddr = adaptor.getSymAddr();
@@ -6064,6 +6124,8 @@ mlir::LogicalResult 
CIRToLLVMComplexImagPtrOpLowering::matchAndRewrite(
     mlir::ConversionPatternRewriter &rewriter) const {
   cir::PointerType operandTy = op.getOperand().getType();
   mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType());
+  if (!resultLLVMTy)
+    return mlir::failure();
   mlir::Type elementLLVMTy =
       getTypeConverter()->convertType(operandTy.getPointee());
 
@@ -6081,6 +6143,8 @@ mlir::LogicalResult 
CIRToLLVMComplexRealPtrOpLowering::matchAndRewrite(
     mlir::ConversionPatternRewriter &rewriter) const {
   cir::PointerType operandTy = op.getOperand().getType();
   mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType());
+  if (!resultLLVMTy)
+    return mlir::failure();
   mlir::Type elementLLVMTy =
       getTypeConverter()->convertType(operandTy.getPointee());
 
diff --git a/clang/test/CIR/Lowering/unlowered-address-spaces.cir 
b/clang/test/CIR/Lowering/unlowered-address-spaces.cir
index 0faf18e5d0067..3220e55e24c6d 100644
--- a/clang/test/CIR/Lowering/unlowered-address-spaces.cir
+++ b/clang/test/CIR/Lowering/unlowered-address-spaces.cir
@@ -2,8 +2,512 @@
 
 !s32i = !cir.int<s, 32>
 
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  // expected-error @below {{failed to legalize operation 'cir.func'}}
+  cir.func @language_address_space(%arg0: !cir.ptr<!s32i, 
lang_address_space(offload_global)>) {
+    cir.return
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  // expected-error @below {{failed to legalize operation 'cir.func'}}
+  cir.func private @language_address_space_return() -> !cir.ptr<!s32i, 
lang_address_space(offload_global)>
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  // expected-error @below {{failed to legalize operation 'cir.func'}}
+  cir.func @nested_language_address_space(%arg0: !cir.ptr<!cir.ptr<!s32i, 
lang_address_space(offload_local)>>) {
+    cir.return
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  // expected-error @below {{failed to legalize operation 'cir.func'}}
+  cir.func @function_and_array_language_address_space(
+      %arg0: !cir.ptr<!cir.func<(!cir.ptr<!cir.array<!cir.ptr<!s32i, 
lang_address_space(offload_constant)> x 4>>)>>) {
+    cir.return
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+// Keep walking after the recursive member to find the language address space.
+!rec_Node = !cir.struct<"Node" {data !cir.ptr<!cir.struct<"Node">>, data 
!cir.ptr<!s32i, lang_address_space(offload_global)>}>
+
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  // expected-error @below {{failed to legalize operation 'cir.func'}}
+  cir.func @recursive_struct_language_address_space(%arg0: 
!cir.ptr<!rec_Node>) {
+    cir.return
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!rec_U = !cir.union<"U" {data !s32i, data !cir.ptr<!s32i, 
lang_address_space(offload_global)>}>
+
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  // expected-error @below {{failed to legalize operation 'cir.func'}}
+  cir.func @union_language_address_space(%arg0: !cir.ptr<!rec_U>) {
+    cir.return
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!rec_Foo = !cir.struct<"Foo" {data !s32i}>
+
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  // expected-error @below {{failed to legalize operation 'cir.func'}}
+  cir.func @data_member_language_address_space(
+      %arg0: !cir.ptr<!cir.data_member<!cir.ptr<!s32i, 
lang_address_space(offload_global)> in !rec_Foo>>) {
+    cir.return
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!rec_Foo = !cir.struct<"Foo" {data !s32i}>
+
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  // expected-error @below {{failed to legalize operation 'cir.func'}}
+  cir.func @method_language_address_space(
+      %arg0: !cir.ptr<!cir.method<!cir.func<(!cir.ptr<!s32i, 
lang_address_space(offload_global)>)> in !rec_Foo>>) {
+    cir.return
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+
 module attributes {cir.triple = "spirv64-unknown-unknown"} {
   // expected-error @below {{cannot lower a global with a language address 
space}}
   // expected-error @below {{failed to legalize operation 'cir.global'}}
   cir.global external lang_address_space(offload_global) @global = #cir.int<1> 
: !s32i
 }
+
+// -----
+
+!s64i = !cir.int<s, 64>
+!langptr = !cir.ptr<!cir.void, lang_address_space(offload_global)>
+!rec_U = !cir.union<"U" {data !s64i, data !langptr}>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  // The union's integer storage converts, but its active initializer does not.
+  // expected-error @below {{failed to legalize operation 'cir.global'}}
+  cir.global external @union_active_initializer_language_address_space = 
#cir.const_record<{#cir.ptr<null> : !langptr}> : !rec_U
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  // Unlike direct cir.func lowering, a global view can request FuncType
+  // conversion before its referenced function is lowered.
+  cir.global external @function_pointer = 
#cir.global_view<@global_view_callee> : !cir.ptr<!cir.void>
+
+  // expected-error @below {{failed to legalize operation 'cir.func'}}
+  cir.func private @global_view_callee() -> !cir.ptr<!s32i, 
lang_address_space(offload_global)>
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!langptr = !cir.ptr<!s32i, lang_address_space(offload_global)>
+!array = !cir.array<!langptr x 1>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  // Keep the view before its target so the initializer is lowered first.
+  // expected-error @below {{failed to legalize operation 'cir.global'}}
+  cir.global external @view = #cir.global_view<@target, [0 : i32]> : 
!cir.ptr<!cir.void>
+
+  cir.global external @target = #cir.zero : !array
+}
+
+// -----
+
+!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>
+!array = !cir.array<!langptr x 1>
+!ptr = !cir.ptr<!cir.void>
+!ptrarray = !cir.array<!ptr x 1>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  // Lower the view before its target, including through enclosing attributes.
+  // expected-error @below {{failed to legalize operation 'cir.global'}}
+  cir.global external @view = #cir.const_array<[#cir.global_view<@target, [0 : 
i32]> : !ptr]> : !ptrarray
+
+  cir.global external @target = #cir.zero : !array
+}
+
+// -----
+
+!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>
+!array = !cir.array<!langptr x 1>
+!ptr = !cir.ptr<!cir.void>
+!record = !cir.struct<{data !ptr}>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  // Lower the view before its target, including through enclosing attributes.
+  // expected-error @below {{failed to legalize operation 'cir.global'}}
+  cir.global external @view = #cir.const_record<{#cir.global_view<@target, [0 
: i32]> : !ptr}> : !record
+
+  cir.global external @target = #cir.zero : !array
+}
+
+// -----
+
+!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>
+!array = !cir.array<!langptr x 1>
+!ptr = !cir.ptr<!cir.void>
+!record = !cir.struct<{data !ptr}>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  // Lower the view before its target, including through enclosing attributes.
+  // expected-error @below {{failed to legalize operation 'cir.global'}}
+  cir.global external @view = #cir.typeinfo<{#cir.global_view<@target, [0 : 
i32]> : !ptr}> : !record
+
+  cir.global external @target = #cir.zero : !array
+}
+
+// -----
+
+!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>
+!array = !cir.array<!langptr x 1>
+!ptr = !cir.ptr<!cir.void>
+!ptrarray = !cir.array<!ptr x 1>
+!vtable = !cir.struct<{data !ptrarray}>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  // Lower the view before its target, including through enclosing attributes.
+  // expected-error @below {{failed to legalize operation 'cir.global'}}
+  cir.global external @view = 
#cir.vtable<{#cir.const_array<[#cir.global_view<@target, [0 : i32]> : !ptr]> : 
!ptrarray}> : !vtable
+
+  cir.global external @target = #cir.zero : !array
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  // Keep the function before the global so get_global is lowered first.
+  cir.func @get_global_language_address_space() {
+    // expected-error @below {{failed to legalize operation 'cir.get_global'}}
+    %0 = cir.get_global @global : !cir.ptr<!s32i, 
lang_address_space(offload_global)>
+    %1 = cir.load %0 : !cir.ptr<!s32i, lang_address_space(offload_global)>, 
!s32i
+    cir.return
+  }
+
+  cir.global external lang_address_space(offload_global) @global = #cir.int<1> 
: !s32i
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  cir.func @alloca_language_address_space() {
+    // expected-error @below {{failed to legalize operation 'cir.alloca'}}
+    %0 = cir.alloca "x" align(4) : !cir.ptr<!s32i, 
lang_address_space(offload_private)>
+    cir.return
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  cir.func @null_constant_language_address_space() {
+    // expected-error @below {{failed to legalize operation 'cir.const'}}
+    %0 = cir.const #cir.ptr<null> : !cir.ptr<!s32i, 
lang_address_space(offload_global)>
+    cir.return
+  }
+}
+
+// -----
+
+!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>
+!array = !cir.array<!langptr x 1>
+!ptr = !cir.ptr<!cir.void>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  // Lower the view before its target, including through enclosing attributes.
+  cir.func @constant_global_view_language_address_space() {
+    // expected-error @below {{failed to legalize operation 'cir.const'}}
+    %0 = cir.const #cir.global_view<@target, [0 : i32]> : !ptr
+    cir.return
+  }
+
+  cir.global external @target = #cir.zero : !array
+}
+
+// -----
+
+!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>
+!array = !cir.array<!langptr x 1>
+!ptr = !cir.ptr<!cir.void>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  // Lower the view before its target, including through enclosing attributes.
+  cir.func @constant_array_global_view_language_address_space() {
+    // expected-error @below {{failed to legalize operation 'cir.const'}}
+    %0 = cir.const #cir.const_array<[#cir.global_view<@target, [0 : i32]> : 
!ptr]> : !cir.array<!ptr x 1>
+    cir.return
+  }
+
+  cir.global external @target = #cir.zero : !array
+}
+
+// -----
+
+!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>
+!array = !cir.array<!langptr x 1>
+!ptr = !cir.ptr<!cir.void>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  // Lower the view before its target, including through enclosing attributes.
+  cir.func @constant_record_global_view_language_address_space() {
+    // expected-error @below {{failed to legalize operation 'cir.const'}}
+    %0 = cir.const #cir.const_record<{#cir.global_view<@target, [0 : i32]> : 
!ptr}> : !cir.struct<{data !ptr}>
+    cir.return
+  }
+
+  cir.global external @target = #cir.zero : !array
+}
+
+// -----
+
+!s64i = !cir.int<s, 64>
+!langptr = !cir.ptr<!cir.void, lang_address_space(offload_global)>
+!rec_U = !cir.union<"U" {data !s64i, data !langptr}>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  cir.func @constant_union_active_initializer_language_address_space() {
+    // expected-error @below {{failed to legalize operation 'cir.const'}}
+    %0 = cir.const #cir.const_record<{#cir.ptr<null> : !langptr}> : !rec_U
+    cir.return
+  }
+}
+
+// -----
+
+!s64i = !cir.int<s, 64>
+!langptr = !cir.ptr<!cir.void, lang_address_space(offload_global)>
+!rec_U = !cir.union<"U" {data !s64i, data !langptr}>
+!rec_Outer = !cir.union<"Outer" {data !s64i, data !rec_U}>
+!rec_S = !cir.struct<"S" {data !rec_Outer}>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  // Propagate adjustment failure through both the enclosing union and struct.
+  cir.func @constant_nested_union_initializer_language_address_space() {
+    // expected-error @below {{failed to legalize operation 'cir.const'}}
+    %0 = cir.const 
#cir.const_record<{#cir.const_record<{#cir.const_record<{#cir.ptr<null> : 
!langptr}> : !rec_U}> : !rec_Outer}> : !rec_S
+    cir.return
+  }
+}
+
+// -----
+
+!s64i = !cir.int<s, 64>
+!langptr = !cir.ptr<!cir.void, lang_address_space(offload_global)>
+!rec_U = !cir.union<"U" {data !s64i, data !langptr}>
+!array = !cir.array<!rec_U x 1>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  cir.func @constant_union_array_initializer_language_address_space() {
+    // expected-error @below {{failed to legalize operation 'cir.const'}}
+    %0 = cir.const #cir.const_array<[#cir.const_record<{#cir.ptr<null> : 
!langptr}> : !rec_U]> : !array
+    cir.return
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  cir.func @int_to_ptr_language_address_space(%arg0: !s32i) {
+    // expected-error @below {{failed to legalize operation 'cir.cast'}}
+    %0 = cir.cast int_to_ptr %arg0 : !s32i -> !cir.ptr<!s32i, 
lang_address_space(offload_global)>
+    cir.return
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  cir.func @address_space_cast_language_address_space(%arg0: !cir.ptr<!s32i>) {
+    // expected-error @below {{failed to legalize operation 'cir.cast'}}
+    %0 = cir.cast address_space %arg0 : !cir.ptr<!s32i> -> !cir.ptr<!s32i, 
lang_address_space(offload_global)>
+    cir.return
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!rec_Base = !cir.struct<"Base" {data !s32i}>
+!rec_Derived = !cir.struct<"Derived" {data !cir.ptr<!s32i, 
lang_address_space(offload_global)>, data !rec_Base}>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  cir.func @derived_class_addr_language_address_space() {
+    %base = cir.alloca "base" align(4) : !cir.ptr<!rec_Base>
+    // expected-error @below {{failed to legalize operation 
'cir.derived_class_addr'}}
+    %derived = cir.derived_class_addr nonnull %base [4] : !cir.ptr<!rec_Base> 
-> !cir.ptr<!rec_Derived>
+    cir.return
+  }
+}
+
+// -----
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  cir.func @complex_real_ptr_language_address_space(%ptr: 
!cir.ptr<!cir.complex<!cir.double>>) {
+    // expected-error @below {{failed to legalize operation 
'cir.complex.real_ptr'}}
+    %real = cir.complex.real_ptr %ptr : !cir.ptr<!cir.complex<!cir.double>> -> 
!cir.ptr<!cir.double, lang_address_space(offload_private)>
+    cir.return
+  }
+}
+
+// -----
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  cir.func @complex_imag_ptr_language_address_space(%ptr: 
!cir.ptr<!cir.complex<!cir.double>>) {
+    // expected-error @below {{failed to legalize operation 
'cir.complex.imag_ptr'}}
+    %imag = cir.complex.imag_ptr %ptr : !cir.ptr<!cir.complex<!cir.double>> -> 
!cir.ptr<!cir.double, lang_address_space(offload_private)>
+    cir.return
+  }
+}
+
+// -----
+
+!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>
+!array = !cir.array<!langptr x 1>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  // Lower the address point before its referenced global.
+  cir.func @vtable_symbol_language_address_space() {
+    // expected-error @below {{failed to legalize operation 
'cir.vtable.address_point'}}
+    %0 = cir.vtable.address_point(@target, address_point = <index = 0, offset 
= 0>) : !cir.vptr
+    cir.return
+  }
+
+  cir.global "private" external @target : !cir.struct<{data !array}>
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!langptr = !cir.ptr<!s32i, lang_address_space(offload_global)>
+!fn = !cir.func<() -> !langptr>
+!fnptr = !cir.ptr<!fn>
+!fnptrptr = !cir.ptr<!fnptr>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  cir.func @virtual_fn_addr_language_address_space(%vptr: !cir.vptr) {
+    // expected-error @below {{failed to legalize operation 
'cir.vtable.get_virtual_fn_addr'}}
+    %0 = cir.vtable.get_virtual_fn_addr %vptr[0] : !cir.vptr -> !fnptrptr
+    cir.return
+  }
+}
+
+// -----
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  cir.func @vtt_address_point_language_address_space(
+      %vtt: !cir.ptr<!cir.ptr<!cir.void>>) {
+    // expected-error @below {{failed to legalize operation 
'cir.vtt.address_point'}}
+    %0 = cir.vtt.address_point %vtt : !cir.ptr<!cir.ptr<!cir.void>>, offset = 
1 -> !cir.ptr<!cir.ptr<!cir.void>, lang_address_space(offload_global)>
+    cir.return
+  }
+}
+
+// -----
+
+!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>
+!array = !cir.array<!langptr x 1>
+!ptr = !cir.ptr<!cir.void>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  // Lower the address point before its referenced global.
+  cir.func @vtt_symbol_language_address_space() {
+    // expected-error @below {{failed to legalize operation 
'cir.vtt.address_point'}}
+    %0 = cir.vtt.address_point @target, offset = 0 -> !cir.ptr<!ptr>
+    cir.return
+  }
+
+  cir.global "private" external @target : !array
+}
+
+// -----
+
+!u8i = !cir.int<u, 8>
+!u32i = !cir.int<u, 32>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  cir.func @frame_address_language_address_space() {
+    %level = cir.const #cir.int<0> : !u32i
+    // expected-error @below {{failed to legalize operation 
'cir.frame_address'}}
+    %0 = cir.frame_address(%level) : !cir.ptr<!u8i, 
lang_address_space(offload_global)>
+    cir.return
+  }
+}
+
+// -----
+
+!u8i = !cir.int<u, 8>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  cir.func @address_of_return_address_language_address_space() {
+    // expected-error @below {{failed to legalize operation 
'cir.address_of_return_address'}}
+    %0 = cir.address_of_return_address : !cir.ptr<!u8i, 
lang_address_space(offload_global)>
+    cir.return
+  }
+}
+
+// -----
+
+!u8i = !cir.int<u, 8>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  cir.func @stacksave_language_address_space() {
+    // expected-error @below {{failed to legalize operation 'cir.stacksave'}}
+    %0 = cir.stacksave : !cir.ptr<!u8i, lang_address_space(offload_global)>
+    cir.return
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  cir.func @inline_asm_language_address_space() {
+    // expected-error @below {{failed to legalize operation 'cir.asm'}}
+    %0 = cir.asm(x86_att,
+      out = [],
+      in = [],
+      in_out = [],
+      {"" "=r"}) -> !cir.ptr<!s32i, lang_address_space(offload_global)>
+    cir.return
+  }
+}
diff --git a/clang/utils/TableGen/CIRLoweringEmitter.cpp 
b/clang/utils/TableGen/CIRLoweringEmitter.cpp
index b533c239635a6..62a2411c66c0f 100644
--- a/clang/utils/TableGen/CIRLoweringEmitter.cpp
+++ b/clang/utils/TableGen/CIRLoweringEmitter.cpp
@@ -239,6 +239,8 @@ void GenerateLLVMLoweringPattern(llvm::StringRef OpName,
     } else {
       Code << "    mlir::Type resTy = "
               "typeConverter->convertType(op.getType());\n";
+      Code << "    if (!resTy)\n";
+      Code << "      return mlir::failure();\n";
       Code << "    rewriter.replaceOpWithNewOp<mlir::LLVM::" << LLVMOp
            << ">(op, mlir::TypeRange{resTy}, adaptor.getOperands(), "
            << Properties << ");\n";

>From c4cf0482ef05468f1bee73a21aab463ad4acf01c Mon Sep 17 00:00:00 2001
From: mencotton <[email protected]>
Date: Fri, 16 Oct 2026 11:55:28 -0500
Subject: [PATCH 2/2] fix: [CIR] Check only the converted pointer's address
 space

Limit opaque pointer conversion to its own address space and diagnose 
unsupported pointee types where their layout is required. Emit type-specific 
errors for failed pointer conversions.

Validate pointee memory conversion before deriving copy sizes, alignments, or 
pointer-difference strides from CIR layout. Keep deeper pointee types opaque 
when their layouts are not needed.

Assisted-by: Codex / GPT-6
---
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  91 +++----
 .../opaque-pointer-address-spaces.cir         | 153 +++++++++++
 .../CIR/Lowering/unlowered-address-spaces.cir | 247 +++++++++++-------
 clang/utils/TableGen/CIRLoweringEmitter.cpp   |   3 +-
 4 files changed, 342 insertions(+), 152 deletions(-)
 create mode 100644 clang/test/CIR/Lowering/opaque-pointer-address-spaces.cir

diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index a8d9672cf0867..abd781ed03baa 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -49,7 +49,6 @@
 #include "clang/CIR/LoweringHelpers.h"
 #include "clang/CIR/MissingFeatures.h"
 #include "clang/CIR/Passes.h"
-#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/TypeSwitch.h"
@@ -360,6 +359,11 @@ convertFramePointerKindToLLVMIR(cir::FramePointerKind 
kind) {
 mlir::LogicalResult CIRToLLVMCopyOpLowering::matchAndRewrite(
     cir::CopyOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
+  // Opaque pointer conversion does not validate the pointee's memory layout.
+  mlir::Type pointeeType = op.getType().getPointee();
+  if (!convertTypeForMemory(*getTypeConverter(), dataLayout, pointeeType))
+    return emitTypeConversionError(op, pointeeType);
+
   mlir::DataLayout layout(op->getParentOfType<mlir::ModuleOp>());
   const mlir::Value length = mlir::LLVM::ConstantOp::create(
       rewriter, op.getLoc(), rewriter.getI64Type(),
@@ -1933,6 +1937,8 @@ mlir::LogicalResult 
CIRToLLVMCastOpLowering::matchAndRewrite(
     mlir::Type targetType = convertTy(ptrTy);
     mlir::Type elementTy = convertTypeForMemory(*getTypeConverter(), 
dataLayout,
                                                 ptrTy.getPointee());
+    if (!elementTy)
+      return emitTypeConversionError(castOp, ptrTy.getPointee());
     llvm::SmallVector<mlir::LLVM::GEPArg> offset{0};
     rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(
         castOp, targetType, elementTy, sourceValue, offset);
@@ -2226,6 +2232,8 @@ mlir::LogicalResult 
CIRToLLVMPtrStrideOpLowering::matchAndRewrite(
 
   mlir::Type elementTy =
       convertTypeForMemory(*tc, dataLayout, ptrStrideOp.getElementType());
+  if (!elementTy)
+    return emitTypeConversionError(ptrStrideOp, ptrStrideOp.getElementType());
 
   // void and function types doesn't really have a layout to use in GEPs,
   // make it i8 instead.
@@ -2252,6 +2260,8 @@ mlir::LogicalResult 
CIRToLLVMGetElementOpLowering::matchAndRewrite(
           mlir::dyn_cast<cir::ArrayType>(op.getBaseType().getPointee())) {
     const mlir::TypeConverter *converter = getTypeConverter();
     const mlir::Type llArrayTy = converter->convertType(arrayTy);
+    if (!llArrayTy)
+      return emitTypeConversionError(op, arrayTy);
     const mlir::Type llResultTy = converter->convertType(op.getType());
     mlir::Type elementTy =
         convertTypeForMemory(*converter, dataLayout, op.getElementType());
@@ -2287,7 +2297,7 @@ mlir::LogicalResult 
CIRToLLVMBaseClassAddrOpLowering::matchAndRewrite(
   const mlir::Type resultType =
       getTypeConverter()->convertType(baseClassOp.getType());
   if (!resultType)
-    return mlir::failure();
+    return emitTypeConversionError(baseClassOp, baseClassOp.getType());
   mlir::Value derivedAddr = adaptor.getSrcAddr();
   llvm::SmallVector<mlir::LLVM::GEPArg, 1> offset = {
       adaptor.getOffset().getZExtValue()};
@@ -2321,7 +2331,7 @@ mlir::LogicalResult 
CIRToLLVMDerivedClassAddrOpLowering::matchAndRewrite(
   const mlir::Type resultType =
       getTypeConverter()->convertType(derivedClassOp.getType());
   if (!resultType)
-    return mlir::failure();
+    return emitTypeConversionError(derivedClassOp, derivedClassOp.getType());
   mlir::Value baseAddr = adaptor.getSrcAddr();
   // The offset is set in the operation as an unsigned value, but it must be
   // applied as a negative offset.
@@ -2397,7 +2407,7 @@ mlir::LogicalResult 
CIRToLLVMAllocaOpLowering::matchAndRewrite(
   mlir::Type resultTy =
       convertTypeForMemory(*getTypeConverter(), dataLayout, op.getType());
   if (!resultTy)
-    return mlir::failure();
+    return emitTypeConversionError(op, op.getType());
 
   assert(!cir::MissingFeatures::addressSpace());
   assert(!cir::MissingFeatures::opAllocaAnnotations());
@@ -2655,7 +2665,7 @@ mlir::LogicalResult 
CIRToLLVMFrameAddrOpLowering::matchAndRewrite(
     mlir::ConversionPatternRewriter &rewriter) const {
   const mlir::Type llvmPtrTy = getTypeConverter()->convertType(op.getType());
   if (!llvmPtrTy)
-    return mlir::failure();
+    return emitTypeConversionError(op, op.getType());
   replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm.frameaddress", 
llvmPtrTy,
                                    adaptor.getOperands());
   return mlir::success();
@@ -2679,7 +2689,7 @@ mlir::LogicalResult 
CIRToLLVMAddrOfReturnAddrOpLowering::matchAndRewrite(
     mlir::ConversionPatternRewriter &rewriter) const {
   const mlir::Type llvmPtrTy = getTypeConverter()->convertType(op.getType());
   if (!llvmPtrTy)
-    return mlir::failure();
+    return emitTypeConversionError(op, op.getType());
   replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm.addressofreturnaddress",
                                    llvmPtrTy, adaptor.getOperands());
   return mlir::success();
@@ -2691,8 +2701,7 @@ mlir::LogicalResult 
CIRToLLVMLoadOpLowering::matchAndRewrite(
   const mlir::Type llvmTy =
       convertTypeForLoadStore(*getTypeConverter(), dataLayout, op.getType());
   if (!llvmTy)
-    return op.emitError()
-           << "NYI: lowering load of a type with no memory representation";
+    return emitTypeConversionError(op, op.getType());
   mlir::LLVM::AtomicOrdering ordering = getLLVMMemOrder(op.getMemOrder());
   std::optional<size_t> opAlign = op.getAlignment();
   unsigned alignment = (unsigned)opAlign.value_or(
@@ -2973,6 +2982,10 @@ mlir::LogicalResult 
CIRToLLVMPrefetchOpLowering::matchAndRewrite(
 mlir::LogicalResult CIRToLLVMPtrDiffOpLowering::matchAndRewrite(
     cir::PtrDiffOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
+  mlir::Type pointeeType = op.getLhs().getType().getPointee();
+  if (!convertTypeForMemory(*getTypeConverter(), dataLayout, pointeeType))
+    return emitTypeConversionError(op, pointeeType);
+
   auto dstTy = mlir::cast<cir::IntType>(op.getType());
   mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);
 
@@ -2984,9 +2997,8 @@ mlir::LogicalResult 
CIRToLLVMPtrDiffOpLowering::matchAndRewrite(
   auto diff =
       mlir::LLVM::SubOp::create(rewriter, op.getLoc(), llvmDstTy, lhs, rhs);
 
-  cir::PointerType ptrTy = op.getLhs().getType();
   assert(!cir::MissingFeatures::llvmLoweringPtrDiffConsidersPointee());
-  uint64_t typeSize = getTypeAllocSize(ptrTy.getPointee(), *op);
+  uint64_t typeSize = getTypeAllocSize(pointeeType, *op);
 
   // Avoid silly division by 1.
   mlir::Value resultVal = diff.getResult();
@@ -3263,7 +3275,7 @@ mlir::LogicalResult 
CIRToLLVMGetGlobalOpLowering::matchAndRewrite(
 
   mlir::Type type = getTypeConverter()->convertType(op.getType());
   if (!type)
-    return mlir::failure();
+    return emitTypeConversionError(op, op.getType());
   mlir::Operation *newop = mlir::LLVM::AddressOfOp::create(
       rewriter, op.getLoc(), type, op.getName());
 
@@ -4299,49 +4311,13 @@ mlir::LogicalResult 
CIRToLLVMSelectOpLowering::matchAndRewrite(
   return mlir::success();
 }
 
-static bool
-containsLangAddressSpace(mlir::Type type,
-                         llvm::SmallDenseSet<mlir::Type, 4> &visited) {
-  if (!visited.insert(type).second)
-    return false;
-
-  if (auto ptrTy = mlir::dyn_cast<cir::PointerType>(type))
-    return mlir::isa_and_present<cir::LangAddressSpaceAttr>(
-               ptrTy.getAddrSpace()) ||
-           containsLangAddressSpace(ptrTy.getPointee(), visited);
-  if (auto arrayTy = mlir::dyn_cast<cir::ArrayType>(type))
-    return containsLangAddressSpace(arrayTy.getElementType(), visited);
-  if (auto vectorTy = mlir::dyn_cast<cir::VectorType>(type))
-    return containsLangAddressSpace(vectorTy.getElementType(), visited);
-  if (auto funcTy = mlir::dyn_cast<cir::FuncType>(type))
-    return llvm::any_of(funcTy.getInputs(),
-                        [&](mlir::Type input) {
-                          return containsLangAddressSpace(input, visited);
-                        }) ||
-           containsLangAddressSpace(funcTy.getReturnType(), visited);
-  if (auto dataMemberTy = mlir::dyn_cast<cir::DataMemberType>(type))
-    return containsLangAddressSpace(dataMemberTy.getMemberTy(), visited);
-  if (auto methodTy = mlir::dyn_cast<cir::MethodType>(type))
-    return containsLangAddressSpace(methodTy.getMemberFuncTy(), visited);
-  if (auto recordTy = mlir::dyn_cast<cir::RecordType>(type))
-    return llvm::any_of(recordTy.getMembers(), [&](mlir::Type member) {
-      return containsLangAddressSpace(member, visited);
-    });
-  return false;
-}
-
-static bool containsLangAddressSpace(mlir::Type type) {
-  llvm::SmallDenseSet<mlir::Type, 4> visited;
-  return containsLangAddressSpace(type, visited);
-}
-
 static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
                                  mlir::DataLayout &dataLayout) {
   converter.addConversion([&](cir::PointerType type) -> mlir::Type {
     mlir::ptr::MemorySpaceAttrInterface addrSpaceAttr = type.getAddrSpace();
     unsigned numericAS = 0;
 
-    if (containsLangAddressSpace(type))
+    if (mlir::isa_and_present<cir::LangAddressSpaceAttr>(addrSpaceAttr))
       return {};
 
     if (auto targetAsAttr =
@@ -4982,7 +4958,7 @@ mlir::LogicalResult 
CIRToLLVMGetMemberOpLowering::matchAndRewrite(
     mlir::ConversionPatternRewriter &rewriter) const {
   mlir::Type llResTy = getTypeConverter()->convertType(op.getType());
   if (!llResTy)
-    return mlir::failure();
+    return emitTypeConversionError(op, op.getType());
   mlir::Type pointee = op.getAddrTy().getPointee();
 
   if (mlir::isa<cir::UnionType>(pointee)) {
@@ -5001,6 +4977,8 @@ mlir::LogicalResult 
CIRToLLVMGetMemberOpLowering::matchAndRewrite(
   llvm::SmallVector<mlir::LLVM::GEPArg, 2> offset{
       0, static_cast<int32_t>(structTy.getLLVMFieldIndex(op.getIndex()))};
   const mlir::Type elementTy = getTypeConverter()->convertType(structTy);
+  if (!elementTy)
+    return emitTypeConversionError(op, structTy);
   // Struct member accesses are always inbounds and nuw: the base pointer
   // is valid and the member offset is a positive, constant offset within
   // the struct layout, so it cannot wrap. This matches LLVM's
@@ -5376,7 +5354,7 @@ mlir::LogicalResult 
CIRToLLVMVTableGetVirtualFnAddrOpLowering::matchAndRewrite(
     mlir::ConversionPatternRewriter &rewriter) const {
   mlir::Type targetType = getTypeConverter()->convertType(op.getType());
   if (!targetType)
-    return mlir::failure();
+    return emitTypeConversionError(op, op.getType());
   auto eltType = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());
   llvm::SmallVector<mlir::LLVM::GEPArg> offsets =
       llvm::SmallVector<mlir::LLVM::GEPArg>{op.getIndex()};
@@ -5391,7 +5369,7 @@ mlir::LogicalResult 
CIRToLLVMVTTAddrPointOpLowering::matchAndRewrite(
     mlir::ConversionPatternRewriter &rewriter) const {
   const mlir::Type resultType = getTypeConverter()->convertType(op.getType());
   if (!resultType)
-    return mlir::failure();
+    return emitTypeConversionError(op, op.getType());
   llvm::SmallVector<mlir::LLVM::GEPArg> offsets;
   mlir::Type eltType;
   mlir::Value llvmAddr = adaptor.getSymAddr();
@@ -6125,7 +6103,7 @@ mlir::LogicalResult 
CIRToLLVMComplexImagPtrOpLowering::matchAndRewrite(
   cir::PointerType operandTy = op.getOperand().getType();
   mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType());
   if (!resultLLVMTy)
-    return mlir::failure();
+    return emitTypeConversionError(op, op.getType());
   mlir::Type elementLLVMTy =
       getTypeConverter()->convertType(operandTy.getPointee());
 
@@ -6144,7 +6122,7 @@ mlir::LogicalResult 
CIRToLLVMComplexRealPtrOpLowering::matchAndRewrite(
   cir::PointerType operandTy = op.getOperand().getType();
   mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType());
   if (!resultLLVMTy)
-    return mlir::failure();
+    return emitTypeConversionError(op, op.getType());
   mlir::Type elementLLVMTy =
       getTypeConverter()->convertType(operandTy.getPointee());
 
@@ -6243,8 +6221,11 @@ mlir::LogicalResult 
CIRToLLVMInlineAsmOpLowering::matchAndRewrite(
 
     llvm::SmallVector<mlir::NamedAttribute, 1> attrs;
     cir::PointerType typ = mlir::cast<cir::PointerType>(cirOp.getType());
-    mlir::TypeAttr typAttr = mlir::TypeAttr::get(convertTypeForMemory(
-        *getTypeConverter(), dataLayout, typ.getPointee()));
+    mlir::Type elementTy =
+        convertTypeForMemory(*getTypeConverter(), dataLayout, 
typ.getPointee());
+    if (!elementTy)
+      return emitTypeConversionError(op, typ.getPointee());
+    mlir::TypeAttr typAttr = mlir::TypeAttr::get(elementTy);
 
     attrs.push_back(rewriter.getNamedAttr(llvmAttrName, typAttr));
     mlir::DictionaryAttr newDict = rewriter.getDictionaryAttr(attrs);
diff --git a/clang/test/CIR/Lowering/opaque-pointer-address-spaces.cir 
b/clang/test/CIR/Lowering/opaque-pointer-address-spaces.cir
new file mode 100644
index 0000000000000..90b6d22962158
--- /dev/null
+++ b/clang/test/CIR/Lowering/opaque-pointer-address-spaces.cir
@@ -0,0 +1,153 @@
+// RUN: cir-opt %s --split-input-file --cir-to-llvm | FileCheck %s
+
+// Only the pointer's own address space is needed for an opaque LLVM pointer.
+// Language address spaces in its pointee do not prevent pointer conversion.
+
+!s32i = !cir.int<s, 32>
+
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  // CHECK-LABEL: llvm.func @nested_language_address_space
+  // CHECK-SAME: !llvm.ptr
+  cir.func @nested_language_address_space(%arg0: !cir.ptr<!cir.ptr<!s32i, 
lang_address_space(offload_local)>>) {
+    cir.return
+  }
+}
+
+// -----
+
+!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_local)>
+!outer = !cir.ptr<!langptr, target_address_space(3)>
+
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  // CHECK-LABEL: llvm.func @outer_target_address_space
+  // CHECK-SAME: %[[ARG:.*]]: !llvm.ptr<3>) -> !llvm.ptr<3>
+  cir.func @outer_target_address_space(%ptr: !outer) -> !outer {
+    // CHECK: llvm.return %[[ARG]] : !llvm.ptr<3>
+    cir.return %ptr : !outer
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!rec_Node = !cir.struct<"Node" {data !cir.ptr<!cir.struct<"Node">>, data 
!cir.ptr<!s32i, lang_address_space(offload_global)>}>
+
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  // CHECK-LABEL: llvm.func @recursive_struct_language_address_space
+  // CHECK-SAME: !llvm.ptr
+  cir.func @recursive_struct_language_address_space(%arg0: 
!cir.ptr<!rec_Node>) {
+    cir.return
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!rec_U = !cir.union<"U" {data !s32i, data !cir.ptr<!s32i, 
lang_address_space(offload_global)>}>
+
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  // CHECK-LABEL: llvm.func @union_language_address_space
+  // CHECK-SAME: !llvm.ptr
+  cir.func @union_language_address_space(%arg0: !cir.ptr<!rec_U>) {
+    cir.return
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  // CHECK-LABEL: llvm.func @function_and_array_language_address_space
+  // CHECK-SAME: !llvm.ptr
+  cir.func @function_and_array_language_address_space(
+      %arg0: !cir.ptr<!cir.func<(!cir.ptr<!cir.array<!cir.ptr<!s32i, 
lang_address_space(offload_constant)> x 4>>)>>) {
+    cir.return
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!rec_Foo = !cir.struct<"Foo" {data !s32i}>
+
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  // CHECK-LABEL: llvm.func @data_member_language_address_space
+  // CHECK-SAME: !llvm.ptr
+  cir.func @data_member_language_address_space(
+      %arg0: !cir.ptr<!cir.data_member<!cir.ptr<!s32i, 
lang_address_space(offload_global)> in !rec_Foo>>) {
+    cir.return
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!rec_Foo = !cir.struct<"Foo" {data !s32i}>
+
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  // CHECK-LABEL: llvm.func @method_language_address_space
+  // CHECK-SAME: !llvm.ptr
+  cir.func @method_language_address_space(
+      %arg0: !cir.ptr<!cir.method<!cir.func<(!cir.ptr<!s32i, 
lang_address_space(offload_global)>)> in !rec_Foo>>) {
+    cir.return
+  }
+}
+
+// -----
+
+!s64i = !cir.int<s, 64>
+!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_local)>
+!ptr = !cir.ptr<!langptr>
+
+module attributes {cir.triple = "amdgcn-amd-amdhsa", llvm.data_layout = 
"e-p:64:64-p3:32:32"} {
+  // The stored pointer has a known layout even though its pointee does not.
+  // CHECK-LABEL: llvm.func @copy_opaque_pointers
+  cir.func @copy_opaque_pointers(%src: !cir.ptr<!ptr>, %dst: !cir.ptr<!ptr>) {
+    // CHECK: %[[SIZE:.*]] = llvm.mlir.constant(8 : i64)
+    // CHECK: "llvm.intr.memcpy"(%{{.*}}, %{{.*}}, %[[SIZE]])
+    cir.copy %src to %dst : !cir.ptr<!ptr>
+    cir.return
+  }
+
+  // CHECK-LABEL: llvm.func @diff_opaque_pointers
+  cir.func @diff_opaque_pointers(%lhs: !cir.ptr<!ptr>, %rhs: !cir.ptr<!ptr>) 
-> !s64i {
+    // CHECK: %[[SIZE:.*]] = llvm.mlir.constant(8 : i64)
+    // CHECK: llvm.sdiv exact %{{.*}}, %[[SIZE]] : i64
+    %diff = cir.ptr_diff %lhs, %rhs : !cir.ptr<!ptr> -> !s64i
+    cir.return %diff : !s64i
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!rec_Base = !cir.struct<"Base" {data !s32i}>
+!rec_Derived = !cir.struct<"Derived" {data !cir.ptr<!s32i, 
lang_address_space(offload_global)>, data !rec_Base}>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  // CHECK-LABEL: llvm.func @derived_class_addr_language_address_space
+  cir.func @derived_class_addr_language_address_space() {
+    %base = cir.alloca "base" align(4) : !cir.ptr<!rec_Base>
+    // CHECK: llvm.getelementptr inbounds {{.*}}[-4] : (!llvm.ptr) -> 
!llvm.ptr, i8
+    %derived = cir.derived_class_addr nonnull %base [4] : !cir.ptr<!rec_Base> 
-> !cir.ptr<!rec_Derived>
+    cir.return
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!langptr = !cir.ptr<!s32i, lang_address_space(offload_global)>
+!fn = !cir.func<() -> !langptr>
+!fnptr = !cir.ptr<!fn>
+!fnptrptr = !cir.ptr<!fnptr>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  // CHECK-LABEL: llvm.func @virtual_fn_addr_language_address_space
+  cir.func @virtual_fn_addr_language_address_space(%vptr: !cir.vptr) {
+    // CHECK: llvm.getelementptr {{.*}}[0] : (!llvm.ptr) -> !llvm.ptr, 
!llvm.ptr
+    %0 = cir.vtable.get_virtual_fn_addr %vptr[0] : !cir.vptr -> !fnptrptr
+    cir.return
+  }
+}
diff --git a/clang/test/CIR/Lowering/unlowered-address-spaces.cir 
b/clang/test/CIR/Lowering/unlowered-address-spaces.cir
index 3220e55e24c6d..32a80f537d503 100644
--- a/clang/test/CIR/Lowering/unlowered-address-spaces.cir
+++ b/clang/test/CIR/Lowering/unlowered-address-spaces.cir
@@ -3,6 +3,7 @@
 !s32i = !cir.int<s, 32>
 
 module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}}
   // expected-error @below {{failed to legalize operation 'cir.func'}}
   cir.func @language_address_space(%arg0: !cir.ptr<!s32i, 
lang_address_space(offload_global)>) {
     cir.return
@@ -14,6 +15,7 @@ module attributes {cir.triple = "spirv64-unknown-unknown"} {
 !s32i = !cir.int<s, 32>
 
 module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}}
   // expected-error @below {{failed to legalize operation 'cir.func'}}
   cir.func private @language_address_space_return() -> !cir.ptr<!s32i, 
lang_address_space(offload_global)>
 }
@@ -22,80 +24,6 @@ module attributes {cir.triple = "spirv64-unknown-unknown"} {
 
 !s32i = !cir.int<s, 32>
 
-module attributes {cir.triple = "spirv64-unknown-unknown"} {
-  // expected-error @below {{failed to legalize operation 'cir.func'}}
-  cir.func @nested_language_address_space(%arg0: !cir.ptr<!cir.ptr<!s32i, 
lang_address_space(offload_local)>>) {
-    cir.return
-  }
-}
-
-// -----
-
-!s32i = !cir.int<s, 32>
-
-module attributes {cir.triple = "spirv64-unknown-unknown"} {
-  // expected-error @below {{failed to legalize operation 'cir.func'}}
-  cir.func @function_and_array_language_address_space(
-      %arg0: !cir.ptr<!cir.func<(!cir.ptr<!cir.array<!cir.ptr<!s32i, 
lang_address_space(offload_constant)> x 4>>)>>) {
-    cir.return
-  }
-}
-
-// -----
-
-!s32i = !cir.int<s, 32>
-// Keep walking after the recursive member to find the language address space.
-!rec_Node = !cir.struct<"Node" {data !cir.ptr<!cir.struct<"Node">>, data 
!cir.ptr<!s32i, lang_address_space(offload_global)>}>
-
-module attributes {cir.triple = "spirv64-unknown-unknown"} {
-  // expected-error @below {{failed to legalize operation 'cir.func'}}
-  cir.func @recursive_struct_language_address_space(%arg0: 
!cir.ptr<!rec_Node>) {
-    cir.return
-  }
-}
-
-// -----
-
-!s32i = !cir.int<s, 32>
-!rec_U = !cir.union<"U" {data !s32i, data !cir.ptr<!s32i, 
lang_address_space(offload_global)>}>
-
-module attributes {cir.triple = "spirv64-unknown-unknown"} {
-  // expected-error @below {{failed to legalize operation 'cir.func'}}
-  cir.func @union_language_address_space(%arg0: !cir.ptr<!rec_U>) {
-    cir.return
-  }
-}
-
-// -----
-
-!s32i = !cir.int<s, 32>
-!rec_Foo = !cir.struct<"Foo" {data !s32i}>
-
-module attributes {cir.triple = "spirv64-unknown-unknown"} {
-  // expected-error @below {{failed to legalize operation 'cir.func'}}
-  cir.func @data_member_language_address_space(
-      %arg0: !cir.ptr<!cir.data_member<!cir.ptr<!s32i, 
lang_address_space(offload_global)> in !rec_Foo>>) {
-    cir.return
-  }
-}
-
-// -----
-
-!s32i = !cir.int<s, 32>
-!rec_Foo = !cir.struct<"Foo" {data !s32i}>
-
-module attributes {cir.triple = "spirv64-unknown-unknown"} {
-  // expected-error @below {{failed to legalize operation 'cir.func'}}
-  cir.func @method_language_address_space(
-      %arg0: !cir.ptr<!cir.method<!cir.func<(!cir.ptr<!s32i, 
lang_address_space(offload_global)>)> in !rec_Foo>>) {
-    cir.return
-  }
-}
-
-// -----
-
-!s32i = !cir.int<s, 32>
-
 module attributes {cir.triple = "spirv64-unknown-unknown"} {
   // expected-error @below {{cannot lower a global with a language address 
space}}
   // expected-error @below {{failed to legalize operation 'cir.global'}}
@@ -123,6 +51,7 @@ module attributes {cir.triple = "spirv64-unknown-unknown"} {
   // conversion before its referenced function is lowered.
   cir.global external @function_pointer = 
#cir.global_view<@global_view_callee> : !cir.ptr<!cir.void>
 
+  // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}}
   // expected-error @below {{failed to legalize operation 'cir.func'}}
   cir.func private @global_view_callee() -> !cir.ptr<!s32i, 
lang_address_space(offload_global)>
 }
@@ -135,6 +64,7 @@ module attributes {cir.triple = "spirv64-unknown-unknown"} {
 
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   // Keep the view before its target so the initializer is lowered first.
+  // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.array<!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> x 1>' 
for symbol @target}}
   // expected-error @below {{failed to legalize operation 'cir.global'}}
   cir.global external @view = #cir.global_view<@target, [0 : i32]> : 
!cir.ptr<!cir.void>
 
@@ -150,6 +80,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
 
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   // Lower the view before its target, including through enclosing attributes.
+  // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.array<!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> x 1>' 
for symbol @target}}
   // expected-error @below {{failed to legalize operation 'cir.global'}}
   cir.global external @view = #cir.const_array<[#cir.global_view<@target, [0 : 
i32]> : !ptr]> : !ptrarray
 
@@ -165,6 +96,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
 
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   // Lower the view before its target, including through enclosing attributes.
+  // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.array<!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> x 1>' 
for symbol @target}}
   // expected-error @below {{failed to legalize operation 'cir.global'}}
   cir.global external @view = #cir.const_record<{#cir.global_view<@target, [0 
: i32]> : !ptr}> : !record
 
@@ -180,6 +112,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} 
{
 
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   // Lower the view before its target, including through enclosing attributes.
+  // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.array<!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> x 1>' 
for symbol @target}}
   // expected-error @below {{failed to legalize operation 'cir.global'}}
   cir.global external @view = #cir.typeinfo<{#cir.global_view<@target, [0 : 
i32]> : !ptr}> : !record
 
@@ -196,6 +129,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} 
{
 
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   // Lower the view before its target, including through enclosing attributes.
+  // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.array<!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> x 1>' 
for symbol @target}}
   // expected-error @below {{failed to legalize operation 'cir.global'}}
   cir.global external @view = 
#cir.vtable<{#cir.const_array<[#cir.global_view<@target, [0 : i32]> : !ptr]> : 
!ptrarray}> : !vtable
 
@@ -209,6 +143,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} 
{
 module attributes {cir.triple = "spirv64-unknown-unknown"} {
   // Keep the function before the global so get_global is lowered first.
   cir.func @get_global_language_address_space() {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}}
     // expected-error @below {{failed to legalize operation 'cir.get_global'}}
     %0 = cir.get_global @global : !cir.ptr<!s32i, 
lang_address_space(offload_global)>
     %1 = cir.load %0 : !cir.ptr<!s32i, lang_address_space(offload_global)>, 
!s32i
@@ -224,6 +159,7 @@ module attributes {cir.triple = "spirv64-unknown-unknown"} {
 
 module attributes {cir.triple = "spirv64-unknown-unknown"} {
   cir.func @alloca_language_address_space() {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_private)>'}}
     // expected-error @below {{failed to legalize operation 'cir.alloca'}}
     %0 = cir.alloca "x" align(4) : !cir.ptr<!s32i, 
lang_address_space(offload_private)>
     cir.return
@@ -232,10 +168,56 @@ module attributes {cir.triple = 
"spirv64-unknown-unknown"} {
 
 // -----
 
+!s32i = !cir.int<s, 32>
+!langptr = !cir.ptr<!s32i, lang_address_space(offload_global)>
+
+module attributes {cir.triple = "spirv64-unknown-unknown"} {
+  // The argument lowers to an opaque pointer, but the load needs the inner 
type.
+  cir.func @load_language_address_space(%ptr: !cir.ptr<!langptr>) {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}}
+    // expected-error @below {{failed to legalize operation 'cir.load'}}
+    %0 = cir.load %ptr : !cir.ptr<!langptr>, !langptr
+    cir.return
+  }
+}
+
+// -----
+
+!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_local)>
+
+module attributes {cir.triple = "amdgcn-amd-amdhsa", llvm.data_layout = 
"e-p:64:64-p3:32:32"} {
+  // The copy needs the local pointer's layout, not the outer opaque pointer's.
+  // The default pointer layout would incorrectly copy 8 bytes with alignment 
8.
+  cir.func @copy_language_address_space(%src: !cir.ptr<!langptr>, %dst: 
!cir.ptr<!langptr>) {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_local)>'}}
+    // expected-error @below {{failed to legalize operation 'cir.copy'}}
+    cir.copy %src to %dst : !cir.ptr<!langptr>
+    cir.return
+  }
+}
+
+// -----
+
+!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_local)>
+!record = !cir.struct<{data !langptr}>
+
+module attributes {cir.triple = "amdgcn-amd-amdhsa", llvm.data_layout = 
"e-p:64:64-p3:32:32"} {
+  // Validate the copied layout through aggregate members as well.
+  cir.func @copy_record_language_address_space(%src: !cir.ptr<!record>, %dst: 
!cir.ptr<!record>) {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.struct<{data !cir.ptr<!cir.int<s, 32>, 
lang_address_space(offload_local)>}>'}}
+    // expected-error @below {{failed to legalize operation 'cir.copy'}}
+    cir.copy %src to %dst : !cir.ptr<!record>
+    cir.return
+  }
+}
+
+// -----
+
 !s32i = !cir.int<s, 32>
 
 module attributes {cir.triple = "spirv64-unknown-unknown"} {
   cir.func @null_constant_language_address_space() {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}}
     // expected-error @below {{failed to legalize operation 'cir.const'}}
     %0 = cir.const #cir.ptr<null> : !cir.ptr<!s32i, 
lang_address_space(offload_global)>
     cir.return
@@ -251,6 +233,7 @@ module attributes {cir.triple = "spirv64-unknown-unknown"} {
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   // Lower the view before its target, including through enclosing attributes.
   cir.func @constant_global_view_language_address_space() {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.array<!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> x 1>' 
for symbol @target}}
     // expected-error @below {{failed to legalize operation 'cir.const'}}
     %0 = cir.const #cir.global_view<@target, [0 : i32]> : !ptr
     cir.return
@@ -268,6 +251,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} 
{
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   // Lower the view before its target, including through enclosing attributes.
   cir.func @constant_array_global_view_language_address_space() {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.array<!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> x 1>' 
for symbol @target}}
     // expected-error @below {{failed to legalize operation 'cir.const'}}
     %0 = cir.const #cir.const_array<[#cir.global_view<@target, [0 : i32]> : 
!ptr]> : !cir.array<!ptr x 1>
     cir.return
@@ -285,6 +269,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} 
{
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   // Lower the view before its target, including through enclosing attributes.
   cir.func @constant_record_global_view_language_address_space() {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.array<!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> x 1>' 
for symbol @target}}
     // expected-error @below {{failed to legalize operation 'cir.const'}}
     %0 = cir.const #cir.const_record<{#cir.global_view<@target, [0 : i32]> : 
!ptr}> : !cir.struct<{data !ptr}>
     cir.return
@@ -345,6 +330,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} 
{
 
 module attributes {cir.triple = "spirv64-unknown-unknown"} {
   cir.func @int_to_ptr_language_address_space(%arg0: !s32i) {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}}
     // expected-error @below {{failed to legalize operation 'cir.cast'}}
     %0 = cir.cast int_to_ptr %arg0 : !s32i -> !cir.ptr<!s32i, 
lang_address_space(offload_global)>
     cir.return
@@ -357,6 +343,7 @@ module attributes {cir.triple = "spirv64-unknown-unknown"} {
 
 module attributes {cir.triple = "spirv64-unknown-unknown"} {
   cir.func @address_space_cast_language_address_space(%arg0: !cir.ptr<!s32i>) {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}}
     // expected-error @below {{failed to legalize operation 'cir.cast'}}
     %0 = cir.cast address_space %arg0 : !cir.ptr<!s32i> -> !cir.ptr<!s32i, 
lang_address_space(offload_global)>
     cir.return
@@ -365,15 +352,75 @@ module attributes {cir.triple = 
"spirv64-unknown-unknown"} {
 
 // -----
 
+// These operations need the pointee layout to build a GEP.
+!s32i = !cir.int<s, 32>
+!langptr = !cir.ptr<!s32i, lang_address_space(offload_global)>
+!array = !cir.array<!langptr x 4>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  cir.func @array_decay_language_address_space(%ptr: !cir.ptr<!array>) {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}}
+    // expected-error @below {{failed to legalize operation 'cir.cast'}}
+    %0 = cir.cast array_to_ptrdecay %ptr : !cir.ptr<!array> -> 
!cir.ptr<!langptr>
+    cir.return
+  }
+}
+
+// -----
+
 !s32i = !cir.int<s, 32>
-!rec_Base = !cir.struct<"Base" {data !s32i}>
-!rec_Derived = !cir.struct<"Derived" {data !cir.ptr<!s32i, 
lang_address_space(offload_global)>, data !rec_Base}>
+!langptr = !cir.ptr<!s32i, lang_address_space(offload_global)>
 
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
-  cir.func @derived_class_addr_language_address_space() {
-    %base = cir.alloca "base" align(4) : !cir.ptr<!rec_Base>
-    // expected-error @below {{failed to legalize operation 
'cir.derived_class_addr'}}
-    %derived = cir.derived_class_addr nonnull %base [4] : !cir.ptr<!rec_Base> 
-> !cir.ptr<!rec_Derived>
+  cir.func @ptr_stride_language_address_space(%ptr: !cir.ptr<!langptr>, %idx: 
!s32i) {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}}
+    // expected-error @below {{failed to legalize operation 'cir.ptr_stride'}}
+    %0 = cir.ptr_stride %ptr, %idx : (!cir.ptr<!langptr>, !s32i) -> 
!cir.ptr<!langptr>
+    cir.return
+  }
+}
+
+// -----
+
+!s64i = !cir.int<s, 64>
+!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_local)>
+
+module attributes {cir.triple = "amdgcn-amd-amdhsa", llvm.data_layout = 
"e-p:64:64-p3:32:32"} {
+  // Pointer differences must not divide by the default 8-byte pointer size.
+  cir.func @ptr_diff_language_address_space(%lhs: !cir.ptr<!langptr>, %rhs: 
!cir.ptr<!langptr>) -> !s64i {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_local)>'}}
+    // expected-error @below {{failed to legalize operation 'cir.ptr_diff'}}
+    %diff = cir.ptr_diff %lhs, %rhs : !cir.ptr<!langptr> -> !s64i
+    cir.return %diff : !s64i
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!langptr = !cir.ptr<!s32i, lang_address_space(offload_global)>
+!array = !cir.array<!langptr x 4>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  cir.func @get_element_language_address_space(%ptr: !cir.ptr<!array>, %idx: 
!s32i) {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.array<!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> x 
4>'}}
+    // expected-error @below {{failed to legalize operation 'cir.get_element'}}
+    %0 = cir.get_element %ptr[%idx : !s32i] : !cir.ptr<!array> -> 
!cir.ptr<!langptr>
+    cir.return
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!langptr = !cir.ptr<!s32i, lang_address_space(offload_global)>
+!record = !cir.struct<{data !langptr}>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  cir.func @get_member_language_address_space(%ptr: !cir.ptr<!record>) {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.struct<{data !cir.ptr<!cir.int<s, 32>, 
lang_address_space(offload_global)>}>'}}
+    // expected-error @below {{failed to legalize operation 'cir.get_member'}}
+    %0 = cir.get_member %ptr[0] {name = "p"} : !cir.ptr<!record> -> 
!cir.ptr<!langptr>
     cir.return
   }
 }
@@ -382,6 +429,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} 
{
 
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   cir.func @complex_real_ptr_language_address_space(%ptr: 
!cir.ptr<!cir.complex<!cir.double>>) {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.ptr<!cir.double, lang_address_space(offload_private)>'}}
     // expected-error @below {{failed to legalize operation 
'cir.complex.real_ptr'}}
     %real = cir.complex.real_ptr %ptr : !cir.ptr<!cir.complex<!cir.double>> -> 
!cir.ptr<!cir.double, lang_address_space(offload_private)>
     cir.return
@@ -392,6 +440,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} 
{
 
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   cir.func @complex_imag_ptr_language_address_space(%ptr: 
!cir.ptr<!cir.complex<!cir.double>>) {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.ptr<!cir.double, lang_address_space(offload_private)>'}}
     // expected-error @below {{failed to legalize operation 
'cir.complex.imag_ptr'}}
     %imag = cir.complex.imag_ptr %ptr : !cir.ptr<!cir.complex<!cir.double>> -> 
!cir.ptr<!cir.double, lang_address_space(offload_private)>
     cir.return
@@ -406,6 +455,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} 
{
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   // Lower the address point before its referenced global.
   cir.func @vtable_symbol_language_address_space() {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.struct<{data !cir.array<!cir.ptr<!cir.int<s, 32>, 
lang_address_space(offload_global)> x 1>}>' for vtable symbol @target}}
     // expected-error @below {{failed to legalize operation 
'cir.vtable.address_point'}}
     %0 = cir.vtable.address_point(@target, address_point = <index = 0, offset 
= 0>) : !cir.vptr
     cir.return
@@ -416,25 +466,10 @@ module attributes {cir.triple = 
"x86_64-unknown-linux-gnu"} {
 
 // -----
 
-!s32i = !cir.int<s, 32>
-!langptr = !cir.ptr<!s32i, lang_address_space(offload_global)>
-!fn = !cir.func<() -> !langptr>
-!fnptr = !cir.ptr<!fn>
-!fnptrptr = !cir.ptr<!fnptr>
-
-module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
-  cir.func @virtual_fn_addr_language_address_space(%vptr: !cir.vptr) {
-    // expected-error @below {{failed to legalize operation 
'cir.vtable.get_virtual_fn_addr'}}
-    %0 = cir.vtable.get_virtual_fn_addr %vptr[0] : !cir.vptr -> !fnptrptr
-    cir.return
-  }
-}
-
-// -----
-
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   cir.func @vtt_address_point_language_address_space(
       %vtt: !cir.ptr<!cir.ptr<!cir.void>>) {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.ptr<!cir.ptr<!cir.void>, lang_address_space(offload_global)>'}}
     // expected-error @below {{failed to legalize operation 
'cir.vtt.address_point'}}
     %0 = cir.vtt.address_point %vtt : !cir.ptr<!cir.ptr<!cir.void>>, offset = 
1 -> !cir.ptr<!cir.ptr<!cir.void>, lang_address_space(offload_global)>
     cir.return
@@ -450,6 +485,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} 
{
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   // Lower the address point before its referenced global.
   cir.func @vtt_symbol_language_address_space() {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.array<!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> x 1>' 
for vtable symbol @target}}
     // expected-error @below {{failed to legalize operation 
'cir.vtt.address_point'}}
     %0 = cir.vtt.address_point @target, offset = 0 -> !cir.ptr<!ptr>
     cir.return
@@ -466,6 +502,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} 
{
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   cir.func @frame_address_language_address_space() {
     %level = cir.const #cir.int<0> : !u32i
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.ptr<!cir.int<u, 8>, lang_address_space(offload_global)>'}}
     // expected-error @below {{failed to legalize operation 
'cir.frame_address'}}
     %0 = cir.frame_address(%level) : !cir.ptr<!u8i, 
lang_address_space(offload_global)>
     cir.return
@@ -478,6 +515,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} 
{
 
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   cir.func @address_of_return_address_language_address_space() {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.ptr<!cir.int<u, 8>, lang_address_space(offload_global)>'}}
     // expected-error @below {{failed to legalize operation 
'cir.address_of_return_address'}}
     %0 = cir.address_of_return_address : !cir.ptr<!u8i, 
lang_address_space(offload_global)>
     cir.return
@@ -490,6 +528,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} 
{
 
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   cir.func @stacksave_language_address_space() {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.ptr<!cir.int<u, 8>, lang_address_space(offload_global)>'}}
     // expected-error @below {{failed to legalize operation 'cir.stacksave'}}
     %0 = cir.stacksave : !cir.ptr<!u8i, lang_address_space(offload_global)>
     cir.return
@@ -502,6 +541,7 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} 
{
 
 module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
   cir.func @inline_asm_language_address_space() {
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}}
     // expected-error @below {{failed to legalize operation 'cir.asm'}}
     %0 = cir.asm(x86_att,
       out = [],
@@ -511,3 +551,18 @@ module attributes {cir.triple = 
"x86_64-unknown-linux-gnu"} {
     cir.return
   }
 }
+
+// -----
+
+!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  // Memory operands require an LLVM elementtype attribute for the pointee.
+  cir.func @inline_asm_memory_language_address_space(%ptr: !cir.ptr<!langptr>) 
{
+    // expected-error @below {{ClangIR lowering NYI: cannot convert 
'!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}}
+    // expected-error @below {{failed to legalize operation 'cir.asm'}}
+    cir.asm(x86_att, out = [], in = [%ptr : !cir.ptr<!langptr> (maybe_memory)],
+      in_out = [], {"" "*m"}) side_effects
+    cir.return
+  }
+}
diff --git a/clang/utils/TableGen/CIRLoweringEmitter.cpp 
b/clang/utils/TableGen/CIRLoweringEmitter.cpp
index 62a2411c66c0f..46a8dd8bd6ba0 100644
--- a/clang/utils/TableGen/CIRLoweringEmitter.cpp
+++ b/clang/utils/TableGen/CIRLoweringEmitter.cpp
@@ -240,7 +240,8 @@ void GenerateLLVMLoweringPattern(llvm::StringRef OpName,
       Code << "    mlir::Type resTy = "
               "typeConverter->convertType(op.getType());\n";
       Code << "    if (!resTy)\n";
-      Code << "      return mlir::failure();\n";
+      Code << "      return op.emitError() << \"ClangIR lowering NYI: cannot "
+              "convert \" << op.getType();\n";
       Code << "    rewriter.replaceOpWithNewOp<mlir::LLVM::" << LLVMOp
            << ">(op, mlir::TypeRange{resTy}, adaptor.getOperands(), "
            << Properties << ");\n";

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

Reply via email to