Skip to content

Commit 2ed67e1

Browse files
YazZz1klanza
authored andcommitted
[CIR][CIRGen] Handle initilization of arrays (llvm#431)
1 parent 1510e73 commit 2ed67e1

File tree

2 files changed

+140
-0
lines changed

2 files changed

+140
-0
lines changed

clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
148148
void buildCopy(QualType type, const AggValueSlot &dest,
149149
const AggValueSlot &src);
150150

151+
void buildArrayInit(Address DestPtr, mlir::cir::ArrayType AType,
152+
QualType ArrayQTy, Expr *ExprToVisit,
153+
ArrayRef<Expr *> Args, Expr *ArrayFiller);
154+
151155
AggValueSlot::NeedsGCBarriers_t needsGC(QualType T) {
152156
if (CGF.getLangOpts().getGC() && TypeRequiresGCollection(T))
153157
llvm_unreachable("garbage collection is NYI");
@@ -394,6 +398,113 @@ void AggExprEmitter::buildCopy(QualType type, const AggValueSlot &dest,
394398
CGF.buildAggregateCopy(DestLV, SrcLV, type, dest.mayOverlap(), false);
395399
}
396400

401+
// FIXME(cir): This function could be shared with traditional LLVM codegen
402+
/// Determine if E is a trivial array filler, that is, one that is
403+
/// equivalent to zero-initialization.
404+
static bool isTrivialFiller(Expr *E) {
405+
if (!E)
406+
return true;
407+
408+
if (isa<ImplicitValueInitExpr>(E))
409+
return true;
410+
411+
if (auto *ILE = dyn_cast<InitListExpr>(E)) {
412+
if (ILE->getNumInits())
413+
return false;
414+
return isTrivialFiller(ILE->getArrayFiller());
415+
}
416+
417+
if (auto *Cons = dyn_cast_or_null<CXXConstructExpr>(E))
418+
return Cons->getConstructor()->isDefaultConstructor() &&
419+
Cons->getConstructor()->isTrivial();
420+
421+
// FIXME: Are there other cases where we can avoid emitting an initializer?
422+
return false;
423+
}
424+
425+
void AggExprEmitter::buildArrayInit(Address DestPtr, mlir::cir::ArrayType AType,
426+
QualType ArrayQTy, Expr *ExprToVisit,
427+
ArrayRef<Expr *> Args, Expr *ArrayFiller) {
428+
uint64_t NumInitElements = Args.size();
429+
430+
uint64_t NumArrayElements = AType.getSize();
431+
assert(NumInitElements != 0 && "expected at least one initializaed value");
432+
assert(NumInitElements <= NumArrayElements);
433+
434+
QualType elementType =
435+
CGF.getContext().getAsArrayType(ArrayQTy)->getElementType();
436+
437+
auto cirElementType = CGF.convertType(elementType);
438+
auto cirElementPtrType = mlir::cir::PointerType::get(
439+
CGF.getBuilder().getContext(), cirElementType);
440+
auto loc = CGF.getLoc(ExprToVisit->getSourceRange());
441+
442+
// Cast from cir.ptr<cir.array<elementType> to cir.ptr<elementType>
443+
auto begin = CGF.getBuilder().create<mlir::cir::CastOp>(
444+
loc, cirElementPtrType, mlir::cir::CastKind::array_to_ptrdecay,
445+
DestPtr.getPointer());
446+
447+
CharUnits elementSize = CGF.getContext().getTypeSizeInChars(elementType);
448+
CharUnits elementAlign =
449+
DestPtr.getAlignment().alignmentOfArrayElement(elementSize);
450+
451+
// Exception safety requires us to destroy all the
452+
// already-constructed members if an initializer throws.
453+
// For that, we'll need an EH cleanup.
454+
[[maybe_unused]] QualType::DestructionKind dtorKind =
455+
elementType.isDestructedType();
456+
[[maybe_unused]] Address endOfInit = Address::invalid();
457+
assert(!CGF.needsEHCleanup(dtorKind) && "destructed types NIY");
458+
459+
// The 'current element to initialize'. The invariants on this
460+
// variable are complicated. Essentially, after each iteration of
461+
// the loop, it points to the last initialized element, except
462+
// that it points to the beginning of the array before any
463+
// elements have been initialized.
464+
mlir::Value element = begin;
465+
466+
// Don't build the 'one' before the cycle to avoid
467+
// emmiting the redundant cir.const(1) instrs.
468+
mlir::Value one;
469+
470+
// Emit the explicit initializers.
471+
for (uint64_t i = 0; i != NumInitElements; ++i) {
472+
if (i == 1)
473+
one = CGF.getBuilder().getConstInt(
474+
loc, CGF.PtrDiffTy.cast<mlir::cir::IntType>(), 1);
475+
476+
// Advance to the next element.
477+
if (i > 0) {
478+
element = CGF.getBuilder().create<mlir::cir::PtrStrideOp>(
479+
loc, cirElementPtrType, element, one);
480+
481+
// Tell the cleanup that it needs to destroy up to this
482+
// element. TODO: some of these stores can be trivially
483+
// observed to be unnecessary.
484+
assert(!endOfInit.isValid() && "destructed types NIY");
485+
}
486+
487+
LValue elementLV = CGF.makeAddrLValue(
488+
Address(element, cirElementType, elementAlign), elementType);
489+
buildInitializationToLValue(Args[i], elementLV);
490+
}
491+
492+
// Check whether there's a non-trivial array-fill expression.
493+
bool hasTrivialFiller = isTrivialFiller(ArrayFiller);
494+
495+
// Any remaining elements need to be zero-initialized, possibly
496+
// using the filler expression. We can skip this if the we're
497+
// emitting to zeroed memory.
498+
if (NumInitElements != NumArrayElements &&
499+
!(Dest.isZeroed() && hasTrivialFiller &&
500+
CGF.getTypes().isZeroInitializable(elementType))) {
501+
llvm_unreachable("zero-initialization of arrays NIY");
502+
}
503+
504+
// Leave the partial-array cleanup if we entered one.
505+
assert(!dtorKind && "destructed types NIY");
506+
}
507+
397508
/// True if the given aggregate type requires special GC API calls.
398509
bool AggExprEmitter::TypeRequiresGCollection(QualType T) {
399510
// Only record types have members that might require garbage collection.
@@ -888,6 +999,16 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
888999
LValue DestLV = CGF.makeAddrLValue(Dest.getAddress(), ExprToVisit->getType());
8891000

8901001
// Handle initialization of an array.
1002+
if (ExprToVisit->getType()->isConstantArrayType()) {
1003+
auto AType = cast<mlir::cir::ArrayType>(Dest.getAddress().getElementType());
1004+
buildArrayInit(Dest.getAddress(), AType, ExprToVisit->getType(),
1005+
ExprToVisit, InitExprs, ArrayFiller);
1006+
return;
1007+
} else if (ExprToVisit->getType()->isVariableArrayType()) {
1008+
llvm_unreachable("variable arrays NYI");
1009+
return;
1010+
}
1011+
8911012
if (ExprToVisit->getType()->isArrayType()) {
8921013
llvm_unreachable("NYI");
8931014
}

clang/test/CIR/CodeGen/array-init.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,22 @@ void foo() {
88
// CHECK-NEXT: %1 = cir.const(#cir.const_array<[9.000000e+00, 8.000000e+00, 7.000000e+00]> : !cir.array<f64 x 3>) : !cir.array<f64 x 3>
99
// CHECK-NEXT: cir.store %1, %0 : !cir.array<f64 x 3>, cir.ptr <!cir.array<f64 x 3>>
1010

11+
void bar(int a, int b, int c) {
12+
int arr[] = {a,b,c};
13+
}
14+
15+
// CHECK: cir.func @bar
16+
// CHECK: [[ARR:%.*]] = cir.alloca !cir.array<!s32i x 3>, cir.ptr <!cir.array<!s32i x 3>>, ["arr", init] {alignment = 4 : i64}
17+
// CHECK-NEXT: cir.store %arg0, [[A:%.*]] : !s32i, cir.ptr <!s32i>
18+
// CHECK-NEXT: cir.store %arg1, [[B:%.*]] : !s32i, cir.ptr <!s32i>
19+
// CHECK-NEXT: cir.store %arg2, [[C:%.*]] : !s32i, cir.ptr <!s32i>
20+
// CHECK-NEXT: [[FI_EL:%.*]] = cir.cast(array_to_ptrdecay, [[ARR]] : !cir.ptr<!cir.array<!s32i x 3>>), !cir.ptr<!s32i>
21+
// CHECK-NEXT: [[LOAD_A:%.*]] = cir.load [[A]] : cir.ptr <!s32i>, !s32i
22+
// CHECK-NEXT: cir.store [[LOAD_A]], [[FI_EL]] : !s32i, cir.ptr <!s32i>
23+
// CHECK-NEXT: [[ONE:%.*]] = cir.const(#cir.int<1> : !s64i) : !s64i
24+
// CHECK-NEXT: [[SE_EL:%.*]] = cir.ptr_stride(%4 : !cir.ptr<!s32i>, [[ONE]] : !s64i), !cir.ptr<!s32i>
25+
// CHECK-NEXT: [[LOAD_B:%.*]] = cir.load [[B]] : cir.ptr <!s32i>, !s32i
26+
// CHECK-NEXT: cir.store [[LOAD_B]], [[SE_EL]] : !s32i, cir.ptr <!s32i>
27+
// CHECK-NEXT: [[TH_EL:%.*]] = cir.ptr_stride(%7 : !cir.ptr<!s32i>, [[ONE]] : !s64i), !cir.ptr<!s32i>
28+
// CHECK-NEXT: [[LOAD_C:%.*]] = cir.load [[C]] : cir.ptr <!s32i>, !s32i
29+
// CHECK-NEXT: cir.store [[LOAD_C]], [[TH_EL]] : !s32i, cir.ptr <!s32i>

0 commit comments

Comments
 (0)