Skip to content

Commit 4ae9c42

Browse files
committed
[CIR] Upstream global initialization for ArrayType
1 parent e9fc768 commit 4ae9c42

File tree

13 files changed

+453
-67
lines changed

13 files changed

+453
-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: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,40 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
4343
assert(!cir::MissingFeatures::unsizedTypes());
4444
return false;
4545
}
46+
47+
bool isNullValue(mlir::Attribute attr) const {
48+
if (mlir::isa<cir::ZeroAttr>(attr))
49+
return true;
50+
51+
if (const auto ptrVal = mlir::dyn_cast<cir::ConstPtrAttr>(attr))
52+
return ptrVal.isNullValue();
53+
54+
if (const auto intVal = mlir::dyn_cast<cir::IntAttr>(attr))
55+
return intVal.isNullValue();
56+
57+
if (const auto boolVal = mlir::dyn_cast<cir::BoolAttr>(attr))
58+
return !boolVal.getValue();
59+
60+
if (auto fpAttr = mlir::dyn_cast<cir::FPAttr>(attr)) {
61+
auto fpVal = fpAttr.getValue();
62+
bool ignored;
63+
llvm::APFloat fv(+0.0);
64+
fv.convert(fpVal.getSemantics(), llvm::APFloat::rmNearestTiesToEven,
65+
&ignored);
66+
return fv.bitwiseIsEqual(fpVal);
67+
}
68+
69+
if (const auto arrayVal = mlir::dyn_cast<cir::ConstArrayAttr>(attr)) {
70+
if (mlir::isa<mlir::StringAttr>(arrayVal.getElts()))
71+
return false;
72+
for (const auto elt : mlir::cast<mlir::ArrayAttr>(arrayVal.getElts())) {
73+
if (!isNullValue(elt))
74+
return false;
75+
}
76+
return true;
77+
}
78+
return false;
79+
}
4680
};
4781

4882
} // namespace clang::CIRGen

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: 112 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,56 @@ 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 filter) {
173+
const auto &builder = cgm.getBuilder();
174+
175+
unsigned nonzeroLength = arrayBound;
176+
if (elements.size() < nonzeroLength && builder.isNullValue(filter))
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+
if (trailingZeroes >= 8) {
190+
if (elements.size() < nonzeroLength)
191+
cgm.errorNYI("missing initializer for non-zero element");
192+
} else if (elements.size() != arrayBound) {
193+
elements.resize(arrayBound, filter);
194+
195+
if (filter.getType() != commonElementType)
196+
cgm.errorNYI(
197+
"array filter type should always be the same as element type");
198+
}
199+
200+
SmallVector<mlir::Attribute, 4> eles;
201+
eles.reserve(elements.size());
202+
203+
for (const auto &element : elements)
204+
eles.push_back(element);
205+
206+
return cir::ConstArrayAttr::get(
207+
cir::ArrayType::get(builder.getContext(), commonElementType, arrayBound),
208+
mlir::ArrayAttr::get(builder.getContext(), eles));
209+
}
210+
168211
//===----------------------------------------------------------------------===//
169212
// ConstantEmitter
170213
//===----------------------------------------------------------------------===//
@@ -271,16 +314,61 @@ mlir::Attribute ConstantEmitter::tryEmitPrivate(const APValue &value,
271314
cgm.getASTContext().getTargetInfo().useFP16ConversionIntrinsics()) {
272315
cgm.errorNYI("ConstExprEmitter::tryEmitPrivate half");
273316
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);
279317
}
318+
319+
mlir::Type ty = cgm.convertType(destType);
320+
assert(mlir::isa<cir::CIRFPTypeInterface>(ty) &&
321+
"expected floating-point type");
322+
return cgm.getBuilder().getAttr<cir::FPAttr>(ty, init);
280323
}
281324
case APValue::Array: {
282-
cgm.errorNYI("ConstExprEmitter::tryEmitPrivate array");
283-
return {};
325+
const ArrayType *arrayTy = cgm.getASTContext().getAsArrayType(destType);
326+
const QualType arrayElementTy = arrayTy->getElementType();
327+
const unsigned numElements = value.getArraySize();
328+
const unsigned numInitElts = value.getArrayInitializedElts();
329+
330+
mlir::Attribute filter;
331+
if (value.hasArrayFiller()) {
332+
filter =
333+
tryEmitPrivate(value.getArrayFiller(), arrayTy->getElementType());
334+
if (!filter)
335+
return {};
336+
}
337+
338+
SmallVector<mlir::TypedAttr, 16> elements;
339+
if (filter && builder.isNullValue(filter))
340+
elements.reserve(numInitElts + 1);
341+
else
342+
elements.reserve(numInitElts);
343+
344+
mlir::Type commonElementType;
345+
for (unsigned i = 0; i < numInitElts; ++i) {
346+
const APValue &arrayElement = value.getArrayInitializedElt(i);
347+
const mlir::Attribute element =
348+
tryEmitPrivateForMemory(arrayElement, arrayElementTy);
349+
if (!element)
350+
return {};
351+
352+
const mlir::TypedAttr elementTyped = mlir::cast<mlir::TypedAttr>(element);
353+
if (i == 0)
354+
commonElementType = elementTyped.getType();
355+
else if (elementTyped.getType() != commonElementType) {
356+
cgm.errorNYI("ConstExprEmitter::tryEmitPrivate Array without common "
357+
"element type");
358+
return {};
359+
}
360+
361+
elements.push_back(elementTyped);
362+
}
363+
364+
mlir::TypedAttr typedFilter =
365+
llvm::dyn_cast_or_null<mlir::TypedAttr>(filter);
366+
if (filter && !typedFilter)
367+
cgm.errorNYI("array filter should always be typed");
368+
369+
mlir::Type desiredType = cgm.convertType(destType);
370+
return emitArrayConstant(cgm, desiredType, commonElementType, numElements,
371+
elements, typedFilter);
284372
}
285373
case APValue::Vector: {
286374
cgm.errorNYI("ConstExprEmitter::tryEmitPrivate vector");
@@ -290,9 +378,23 @@ mlir::Attribute ConstantEmitter::tryEmitPrivate(const APValue &value,
290378
cgm.errorNYI("ConstExprEmitter::tryEmitPrivate member pointer");
291379
return {};
292380
}
293-
case APValue::LValue:
294-
cgm.errorNYI("ConstExprEmitter::tryEmitPrivate lvalue");
381+
case APValue::LValue: {
382+
383+
if (value.getLValueBase()) {
384+
cgm.errorNYI("non-null pointer initialization");
385+
} else {
386+
387+
mlir::Type desiredType = cgm.convertType(destType);
388+
if (const cir::PointerType ptrType =
389+
mlir::dyn_cast<cir::PointerType>(desiredType)) {
390+
return builder.getConstPtrAttr(ptrType,
391+
value.getLValueOffset().getQuantity());
392+
} else {
393+
llvm_unreachable("non-pointer variable initialized with a pointer");
394+
}
395+
}
295396
return {};
397+
}
296398
case APValue::Struct:
297399
case APValue::Union:
298400
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"
@@ -127,7 +128,8 @@ void CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd,
127128

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

0 commit comments

Comments
 (0)