[llvm-branch-commits] [clang] [CIR] Reject language address spaces in DirectToLLVM pointer conversion (PR #224239)
Akimasa Watanuki via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Oct 20 14:51:05 PDT 2026
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 <mencotton0410 at gmail.com>
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 <mencotton0410 at gmail.com>
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";
More information about the llvm-branch-commits
mailing list