[clang] [CIR][CodeGen] Support VLA pointer arithmetic (PR #196837)
via cfe-commits
cfe-commits at lists.llvm.org
Sun May 10 13:30:22 PDT 2026
https://github.com/AbdallahRashed updated https://github.com/llvm/llvm-project/pull/196837
>From 2605f7f71afdcab9b670aace4d19e68c0ef5d993 Mon Sep 17 00:00:00 2001
From: AbdallahRashed <abdallah.mrashed at gmail.com>
Date: Sun, 10 May 2026 22:25:17 +0200
Subject: [PATCH] [CIR][CodeGen] Support VLA pointer arithmetic
Implement pointer arithmetic on variable-length array types in CIR
codegen, removing two NYI diagnostics:
1. Binary pointer arithmetic (p + i, p - i) where the pointee is a VLA:
multiply the index by the runtime VLA size before emitting
PtrStrideOp.
2. Unary increment/decrement (p++, p--) on pointers to VLA types:
stride by the VLA element count, negating for decrement.
Fixes #192318
---
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 24 ++++++---
clang/test/CIR/CodeGen/vla-pointer-arith.c | 62 ++++++++++++++++++++++
2 files changed, 80 insertions(+), 6 deletions(-)
create mode 100644 clang/test/CIR/CodeGen/vla-pointer-arith.c
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 231039ec5da29..2ff20badca655 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -668,10 +668,15 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
}
} else if (const PointerType *ptr = type->getAs<PointerType>()) {
QualType type = ptr->getPointeeType();
- if (cgf.getContext().getAsVariableArrayType(type)) {
+ if (const VariableArrayType *vla =
+ cgf.getContext().getAsVariableArrayType(type)) {
// VLA types don't have constant size.
- cgf.cgm.errorNYI(e->getSourceRange(), "Pointer arithmetic on VLA");
- return {};
+ mlir::Location loc = cgf.getLoc(e->getSourceRange());
+ mlir::Value numElts = cgf.getVLASize(vla).numElts;
+ if (!e->isIncrementOp())
+ numElts = cgf.getBuilder().createNeg(numElts);
+ assert(!cir::MissingFeatures::sanitizers());
+ value = cgf.getBuilder().createPtrStride(loc, value, numElts);
} else {
// For everything else, we can just do a simple increment.
mlir::Location loc = cgf.getLoc(e->getSourceRange());
@@ -1898,9 +1903,16 @@ static mlir::Value emitPointerArithmetic(CIRGenFunction &cgf,
}
QualType elementType = pointerType->getPointeeType();
- if (cgf.getContext().getAsVariableArrayType(elementType)) {
- cgf.cgm.errorNYI("variable array type");
- return nullptr;
+ if (const VariableArrayType *vla =
+ cgf.getContext().getAsVariableArrayType(elementType)) {
+ mlir::Value numElements = cgf.getVLASize(vla).numElts;
+ mlir::Location loc = cgf.getLoc(op.e->getExprLoc());
+ index = cgf.getBuilder().createCast(cir::CastKind::integral, index,
+ numElements.getType());
+ index = cgf.getBuilder().createMul(loc, index, numElements);
+ assert(!cir::MissingFeatures::sanitizers());
+ return cir::PtrStrideOp::create(cgf.getBuilder(), loc, pointer.getType(),
+ pointer, index);
}
assert(!cir::MissingFeatures::sanitizers());
diff --git a/clang/test/CIR/CodeGen/vla-pointer-arith.c b/clang/test/CIR/CodeGen/vla-pointer-arith.c
new file mode 100644
index 0000000000000..aa59031433a78
--- /dev/null
+++ b/clang/test/CIR/CodeGen/vla-pointer-arith.c
@@ -0,0 +1,62 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -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 -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 -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+// Test pointer arithmetic on VLA types.
+
+void test_vla_ptr_add(int n) {
+ int arr[n];
+ int (*p)[n] = &arr;
+ p = p + 1;
+}
+
+// CIR-LABEL: @test_vla_ptr_add
+// CIR: %[[P:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !u64i
+// CIR: %[[SCALED:.*]] = cir.mul %[[ONE]], %{{.*}} : !u64i
+// CIR: cir.ptr_stride %[[P]], %[[SCALED]] : (!cir.ptr<!s32i>, !u64i) -> !cir.ptr<!s32i>
+
+// LLVM-LABEL: @test_vla_ptr_add
+// LLVM: %[[SCALED:.*]] = mul i64 1, %{{.*}}
+// LLVM: %[[RESULT:.*]] = getelementptr i32, ptr %{{.*}}, i64 %[[SCALED]]
+
+// OGCG-LABEL: @test_vla_ptr_add
+// OGCG: getelementptr inbounds i32, ptr %{{.*}}, i64 %{{.*}}
+
+void test_vla_ptr_inc(int n) {
+ int arr[n];
+ int (*p)[n] = &arr;
+ p++;
+}
+
+// CIR-LABEL: @test_vla_ptr_inc
+// CIR: %[[P:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+// CIR: cir.ptr_stride %[[P]], %{{.*}} : (!cir.ptr<!s32i>, !u64i) -> !cir.ptr<!s32i>
+
+// LLVM-LABEL: @test_vla_ptr_inc
+// LLVM: getelementptr i32, ptr %{{.*}}, i64 %{{.*}}
+
+// OGCG-LABEL: @test_vla_ptr_inc
+// OGCG: getelementptr inbounds nuw i32, ptr %{{.*}}, i64 %{{.*}}
+
+void test_vla_ptr_dec(int n) {
+ int arr[n];
+ int (*p)[n] = &arr;
+ p--;
+}
+
+// CIR-LABEL: @test_vla_ptr_dec
+// CIR: %[[P:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+// CIR: %[[SIGNED:.*]] = cir.cast integral %{{.*}} : !u64i -> !s64i
+// CIR: %[[NEG:.*]] = cir.minus %[[SIGNED]] : !s64i
+// CIR: cir.ptr_stride %[[P]], %[[NEG]] : (!cir.ptr<!s32i>, !s64i) -> !cir.ptr<!s32i>
+
+// LLVM-LABEL: @test_vla_ptr_dec
+// LLVM: getelementptr i32, ptr %{{.*}}, i64 %{{.*}}
+
+// OGCG-LABEL: @test_vla_ptr_dec
+// OGCG: getelementptr inbounds i32, ptr %{{.*}}, i64 %{{.*}}
+
More information about the cfe-commits
mailing list