Skip to content

Commit 18805b6

Browse files
authored
[CIR] CountOf VLA with Array element type (llvm#169404)
Implement CountOf on VariableArrayType with IntegerConstant SizeExpr
1 parent c98e867 commit 18805b6

File tree

4 files changed

+103
-8
lines changed

4 files changed

+103
-8
lines changed

clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2325,14 +2325,45 @@ mlir::Value ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(
23252325
const QualType typeToSize = e->getTypeOfArgument();
23262326
const mlir::Location loc = cgf.getLoc(e->getSourceRange());
23272327
if (auto kind = e->getKind();
2328-
kind == UETT_SizeOf || kind == UETT_DataSizeOf) {
2329-
if (cgf.getContext().getAsVariableArrayType(typeToSize)) {
2330-
cgf.getCIRGenModule().errorNYI(e->getSourceRange(),
2331-
"sizeof operator for VariableArrayType",
2332-
e->getStmtClassName());
2333-
return builder.getConstant(
2334-
loc, cir::IntAttr::get(cgf.cgm.uInt64Ty,
2335-
llvm::APSInt(llvm::APInt(64, 1), true)));
2328+
kind == UETT_SizeOf || kind == UETT_DataSizeOf || kind == UETT_CountOf) {
2329+
if (const VariableArrayType *vat =
2330+
cgf.getContext().getAsVariableArrayType(typeToSize)) {
2331+
// For _Countof, we only want to evaluate if the extent is actually
2332+
// variable as opposed to a multi-dimensional array whose extent is
2333+
// constant but whose element type is variable.
2334+
bool evaluateExtent = true;
2335+
if (kind == UETT_CountOf && vat->getElementType()->isArrayType()) {
2336+
evaluateExtent =
2337+
!vat->getSizeExpr()->isIntegerConstantExpr(cgf.getContext());
2338+
}
2339+
2340+
if (evaluateExtent) {
2341+
if (e->isArgumentType()) {
2342+
// sizeof(type) - make sure to emit the VLA size.
2343+
cgf.emitVariablyModifiedType(typeToSize);
2344+
} else {
2345+
// C99 6.5.3.4p2: If the argument is an expression of type
2346+
// VLA, it is evaluated.
2347+
cgf.getCIRGenModule().errorNYI(
2348+
e->getSourceRange(),
2349+
"sizeof operator for VariableArrayType & evaluateExtent "
2350+
"ignoredExpr",
2351+
e->getStmtClassName());
2352+
return {};
2353+
}
2354+
2355+
// For _Countof, we just want to return the size of a single dimension.
2356+
if (kind == UETT_CountOf)
2357+
return cgf.getVLAElements1D(vat).numElts;
2358+
2359+
cgf.getCIRGenModule().errorNYI(
2360+
e->getSourceRange(),
2361+
"sizeof operator for VariableArrayType & evaluateExtent",
2362+
e->getStmtClassName());
2363+
return builder.getConstant(
2364+
loc, cir::IntAttr::get(cgf.cgm.uInt64Ty,
2365+
-llvm::APSInt(llvm::APInt(64, 1), true)));
2366+
}
23362367
}
23372368
} else if (e->getKind() == UETT_OpenMPRequiredSimdAlign) {
23382369
cgf.getCIRGenModule().errorNYI(

clang/lib/CIR/CodeGen/CIRGenFunction.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,6 +1138,14 @@ CIRGenFunction::getVLASize(const VariableArrayType *type) {
11381138
return {numElements, elementType};
11391139
}
11401140

1141+
CIRGenFunction::VlaSizePair
1142+
CIRGenFunction::getVLAElements1D(const VariableArrayType *vla) {
1143+
mlir::Value vlaSize = vlaSizeMap[vla->getSizeExpr()];
1144+
assert(vlaSize && "no size for VLA!");
1145+
assert(vlaSize->getType() == sizeTy);
1146+
return {vlaSize, vla->getElementType()};
1147+
}
1148+
11411149
// TODO(cir): Most of this function can be shared between CIRGen
11421150
// and traditional LLVM codegen
11431151
void CIRGenFunction::emitVariablyModifiedType(QualType type) {

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,10 @@ class CIRGenFunction : public CIRGenTypeCache {
498498
VlaSizePair(mlir::Value num, QualType ty) : numElts(num), type(ty) {}
499499
};
500500

501+
/// Return the number of elements for a single dimension
502+
/// for the given array type.
503+
VlaSizePair getVLAElements1D(const VariableArrayType *vla);
504+
501505
/// Returns an MLIR::Value+QualType pair that corresponds to the size,
502506
/// in non-variably-sized elements, of a variable length array type,
503507
/// plus that largest non-variably-sized element type. Assumes that

clang/test/CIR/CodeGen/count-of.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// RUN: %clang_cc1 -std=c2y -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
3+
// RUN: %clang_cc1 -std=c2y -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
4+
// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
5+
// RUN: %clang_cc1 -std=c2y -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
6+
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
7+
8+
unsigned long vla_with_array_element_type_with_const_size() {
9+
long size;
10+
return _Countof(int[5][size]);
11+
}
12+
13+
// CIR: %[[RET_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["__retval"]
14+
// CIR: %[[SIZE_ADDR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["size"]
15+
// CIR: %[[CONST_5:.*]] = cir.const #cir.int<5> : !u64i
16+
// CIR: cir.store %[[CONST_5]], %[[RET_ADDR]] : !u64i, !cir.ptr<!u64i>
17+
// CIR: %[[RET_VAL:.*]] = cir.load %[[RET_ADDR]] : !cir.ptr<!u64i>, !u64i
18+
// CIR: cir.return %[[RET_VAL]] : !u64i
19+
20+
// LLVM: %[[RET_ADDR:.*]] = alloca i64, i64 1, align 8
21+
// LLVM: %[[SIZE_ADDR:.*]] = alloca i64, i64 1, align 8
22+
// LLVM: store i64 5, ptr %[[RET_ADDR]], align 8
23+
// LLVM: %[[RET_VAL:.*]] = load i64, ptr %[[RET_ADDR]], align 8
24+
// LLVM: ret i64 %[[RET_VAL]]
25+
26+
// OGCG: %[[SIZE_ADDR:.*]] = alloca i64, align 8
27+
// OGCG: ret i64 5
28+
29+
unsigned long vla_with_array_element_type_non_const_size() {
30+
long size;
31+
return _Countof(int[size][size]);
32+
}
33+
34+
// CIR: %[[REET_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["__retval"]
35+
// CIR: %[[SIZE_ADDR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["size"]
36+
// CIR: %[[TMP_SIZE:.*]] = cir.load {{.*}} %[[SIZE_ADDR]] : !cir.ptr<!s64i>, !s64i
37+
// CIR: %[[TMP_SIZE_U64:.*]] = cir.cast integral %[[TMP_SIZE]] : !s64i -> !u64i
38+
// CIR: cir.store %[[TMP_SIZE_U64]], %[[RET_ADDR]] : !u64i, !cir.ptr<!u64i>
39+
// CIR: %[[TMP_RET:.*]] = cir.load %[[RET_ADDR]] : !cir.ptr<!u64i>, !u64i
40+
// CIR: cir.return %[[TMP_RET]] : !u64i
41+
42+
// LLVM: %[[RET_ADDR:.*]] = alloca i64, i64 1, align 8
43+
// LLVM: %[[SIZE_ADDR:.*]] = alloca i64, i64 1, align 8
44+
// LLVM: %[[TMP_SIZE:.*]] = load i64, ptr %[[SIZE_ADDR]], align 8
45+
// LLVM: store i64 %[[TMP_SIZE]], ptr %[[RET_ADDR]], align 8
46+
// LLVM: %[[TMP_RET:.*]] = load i64, ptr %[[RET_ADDR]], align 8
47+
// LLVM: ret i64 %[[TMP_RET]]
48+
49+
// OGCG: %[[SIZE_ADDR:.*]] = alloca i64, align 8
50+
// OGCG: %[[TMP_SIZE:.*]] = load i64, ptr %[[SIZE_ADDR]], align 8
51+
// OGCG: %[[TMP_SIZE_2:.*]] = load i64, ptr %[[SIZE_ADDR]], align 8
52+
// OGCG: ret i64 %[[TMP_SIZE]]

0 commit comments

Comments
 (0)