[clang] [CIR] SubscriptExpr for VariableLengthArray (PR #175370)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Jan 10 09:06:21 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clangir
Author: Amr Hesham (AmrDeveloper)
<details>
<summary>Changes</summary>
Support the SubscriptExpr for VariableLengthArray
---
Full diff: https://github.com/llvm/llvm-project/pull/175370.diff
2 Files Affected:
- (modified) clang/lib/CIR/CodeGen/CIRGenExpr.cpp (+40-12)
- (modified) clang/test/CIR/CodeGen/vla.c (+57-3)
``````````diff
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index cd13498e3702f..0f0e9c67e9dae 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -1128,12 +1128,6 @@ static Address emitArraySubscriptPtr(CIRGenFunction &cgf,
LValue
CIRGenFunction::emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e) {
- if (getContext().getAsVariableArrayType(e->getType())) {
- cgm.errorNYI(e->getSourceRange(),
- "emitArraySubscriptExpr: VariableArrayType");
- return LValue::makeAddr(Address::invalid(), e->getType(), LValueBaseInfo());
- }
-
if (e->getType()->getAs<ObjCObjectType>()) {
cgm.errorNYI(e->getSourceRange(), "emitArraySubscriptExpr: ObjCObjectType");
return LValue::makeAddr(Address::invalid(), e->getType(), LValueBaseInfo());
@@ -1165,7 +1159,14 @@ CIRGenFunction::emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e) {
lv.getBaseInfo());
}
- const mlir::Value idx = emitIdxAfterBase(/*promote=*/true);
+ // The HLSL runtime handles subscript expressions on global resource arrays
+ // and objects with HLSL buffer layouts.
+ if (getLangOpts().HLSL) {
+ cgm.errorNYI(e->getSourceRange(), "emitArraySubscriptExpr: HLSL");
+ return {};
+ }
+
+ mlir::Value idx = emitIdxAfterBase(/*promote=*/true);
// Handle the extvector case we ignored above.
if (isa<ExtVectorElementExpr>(e->getBase())) {
@@ -1181,6 +1182,36 @@ CIRGenFunction::emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e) {
return makeAddrLValue(addr, elementType, lv.getBaseInfo());
}
+ if (const VariableArrayType *vla =
+ getContext().getAsVariableArrayType(e->getType())) {
+ // The base must be a pointer, which is not an aggregate. Emit
+ // it. It needs to be emitted first in case it's what captures
+ // the VLA bounds.
+ Address addr = emitPointerWithAlignment(e->getBase());
+
+ // The element count here is the total number of non-VLA elements.
+ mlir::Value numElements = getVLASize(vla).numElts;
+ idx = builder.createIntCast(idx, numElements.getType());
+
+ // Effectively, the multiply by the VLA size is part of the GEP.
+ // GEP indexes are signed, and scaling an index isn't permitted to
+ // signed-overflow, so we use the same semantics for our explicit
+ // multiply. We suppress this if overflow is not undefined behavior.
+ OverflowBehavior overflowBehavior = getLangOpts().PointerOverflowDefined
+ ? OverflowBehavior::None
+ : OverflowBehavior::NoSignedWrap;
+ idx = builder.createMul(cgm.getLoc(e->getExprLoc()), idx, numElements,
+ overflowBehavior);
+
+ assert(!cir::MissingFeatures::emitCheckedInBoundsGEP());
+ addr = emitArraySubscriptPtr(*this, cgm.getLoc(e->getBeginLoc()),
+ cgm.getLoc(e->getEndLoc()), addr, e->getType(),
+ idx, cgm.getLoc(e->getExprLoc()),
+ /*shouldDecay=*/false);
+
+ return makeAddrLValue(addr, vla->getElementType(), LValueBaseInfo());
+ }
+
if (const Expr *array = getSimpleArrayDecayOperand(e->getBase())) {
LValue arrayLV;
if (const auto *ase = dyn_cast<ArraySubscriptExpr>(array))
@@ -1738,11 +1769,8 @@ LValue CIRGenFunction::emitCompoundLiteralLValue(const CompoundLiteralExpr *e) {
return {};
}
- if (e->getType()->isVariablyModifiedType()) {
- cgm.errorNYI(e->getSourceRange(),
- "emitCompoundLiteralLValue: VariablyModifiedType");
- return {};
- }
+ if (e->getType()->isVariablyModifiedType())
+ emitVariablyModifiedType(e->getType());
Address declPtr = createMemTemp(e->getType(), getLoc(e->getSourceRange()),
".compoundliteral");
diff --git a/clang/test/CIR/CodeGen/vla.c b/clang/test/CIR/CodeGen/vla.c
index 971a7def0db44..ce0cbee11add7 100644
--- a/clang/test/CIR/CodeGen/vla.c
+++ b/clang/test/CIR/CodeGen/vla.c
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
+// RUN: %clang_cc1 -Wno-error=incompatible-pointer-types -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: %clang_cc1 -Wno-error=incompatible-pointer-types -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
+// RUN: %clang_cc1 -Wno-error=incompatible-pointer-types -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
void f0(int len) {
@@ -339,3 +339,57 @@ int f5(unsigned long len) {
// OGCG: %[[STACK_RESTORE_PTR:.*]] = load ptr, ptr %[[SAVED_STACK]]
// OGCG: call void @llvm.stackrestore.p0(ptr %[[STACK_RESTORE_PTR]])
// OGCG: ret i32 %[[ARR_VAL]]
+
+void vla_subscript_expr() {
+ int **a;
+ unsigned long n = 5;
+ (int (**)[n]){&a}[0][1][5] = 0;
+}
+
+// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, ["a"]
+// CIR: %[[N_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["n", init]
+// CIR: %[[COMPOUND_ADDR:.*]] = cir.alloca !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, [".compoundliteral"]
+// CIR: %[[CONST_5:.*]] = cir.const #cir.int<5> : !u64i
+// CIR: cir.store {{.*}} %[[CONST_5]], %[[N_ADDR]] : !u64i, !cir.ptr<!u64i>
+// CIR: %[[CONST_0_VAL:.*]] = cir.const #cir.int<0> : !s32i
+// CIR: %[[CONST_5:.*]] = cir.const #cir.int<5> : !s32i
+// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i
+// CIR: %[[TMP_N:.*]] = cir.load {{.*}} %[[N_ADDR]] : !cir.ptr<!u64i>, !u64i
+// CIR: %[[A_VAL:.*]] = cir.cast bitcast %[[A_ADDR]] : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>> -> !cir.ptr<!cir.ptr<!s32i>>
+// CIR: cir.store {{.*}} %[[A_VAL]], %[[COMPOUND_ADDR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>
+// CIR: %[[TMP_COMPOUND:.*]] = cir.load {{.*}} %[[COMPOUND_ADDR]] : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, !cir.ptr<!cir.ptr<!s32i>>
+// CIR: %[[COMPOUND_PTR:.*]] = cir.ptr_stride %[[TMP_COMPOUND]], %[[CONST_0]] : (!cir.ptr<!cir.ptr<!s32i>>, !s32i) -> !cir.ptr<!cir.ptr<!s32i>>
+// CIR: %[[TMP_COMPOUND:.*]] = cir.load {{.*}} %10 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !u64i
+// CIR: %[[VLA_IDX:.*]] = cir.binop(mul, %[[CONST_1]], %7) nsw : !u64i
+// CIR: %[[VLA_A_PTR:.*]] = cir.ptr_stride %[[TMP_COMPOUND]], %[[VLA_IDX]] : (!cir.ptr<!s32i>, !u64i) -> !cir.ptr<!s32i>
+// CIR: %[[ELEM_5_PTR:.*]] = cir.ptr_stride %[[VLA_A_PTR]], %[[CONST_5]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i>
+// CIR: cir.store {{.*}} %[[CONST_0_VAL]], %[[ELEM_5_PTR]] : !s32i, !cir.ptr<!s32i>
+
+// LLVM: %[[A_ADDR:.*]] = alloca ptr, i64 1, align 8
+// LLVM: %[[N_ADDR:.*]] = alloca i64, i64 1, align 8
+// LLVM: %[[COMPOUND_ADDR:.*]] = alloca ptr, i64 1, align 8
+// LLVM: store i64 5, ptr %[[N_ADDR]], align 8
+// LLVM: %[[TMP_N:.*]] = load i64, ptr %[[N_ADDR]], align 8
+// LLVM: store ptr %[[A_ADDR]], ptr %[[COMPOUND_ADDR]], align 8
+// LLVM: %[[TMP_COMPOUND:.*]] = load ptr, ptr %[[COMPOUND_ADDR]], align 8
+// LLVM: %[[COMPOUND_PTR:.*]] = getelementptr ptr, ptr %[[TMP_COMPOUND]], i64 0
+// LLVM: %[[TMP_COMPOUND:.*]] = load ptr, ptr %[[COMPOUND_PTR]], align 8
+// LLVM: %[[VLA_IDX:.*]] = mul nsw i64 1, %[[TMP_N]]
+// LLVM: %[[VLA_A_PTR:.*]] = getelementptr i32, ptr %[[TMP_COMPOUND]], i64 %[[VLA_IDX]]
+// LLVM: %[[ELEM_5_PTR:.*]] = getelementptr i32, ptr %[[VLA_A_PTR]], i64 5
+// LLVM: store i32 0, ptr %[[ELEM_5_PTR]], align 4
+
+// OGCG: %[[A_ADDR:.*]] = alloca ptr, align 8
+// OGCG: %[[N_ADDR:.*]] = alloca i64, align 8
+// OGCG: %[[COMPOUND_ADDR:.*]] = alloca ptr, align 8
+// OGCG: store i64 5, ptr %[[N_ADDR]], align 8
+// OGCG: %[[TMP_N:.*]] = load i64, ptr %[[N_ADDR]], align 8
+// OGCG: store ptr %[[A_ADDR]], ptr %[[COMPOUND_ADDR]], align 8
+// OGCG: %[[TMP_COMPOUND:.*]] = load ptr, ptr %[[COMPOUND_ADDR]], align 8
+// OGCG: %[[COMPOUND_PTR:.*]] = getelementptr inbounds ptr, ptr %[[TMP_COMPOUND]], i64 0
+// OGCG: %[[TMP_COMPOUND:.*]] = load ptr, ptr %[[COMPOUND_PTR]], align 8
+// OGCG: %[[VLA_IDX:.*]] = mul nsw i64 1, %[[TMP_N]]
+// OGCG: %[[VLA_A_PTR:.*]] = getelementptr inbounds i32, ptr %[[TMP_COMPOUND]], i64 %[[VLA_IDX]]
+// OGCG: %[[ELEM_5_PTR:.*]] = getelementptr inbounds i32, ptr %[[VLA_A_PTR]], i64 5
+// OGCG: store i32 0, ptr %[[ELEM_5_PTR]], align 4
``````````
</details>
https://github.com/llvm/llvm-project/pull/175370
More information about the cfe-commits
mailing list