[clang] [CIR] Make array decay and get_element op perserve address spaces (PR #192361)
Jan Leyonberg via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 15 17:12:17 PDT 2026
https://github.com/jsjodin created https://github.com/llvm/llvm-project/pull/192361
This patch makes sure that the maybeBuildArrayDecay function takes address spaces into account and makes the get_element op preserve the address space of the base pointer.
Note: In the test case when directly accessing the array the LLVM codegen case preserves addr_space(1), but in OGCG it does not, since it inserts the addrspace cast earlier. This should not be an an issue, I think doing the cast early on made the code generation easier.
Assisted-by: Cursor / claude-4.6-opus-high
>From 649e945bd0393d89299eed29a0c7b9c762f271cc Mon Sep 17 00:00:00 2001
From: Jan Leyonberg <jan_sjodin at yahoo.com>
Date: Wed, 15 Apr 2026 19:48:09 -0400
Subject: [PATCH] [CIR] Make array decay and get_element op perserve address
spaces
This patch makes sure that the maybeBuildArrayDecay functions takes
address spaces into account, and also makes the get_element op preserve
the address space of the base pointer.
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 11 +++-
clang/lib/CIR/CodeGen/CIRGenBuilder.cpp | 3 +-
.../CIR/CodeGen/amdgpu-array-addrspace.cpp | 50 +++++++++++++++++++
3 files changed, 61 insertions(+), 3 deletions(-)
create mode 100644 clang/test/CIR/CodeGen/amdgpu-array-addrspace.cpp
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 6f8db65acccc9..f20ba262d6480 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -3547,8 +3547,9 @@ def CIR_InsertMemberOp : CIR_Op<"insert_member", [
def CIR_GetElementOp : CIR_Op<"get_element", [
TypesMatchWith<
"type of 'result' matches element type of 'base'", "base", "result",
- "cir::PointerType::get(mlir::cast<cir::ArrayType>(mlir::cast<cir::"
- "PointerType>($_self).getPointee()).getElementType())">
+ "cir::PointerType::get("
+ "mlir::cast<cir::ArrayType>(mlir::cast<cir::PointerType>($_self).getPointee()).getElementType(), "
+ "mlir::cast<cir::PointerType>($_self).getAddrSpace())">
]> {
let summary = "Get the address of an array element";
@@ -3557,6 +3558,7 @@ def CIR_GetElementOp : CIR_Op<"get_element", [
from the `base` array.
It expects a pointer to the `base` array and the `index` of the element.
+ The result pointer preserves the address space of the base pointer.
Example:
```
@@ -3571,6 +3573,11 @@ def CIR_GetElementOp : CIR_Op<"get_element", [
%i = ...
%elem_i = cir.get_element %0[%i : !s32i] : !cir.ptr<!array_ty> -> !cir.ptr<!s32i>
+ // With address space (e.g., GPU private memory):
+ %elem_gpu = cir.get_element %gpu_arr[%i : !s32i] :
+ !cir.ptr<!cir.array<!s32i x 10>, target_address_space(5)> ->
+ !cir.ptr<!s32i, target_address_space(5)>
+
```
}];
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp
index 7953a648715b2..0cf35812babe7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp
@@ -21,7 +21,8 @@ mlir::Value CIRGenBuilderTy::maybeBuildArrayDecay(mlir::Location loc,
const auto arrayTy = mlir::dyn_cast<cir::ArrayType>(arrayPtrTy.getPointee());
if (arrayTy) {
- const cir::PointerType flatPtrTy = getPointerTo(arrayTy.getElementType());
+ const cir::PointerType flatPtrTy =
+ getPointerTo(arrayTy.getElementType(), arrayPtrTy.getAddrSpace());
return cir::CastOp::create(*this, loc, flatPtrTy,
cir::CastKind::array_to_ptrdecay, arrayPtr);
}
diff --git a/clang/test/CIR/CodeGen/amdgpu-array-addrspace.cpp b/clang/test/CIR/CodeGen/amdgpu-array-addrspace.cpp
new file mode 100644
index 0000000000000..38b574bd120b5
--- /dev/null
+++ b/clang/test/CIR/CodeGen/amdgpu-array-addrspace.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -fclangir -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+// Test that address spaces are preserved through array-to-pointer decay
+// and array element access on AMDGPU, where globals are in AS 1.
+
+int globalArr[10] = {0};
+
+void takes_ptr(int *p);
+
+// The array_to_ptrdecay cast must preserve the address space of the base
+// pointer, followed by an address_space cast.
+
+// CIR-LABEL: cir.func{{.*}} @_Z17pass_global_arrayv()
+// CIR: %[[ARR:.*]] = cir.get_global @globalArr : !cir.ptr<!cir.array<!s32i x 10>, target_address_space(1)>
+// CIR-NEXT: %[[DECAY:.*]] = cir.cast array_to_ptrdecay %[[ARR]] : !cir.ptr<!cir.array<!s32i x 10>, target_address_space(1)> -> !cir.ptr<!s32i, target_address_space(1)>
+// CIR-NEXT: %[[FLAT:.*]] = cir.cast address_space %[[DECAY]] : !cir.ptr<!s32i, target_address_space(1)> -> !cir.ptr<!s32i>
+// CIR-NEXT: cir.call @_Z9takes_ptrPi(%[[FLAT]])
+
+// LLVM-LABEL: define{{.*}} void @_Z17pass_global_arrayv()
+// LLVM: call void @_Z9takes_ptrPi(ptr noundef addrspacecast (ptr addrspace(1) @globalArr to ptr))
+
+// OGCG-LABEL: define{{.*}} void @_Z17pass_global_arrayv()
+// OGCG: call void @_Z9takes_ptrPi(ptr noundef addrspacecast (ptr addrspace(1) @globalArr to ptr))
+void pass_global_array() {
+ takes_ptr(globalArr);
+}
+
+// The get_element op must preserve the address space of the base pointer
+// so that the subsequent load uses the correct address space.
+
+// CIR-LABEL: cir.func{{.*}} @_Z18index_global_arrayi
+// CIR: %[[ARR:.*]] = cir.get_global @globalArr : !cir.ptr<!cir.array<!s32i x 10>, target_address_space(1)>
+// CIR-NEXT: %[[ELEM:.*]] = cir.get_element %[[ARR]][%{{.*}} : !s32i] : !cir.ptr<!cir.array<!s32i x 10>, target_address_space(1)> -> !cir.ptr<!s32i, target_address_space(1)>
+// CIR-NEXT: %{{.*}} = cir.load align(4) %[[ELEM]] : !cir.ptr<!s32i, target_address_space(1)>, !s32i
+
+// LLVM-LABEL: define{{.*}} i32 @_Z18index_global_arrayi
+// LLVM: %[[GEP:.*]] = getelementptr [10 x i32], ptr addrspace(1) @globalArr, i32 0, i64 %{{.*}}
+// LLVM-NEXT: %{{.*}} = load i32, ptr addrspace(1) %[[GEP]], align 4
+
+// OGCG-LABEL: define{{.*}} i32 @_Z18index_global_arrayi
+// OGCG: getelementptr inbounds [10 x i32], ptr addrspacecast (ptr addrspace(1) @globalArr to ptr)
+// OGCG: load i32, ptr %{{.*}}, align 4
+int index_global_array(int i) {
+ return globalArr[i];
+}
More information about the cfe-commits
mailing list