Skip to content

Commit 6aeae62

Browse files
authored
[CIR] Upstream global initialization for ArrayType (#131657)
This change adds global initialization for ArrayType Issue #130197
1 parent a810141 commit 6aeae62

File tree

13 files changed

+457
-67
lines changed

13 files changed

+457
-67
lines changed

clang/include/clang/CIR/Dialect/IR/CIRAttrs.td

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,48 @@ def FPAttr : CIR_Attr<"FP", "fp", [TypedAttrInterface]> {
154154
}];
155155
}
156156

157+
158+
//===----------------------------------------------------------------------===//
159+
// ConstArrayAttr
160+
//===----------------------------------------------------------------------===//
161+
162+
def ConstArrayAttr : CIR_Attr<"ConstArray", "const_array", [TypedAttrInterface]> {
163+
let summary = "A constant array from ArrayAttr or StringRefAttr";
164+
let description = [{
165+
An CIR array attribute is an array of literals of the specified attr types.
166+
}];
167+
168+
let parameters = (ins AttributeSelfTypeParameter<"">:$type,
169+
"mlir::Attribute":$elts,
170+
"int":$trailingZerosNum);
171+
172+
// Define a custom builder for the type; that removes the need to pass
173+
// in an MLIRContext instance, as it can be infered from the `type`.
174+
let builders = [
175+
AttrBuilderWithInferredContext<(ins "cir::ArrayType":$type,
176+
"mlir::Attribute":$elts), [{
177+
int zeros = 0;
178+
auto typeSize = mlir::cast<cir::ArrayType>(type).getSize();
179+
if (auto str = mlir::dyn_cast<mlir::StringAttr>(elts))
180+
zeros = typeSize - str.size();
181+
else
182+
zeros = typeSize - mlir::cast<mlir::ArrayAttr>(elts).size();
183+
184+
return $_get(type.getContext(), type, elts, zeros);
185+
}]>
186+
];
187+
188+
// Printing and parsing available in CIRDialect.cpp
189+
let hasCustomAssemblyFormat = 1;
190+
191+
// Enable verifier.
192+
let genVerifyDecl = 1;
193+
194+
let extraClassDeclaration = [{
195+
bool hasTrailingZeros() const { return getTrailingZerosNum() != 0; };
196+
}];
197+
}
198+
157199
//===----------------------------------------------------------------------===//
158200
// ConstPtrAttr
159201
//===----------------------------------------------------------------------===//

clang/lib/CIR/CodeGen/CIRGenBuilder.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,42 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
4545
return false;
4646
}
4747

48+
// Return true if the value is a null constant such as null pointer, (+0.0)
49+
// for floating-point or zero initializer
50+
bool isNullValue(mlir::Attribute attr) const {
51+
if (mlir::isa<cir::ZeroAttr>(attr))
52+
return true;
53+
54+
if (const auto ptrVal = mlir::dyn_cast<cir::ConstPtrAttr>(attr))
55+
return ptrVal.isNullValue();
56+
57+
if (const auto intVal = mlir::dyn_cast<cir::IntAttr>(attr))
58+
return intVal.isNullValue();
59+
60+
if (const auto boolVal = mlir::dyn_cast<cir::BoolAttr>(attr))
61+
return !boolVal.getValue();
62+
63+
if (auto fpAttr = mlir::dyn_cast<cir::FPAttr>(attr)) {
64+
auto fpVal = fpAttr.getValue();
65+
bool ignored;
66+
llvm::APFloat fv(+0.0);
67+
fv.convert(fpVal.getSemantics(), llvm::APFloat::rmNearestTiesToEven,
68+
&ignored);
69+
return fv.bitwiseIsEqual(fpVal);
70+
}
71+
72+
if (const auto arrayVal = mlir::dyn_cast<cir::ConstArrayAttr>(attr)) {
73+
if (mlir::isa<mlir::StringAttr>(arrayVal.getElts()))
74+
return false;
75+
for (const auto elt : mlir::cast<mlir::ArrayAttr>(arrayVal.getElts())) {
76+
if (!isNullValue(elt))
77+
return false;
78+
}
79+
return true;
80+
}
81+
return false;
82+
}
83+
4884
bool isInt(mlir::Type i) { return mlir::isa<cir::IntType>(i); }
4985

5086
// Creates constant nullptr for pointer type ty.

clang/lib/CIR/CodeGen/CIRGenConstantEmitter.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
#include "CIRGenFunction.h"
2222
#include "CIRGenModule.h"
23-
#include "llvm/ADT/SmallVector.h"
2423

2524
namespace clang::CIRGen {
2625

@@ -41,6 +40,9 @@ class ConstantEmitter {
4140
/// block addresses or PredefinedExprs.
4241
ConstantEmitter(CIRGenFunction &cgf) : cgm(cgf.cgm), cgf(&cgf) {}
4342

43+
ConstantEmitter(CIRGenModule &cgm, CIRGenFunction *cgf = nullptr)
44+
: cgm(cgm), cgf(cgf) {}
45+
4446
ConstantEmitter(const ConstantEmitter &other) = delete;
4547
ConstantEmitter &operator=(const ConstantEmitter &other) = delete;
4648

@@ -66,7 +68,7 @@ class ConstantEmitter {
6668
mlir::Attribute emitAbstract(SourceLocation loc, const APValue &value,
6769
QualType t);
6870

69-
mlir::Attribute tryEmitConstantExpr(const ConstantExpr *CE);
71+
mlir::Attribute tryEmitConstantExpr(const ConstantExpr *ce);
7072

7173
// These are private helper routines of the constant emitter that
7274
// can't actually be private because things are split out into helper

clang/lib/CIR/CodeGen/CIRGenDecl.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,6 @@ void CIRGenFunction::emitScalarInit(const Expr *init, mlir::Location loc,
225225
}
226226
assert(!cir::MissingFeatures::emitNullabilityCheck());
227227
emitStoreThroughLValue(RValue::get(value), lvalue, true);
228-
return;
229228
}
230229

231230
void CIRGenFunction::emitExprAsInit(const Expr *init, const ValueDecl *d,

clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp

Lines changed: 115 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,63 @@ class ConstExprEmitter
158158

159159
// TODO(cir): this can be shared with LLVM's codegen
160160
static QualType getNonMemoryType(CIRGenModule &cgm, QualType type) {
161-
if (auto at = type->getAs<AtomicType>()) {
161+
if (const auto *at = type->getAs<AtomicType>()) {
162162
return cgm.getASTContext().getQualifiedType(at->getValueType(),
163163
type.getQualifiers());
164164
}
165165
return type;
166166
}
167167

168+
static mlir::Attribute
169+
emitArrayConstant(CIRGenModule &cgm, mlir::Type desiredType,
170+
mlir::Type commonElementType, unsigned arrayBound,
171+
SmallVectorImpl<mlir::TypedAttr> &elements,
172+
mlir::TypedAttr filler) {
173+
const CIRGenBuilderTy &builder = cgm.getBuilder();
174+
175+
unsigned nonzeroLength = arrayBound;
176+
if (elements.size() < nonzeroLength && builder.isNullValue(filler))
177+
nonzeroLength = elements.size();
178+
179+
if (nonzeroLength == elements.size()) {
180+
while (nonzeroLength > 0 &&
181+
builder.isNullValue(elements[nonzeroLength - 1]))
182+
--nonzeroLength;
183+
}
184+
185+
if (nonzeroLength == 0)
186+
return cir::ZeroAttr::get(builder.getContext(), desiredType);
187+
188+
const unsigned trailingZeroes = arrayBound - nonzeroLength;
189+
190+
// Add a zeroinitializer array filler if we have lots of trailing zeroes.
191+
if (trailingZeroes >= 8) {
192+
assert(elements.size() >= nonzeroLength &&
193+
"missing initializer for non-zero element");
194+
} else if (elements.size() != arrayBound) {
195+
elements.resize(arrayBound, filler);
196+
197+
if (filler.getType() != commonElementType)
198+
commonElementType = {};
199+
}
200+
201+
if (commonElementType) {
202+
SmallVector<mlir::Attribute, 4> eles;
203+
eles.reserve(elements.size());
204+
205+
for (const auto &element : elements)
206+
eles.push_back(element);
207+
208+
return cir::ConstArrayAttr::get(
209+
cir::ArrayType::get(builder.getContext(), commonElementType,
210+
arrayBound),
211+
mlir::ArrayAttr::get(builder.getContext(), eles));
212+
}
213+
214+
cgm.errorNYI("array with different type elements");
215+
return {};
216+
}
217+
168218
//===----------------------------------------------------------------------===//
169219
// ConstantEmitter
170220
//===----------------------------------------------------------------------===//
@@ -271,16 +321,57 @@ mlir::Attribute ConstantEmitter::tryEmitPrivate(const APValue &value,
271321
cgm.getASTContext().getTargetInfo().useFP16ConversionIntrinsics()) {
272322
cgm.errorNYI("ConstExprEmitter::tryEmitPrivate half");
273323
return {};
274-
} else {
275-
mlir::Type ty = cgm.convertType(destType);
276-
assert(mlir::isa<cir::CIRFPTypeInterface>(ty) &&
277-
"expected floating-point type");
278-
return cgm.getBuilder().getAttr<cir::FPAttr>(ty, init);
279324
}
325+
326+
mlir::Type ty = cgm.convertType(destType);
327+
assert(mlir::isa<cir::CIRFPTypeInterface>(ty) &&
328+
"expected floating-point type");
329+
return cgm.getBuilder().getAttr<cir::FPAttr>(ty, init);
280330
}
281331
case APValue::Array: {
282-
cgm.errorNYI("ConstExprEmitter::tryEmitPrivate array");
283-
return {};
332+
const ArrayType *arrayTy = cgm.getASTContext().getAsArrayType(destType);
333+
const QualType arrayElementTy = arrayTy->getElementType();
334+
const unsigned numElements = value.getArraySize();
335+
const unsigned numInitElts = value.getArrayInitializedElts();
336+
337+
mlir::Attribute filler;
338+
if (value.hasArrayFiller()) {
339+
filler = tryEmitPrivate(value.getArrayFiller(), arrayElementTy);
340+
if (!filler)
341+
return {};
342+
}
343+
344+
SmallVector<mlir::TypedAttr, 16> elements;
345+
if (filler && builder.isNullValue(filler))
346+
elements.reserve(numInitElts + 1);
347+
else
348+
elements.reserve(numInitElts);
349+
350+
mlir::Type commonElementType;
351+
for (unsigned i = 0; i < numInitElts; ++i) {
352+
const APValue &arrayElement = value.getArrayInitializedElt(i);
353+
const mlir::Attribute element =
354+
tryEmitPrivateForMemory(arrayElement, arrayElementTy);
355+
if (!element)
356+
return {};
357+
358+
const mlir::TypedAttr elementTyped = mlir::cast<mlir::TypedAttr>(element);
359+
if (i == 0)
360+
commonElementType = elementTyped.getType();
361+
else if (elementTyped.getType() != commonElementType) {
362+
commonElementType = {};
363+
}
364+
365+
elements.push_back(elementTyped);
366+
}
367+
368+
mlir::TypedAttr typedFiller = llvm::cast_or_null<mlir::TypedAttr>(filler);
369+
if (filler && !typedFiller)
370+
cgm.errorNYI("array filler should always be typed");
371+
372+
mlir::Type desiredType = cgm.convertType(destType);
373+
return emitArrayConstant(cgm, desiredType, commonElementType, numElements,
374+
elements, typedFiller);
284375
}
285376
case APValue::Vector: {
286377
cgm.errorNYI("ConstExprEmitter::tryEmitPrivate vector");
@@ -290,9 +381,23 @@ mlir::Attribute ConstantEmitter::tryEmitPrivate(const APValue &value,
290381
cgm.errorNYI("ConstExprEmitter::tryEmitPrivate member pointer");
291382
return {};
292383
}
293-
case APValue::LValue:
294-
cgm.errorNYI("ConstExprEmitter::tryEmitPrivate lvalue");
384+
case APValue::LValue: {
385+
386+
if (value.getLValueBase()) {
387+
cgm.errorNYI("non-null pointer initialization");
388+
} else {
389+
390+
mlir::Type desiredType = cgm.convertType(destType);
391+
if (const cir::PointerType ptrType =
392+
mlir::dyn_cast<cir::PointerType>(desiredType)) {
393+
return builder.getConstPtrAttr(ptrType,
394+
value.getLValueOffset().getQuantity());
395+
} else {
396+
llvm_unreachable("non-pointer variable initialized with a pointer");
397+
}
398+
}
295399
return {};
400+
}
296401
case APValue::Struct:
297402
case APValue::Union:
298403
cgm.errorNYI("ConstExprEmitter::tryEmitPrivate struct or union");

clang/lib/CIR/CodeGen/CIRGenModule.cpp

Lines changed: 5 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "CIRGenModule.h"
14+
#include "CIRGenConstantEmitter.h"
1415
#include "CIRGenFunction.h"
1516

1617
#include "clang/AST/ASTContext.h"
@@ -128,7 +129,8 @@ void CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd,
128129

129130
void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
130131
bool isTentative) {
131-
mlir::Type type = convertType(vd->getType());
132+
const QualType astTy = vd->getType();
133+
const mlir::Type type = convertType(vd->getType());
132134
if (clang::IdentifierInfo *identifier = vd->getIdentifier()) {
133135
auto varOp = builder.create<cir::GlobalOp>(getLoc(vd->getSourceRange()),
134136
identifier->getName(), type);
@@ -141,38 +143,8 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
141143
if (initExpr) {
142144
mlir::Attribute initializer;
143145
if (APValue *value = initDecl->evaluateValue()) {
144-
switch (value->getKind()) {
145-
case APValue::Int: {
146-
if (mlir::isa<cir::BoolType>(type))
147-
initializer =
148-
builder.getCIRBoolAttr(value->getInt().getZExtValue());
149-
else
150-
initializer = builder.getAttr<cir::IntAttr>(type, value->getInt());
151-
break;
152-
}
153-
case APValue::Float: {
154-
initializer = builder.getAttr<cir::FPAttr>(type, value->getFloat());
155-
break;
156-
}
157-
case APValue::LValue: {
158-
if (value->getLValueBase()) {
159-
errorNYI(initExpr->getSourceRange(),
160-
"non-null pointer initialization");
161-
} else {
162-
if (auto ptrType = mlir::dyn_cast<cir::PointerType>(type)) {
163-
initializer = builder.getConstPtrAttr(
164-
ptrType, value->getLValueOffset().getQuantity());
165-
} else {
166-
llvm_unreachable(
167-
"non-pointer variable initialized with a pointer");
168-
}
169-
}
170-
break;
171-
}
172-
default:
173-
errorNYI(initExpr->getSourceRange(), "unsupported initializer kind");
174-
break;
175-
}
146+
ConstantEmitter emitter(*this);
147+
initializer = emitter.tryEmitPrivateForMemory(*value, astTy);
176148
} else {
177149
errorNYI(initExpr->getSourceRange(), "non-constant initializer");
178150
}

0 commit comments

Comments
 (0)