[clang] [CIR] Handle scalar-type element GEP in GlobalView offset computation (PR #201705)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 9 12:55:59 PDT 2026
https://github.com/adams381 updated https://github.com/llvm/llvm-project/pull/201705
>From 9a7050baeebd30b6032e9d0be90907a54701534c Mon Sep 17 00:00:00 2001
From: Adam Smith <adams at nvidia.com>
Date: Thu, 4 Jun 2026 15:05:37 -0700
Subject: [PATCH 1/2] [CIR] Handle scalar-type element GEP in GlobalView offset
computation
computeGlobalViewIndicesFromFlatOffset navigated into array and record
types to convert a flat byte offset into structured GEP indices, but
fell through to llvm_unreachable("unexpected type") when the pointee
type was scalar (e.g. !s8i for const char *).
This occurs when a constexpr struct is initialized with a pointer field
whose value is a global-string-literal address plus a non-zero byte
offset. Classic CodeGen emits getelementptr i8, ptr @str, i64 N for
this case; CIR represents the same thing as a GlobalViewAttr with
index [N]. getAddrOfConstantStringFromLiteral creates the
GlobalViewAttr with ptr-to-char as the pointee type (not ptr-to-array),
so applyOffset passes a char type to the offset navigator rather than
an array type.
Fix: treat any non-array, non-record pointee type as a scalar element
and compute offset / sizeof(element) as the GEP index, mirroring the
array-element logic. Apply the same fix to the inverse function
computeOffsetFromGlobalViewIndices.
---
clang/lib/CIR/CodeGen/CIRGenBuilder.cpp | 21 +++++++++++-----
.../test/CIR/CodeGen/constexpr-ptr-offset.cpp | 24 +++++++++++++++++++
2 files changed, 39 insertions(+), 6 deletions(-)
create mode 100644 clang/test/CIR/CodeGen/constexpr-ptr-offset.cpp
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp
index c48afa0c7c793..0004bdf35ead5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp
@@ -148,11 +148,19 @@ void CIRGenBuilderTy::computeGlobalViewIndicesFromFlatOffset(
}
llvm_unreachable("offset was not found within the record");
})
- .Default([](mlir::Type otherTy) {
- llvm_unreachable("unexpected type");
- return otherTy; // Even though this is unreachable, we need to
- // return a type to satisfy the return type of the
- // lambda.
+ .Default([&](mlir::Type otherTy) -> mlir::Type {
+ // Scalar or pointer type: the offset is a flat element count.
+ // This covers pointer arithmetic through a plain scalar base, e.g.
+ // a char* GlobalViewAttr whose pointee is !s8i rather than an
+ // array — the generated GEP is getelementptr i8, ptr @sym, i64 N.
+ int64_t eltSize =
+ (int64_t)layout.getTypeAllocSize(otherTy).getFixedValue();
+ assert(eltSize > 0 && "element size must be positive");
+ const auto [index, newOffset] =
+ getIndexAndNewOffset(offset, eltSize);
+ indices.push_back(index);
+ offset = newOffset;
+ return otherTy;
});
assert(subType);
@@ -175,7 +183,8 @@ uint64_t CIRGenBuilderTy::computeOffsetFromGlobalViewIndices(
ty = arrayTy.getElementType();
offset += layout.getTypeAllocSize(ty) * idx;
} else {
- llvm_unreachable("unexpected type");
+ // Scalar or pointer type: the index is a flat element count.
+ offset += (int64_t)layout.getTypeAllocSize(ty).getFixedValue() * idx;
}
}
return offset;
diff --git a/clang/test/CIR/CodeGen/constexpr-ptr-offset.cpp b/clang/test/CIR/CodeGen/constexpr-ptr-offset.cpp
new file mode 100644
index 0000000000000..cbe5fc8467293
--- /dev/null
+++ b/clang/test/CIR/CodeGen/constexpr-ptr-offset.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
+
+struct View {
+ const char *ptr;
+ int len;
+ constexpr View(const char *p, int n) : ptr(p), len(n) {}
+};
+
+constexpr const char *global_str = "hello";
+
+void test() {
+ constexpr View v(global_str + 2, 3);
+ (void)v;
+}
+
+// CIR-LABEL: @_Z4testv
+// CIR: #cir.global_view<@{{.*}}str{{.*}}, [2 : i32]> : !cir.ptr<!s8i>
+
+// LLVM: getelementptr{{.*}}(i8, ptr @{{.*}}str{{.*}}, i64 2)
>From 6ad665af7b96afe220f27dc05caaf98a337cb30d Mon Sep 17 00:00:00 2001
From: Adam Smith <adams at nvidia.com>
Date: Tue, 9 Jun 2026 12:53:49 -0700
Subject: [PATCH 2/2] [CIR] Restrict GlobalView offset default to integers
Address review feedback: the broad TypeSwitch default in
computeGlobalViewIndicesFromFlatOffset treated any non-array, non-record
pointee as a flat element, which silenced the llvm_unreachable guard for
types that should never appear. Replace it with a cir::IntType case and
restore llvm_unreachable for the default.
The only non-aggregate type that reaches the navigator is the integer
element of a string-literal GlobalViewAttr (applyOffset passes the
pointee, and getAddrOfConstantStringFromLiteral builds ptr-to-element
over an always-integral string element), so the integer case is
sufficient and the unreachable stays a real invariant guard. Mirror the
same handling in computeOffsetFromGlobalViewIndices.
---
clang/lib/CIR/CodeGen/CIRGenBuilder.cpp | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp
index 0004bdf35ead5..a562c4b7b763f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp
@@ -148,19 +148,22 @@ void CIRGenBuilderTy::computeGlobalViewIndicesFromFlatOffset(
}
llvm_unreachable("offset was not found within the record");
})
- .Default([&](mlir::Type otherTy) -> mlir::Type {
- // Scalar or pointer type: the offset is a flat element count.
- // This covers pointer arithmetic through a plain scalar base, e.g.
- // a char* GlobalViewAttr whose pointee is !s8i rather than an
- // array — the generated GEP is getelementptr i8, ptr @sym, i64 N.
+ .Case<cir::IntType>([&](cir::IntType intTy) -> mlir::Type {
+ // Integer element type: the offset is a flat element count.
+ // This covers pointer arithmetic through a plain integer base,
+ // e.g. a char* GlobalViewAttr whose pointee type is !s8i rather
+ // than an array — the GEP is getelementptr i8, ptr @sym, i64 N.
int64_t eltSize =
- (int64_t)layout.getTypeAllocSize(otherTy).getFixedValue();
+ (int64_t)layout.getTypeAllocSize(intTy).getFixedValue();
assert(eltSize > 0 && "element size must be positive");
const auto [index, newOffset] =
getIndexAndNewOffset(offset, eltSize);
indices.push_back(index);
offset = newOffset;
- return otherTy;
+ return intTy;
+ })
+ .Default([](mlir::Type) -> mlir::Type {
+ llvm_unreachable("unexpected type");
});
assert(subType);
@@ -182,9 +185,11 @@ uint64_t CIRGenBuilderTy::computeOffsetFromGlobalViewIndices(
} else if (auto arrayTy = dyn_cast<cir::ArrayType>(ty)) {
ty = arrayTy.getElementType();
offset += layout.getTypeAllocSize(ty) * idx;
- } else {
- // Scalar or pointer type: the index is a flat element count.
+ } else if (mlir::isa<cir::IntType>(ty)) {
+ // Integer element type: the index is a flat element count.
offset += (int64_t)layout.getTypeAllocSize(ty).getFixedValue() * idx;
+ } else {
+ llvm_unreachable("unexpected type");
}
}
return offset;
More information about the cfe-commits
mailing list