clang 22.0.0git
CIRGenExprAggregate.cpp
Go to the documentation of this file.
1//===- CIRGenExprAggregrate.cpp - Emit CIR Code from Aggregate Expressions ===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This contains code to emit Aggregate Expr nodes as CIR code.
10//
11//===----------------------------------------------------------------------===//
12
13#include "CIRGenBuilder.h"
14#include "CIRGenFunction.h"
15#include "CIRGenValue.h"
17
18#include "clang/AST/Expr.h"
21#include <cstdint>
22
23using namespace clang;
24using namespace clang::CIRGen;
25
26namespace {
27class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
28
29 CIRGenFunction &cgf;
30 AggValueSlot dest;
31
32 // Calls `fn` with a valid return value slot, potentially creating a temporary
33 // to do so. If a temporary is created, an appropriate copy into `Dest` will
34 // be emitted, as will lifetime markers.
35 //
36 // The given function should take a ReturnValueSlot, and return an RValue that
37 // points to said slot.
38 void withReturnValueSlot(const Expr *e,
39 llvm::function_ref<RValue(ReturnValueSlot)> fn);
40
41 AggValueSlot ensureSlot(mlir::Location loc, QualType t) {
42 if (!dest.isIgnored())
43 return dest;
44
45 cgf.cgm.errorNYI(loc, "Slot for ignored address");
46 return dest;
47 }
48
49public:
50 AggExprEmitter(CIRGenFunction &cgf, AggValueSlot dest)
51 : cgf(cgf), dest(dest) {}
52
53 /// Given an expression with aggregate type that represents a value lvalue,
54 /// this method emits the address of the lvalue, then loads the result into
55 /// DestPtr.
56 void emitAggLoadOfLValue(const Expr *e);
57
58 void emitArrayInit(Address destPtr, cir::ArrayType arrayTy, QualType arrayQTy,
59 Expr *exprToVisit, ArrayRef<Expr *> args,
60 Expr *arrayFiller);
61
62 /// Perform the final copy to DestPtr, if desired.
63 void emitFinalDestCopy(QualType type, const LValue &src);
64
65 void emitInitializationToLValue(Expr *e, LValue lv);
66
67 void emitNullInitializationToLValue(mlir::Location loc, LValue lv);
68
70
71 void VisitCallExpr(const CallExpr *e);
72 void VisitStmtExpr(const StmtExpr *e) {
74 Address retAlloca =
75 cgf.createMemTemp(e->getType(), cgf.getLoc(e->getSourceRange()));
76 (void)cgf.emitCompoundStmt(*e->getSubStmt(), &retAlloca, dest);
77 }
78
79 void VisitDeclRefExpr(DeclRefExpr *e) { emitAggLoadOfLValue(e); }
80
81 void VisitInitListExpr(InitListExpr *e);
82 void VisitCXXConstructExpr(const CXXConstructExpr *e);
83
84 void visitCXXParenListOrInitListExpr(Expr *e, ArrayRef<Expr *> args,
85 FieldDecl *initializedFieldInUnion,
86 Expr *arrayFiller);
87
88 void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *e) {
90 Visit(e->getSubExpr());
91 }
92
93 // Stubs -- These should be moved up when they are implemented.
94 void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *e) {
95 // We shouldn't really get here, but we do because of missing handling for
96 // emitting constant aggregate initializers. If we just ignore this, a
97 // fallback handler will do the right thing.
99 return;
100 }
101 void VisitCastExpr(CastExpr *e) {
102 switch (e->getCastKind()) {
103 case CK_LValueToRValue:
104 // If we're loading from a volatile type, force the destination
105 // into existence.
107 cgf.cgm.errorNYI(e->getSourceRange(),
108 "AggExprEmitter: volatile lvalue-to-rvalue cast");
109 [[fallthrough]];
110 case CK_NoOp:
111 case CK_UserDefinedConversion:
112 case CK_ConstructorConversion:
114 e->getType()) &&
115 "Implicit cast types must be compatible");
116 Visit(e->getSubExpr());
117 break;
118 default:
119 cgf.cgm.errorNYI(e->getSourceRange(),
120 std::string("AggExprEmitter: VisitCastExpr: ") +
121 e->getCastKindName());
122 break;
123 }
124 }
125 void VisitStmt(Stmt *s) {
126 cgf.cgm.errorNYI(s->getSourceRange(),
127 std::string("AggExprEmitter::VisitStmt: ") +
128 s->getStmtClassName());
129 }
130 void VisitParenExpr(ParenExpr *pe) {
131 cgf.cgm.errorNYI(pe->getSourceRange(), "AggExprEmitter: VisitParenExpr");
132 }
133 void VisitGenericSelectionExpr(GenericSelectionExpr *ge) {
134 cgf.cgm.errorNYI(ge->getSourceRange(),
135 "AggExprEmitter: VisitGenericSelectionExpr");
136 }
137 void VisitCoawaitExpr(CoawaitExpr *e) {
138 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCoawaitExpr");
139 }
140 void VisitCoyieldExpr(CoyieldExpr *e) {
141 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCoyieldExpr");
142 }
143 void VisitUnaryCoawait(UnaryOperator *e) {
144 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitUnaryCoawait");
145 }
146 void VisitUnaryExtension(UnaryOperator *e) {
147 cgf.cgm.errorNYI(e->getSourceRange(),
148 "AggExprEmitter: VisitUnaryExtension");
149 }
150 void VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *e) {
151 cgf.cgm.errorNYI(e->getSourceRange(),
152 "AggExprEmitter: VisitSubstNonTypeTemplateParmExpr");
153 }
154 void VisitConstantExpr(ConstantExpr *e) {
155 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitConstantExpr");
156 }
157 void VisitMemberExpr(MemberExpr *e) {
158 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitMemberExpr");
159 }
160 void VisitUnaryDeref(UnaryOperator *e) {
161 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitUnaryDeref");
162 }
163 void VisitStringLiteral(StringLiteral *e) {
164 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitStringLiteral");
165 }
166 void VisitCompoundLiteralExpr(CompoundLiteralExpr *e) {
167 cgf.cgm.errorNYI(e->getSourceRange(),
168 "AggExprEmitter: VisitCompoundLiteralExpr");
169 }
170 void VisitArraySubscriptExpr(ArraySubscriptExpr *e) {
171 cgf.cgm.errorNYI(e->getSourceRange(),
172 "AggExprEmitter: VisitArraySubscriptExpr");
173 }
174 void VisitPredefinedExpr(const PredefinedExpr *e) {
175 cgf.cgm.errorNYI(e->getSourceRange(),
176 "AggExprEmitter: VisitPredefinedExpr");
177 }
178 void VisitBinaryOperator(const BinaryOperator *e) {
179 cgf.cgm.errorNYI(e->getSourceRange(),
180 "AggExprEmitter: VisitBinaryOperator");
181 }
182 void VisitPointerToDataMemberBinaryOperator(const BinaryOperator *e) {
183 cgf.cgm.errorNYI(e->getSourceRange(),
184 "AggExprEmitter: VisitPointerToDataMemberBinaryOperator");
185 }
186 void VisitBinAssign(const BinaryOperator *e) {
187 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitBinAssign");
188 }
189 void VisitBinComma(const BinaryOperator *e) {
190 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitBinComma");
191 }
192 void VisitBinCmp(const BinaryOperator *e) {
193 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitBinCmp");
194 }
195 void VisitCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *e) {
196 cgf.cgm.errorNYI(e->getSourceRange(),
197 "AggExprEmitter: VisitCXXRewrittenBinaryOperator");
198 }
199 void VisitObjCMessageExpr(ObjCMessageExpr *e) {
200 cgf.cgm.errorNYI(e->getSourceRange(),
201 "AggExprEmitter: VisitObjCMessageExpr");
202 }
203 void VisitObjCIVarRefExpr(ObjCIvarRefExpr *e) {
204 cgf.cgm.errorNYI(e->getSourceRange(),
205 "AggExprEmitter: VisitObjCIVarRefExpr");
206 }
207
208 void VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *e) {
209 cgf.cgm.errorNYI(e->getSourceRange(),
210 "AggExprEmitter: VisitDesignatedInitUpdateExpr");
211 }
212 void VisitAbstractConditionalOperator(const AbstractConditionalOperator *e) {
213 cgf.cgm.errorNYI(e->getSourceRange(),
214 "AggExprEmitter: VisitAbstractConditionalOperator");
215 }
216 void VisitChooseExpr(const ChooseExpr *e) {
217 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitChooseExpr");
218 }
219 void VisitCXXParenListInitExpr(CXXParenListInitExpr *e) {
220 cgf.cgm.errorNYI(e->getSourceRange(),
221 "AggExprEmitter: VisitCXXParenListInitExpr");
222 }
223 void VisitArrayInitLoopExpr(const ArrayInitLoopExpr *e,
224 llvm::Value *outerBegin = nullptr) {
225 cgf.cgm.errorNYI(e->getSourceRange(),
226 "AggExprEmitter: VisitArrayInitLoopExpr");
227 }
228 void VisitImplicitValueInitExpr(ImplicitValueInitExpr *e) {
229 cgf.cgm.errorNYI(e->getSourceRange(),
230 "AggExprEmitter: VisitImplicitValueInitExpr");
231 }
232 void VisitNoInitExpr(NoInitExpr *e) {
233 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitNoInitExpr");
234 }
235 void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *dae) {
236 cgf.cgm.errorNYI(dae->getSourceRange(),
237 "AggExprEmitter: VisitCXXDefaultArgExpr");
238 }
239 void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *die) {
240 cgf.cgm.errorNYI(die->getSourceRange(),
241 "AggExprEmitter: VisitCXXDefaultInitExpr");
242 }
243 void VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *e) {
244 cgf.cgm.errorNYI(e->getSourceRange(),
245 "AggExprEmitter: VisitCXXInheritedCtorInitExpr");
246 }
247 void VisitLambdaExpr(LambdaExpr *e) {
248 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitLambdaExpr");
249 }
250 void VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *e) {
251 cgf.cgm.errorNYI(e->getSourceRange(),
252 "AggExprEmitter: VisitCXXStdInitializerListExpr");
253 }
254
255 void VisitExprWithCleanups(ExprWithCleanups *e) {
256 cgf.cgm.errorNYI(e->getSourceRange(),
257 "AggExprEmitter: VisitExprWithCleanups");
258 }
259 void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *e) {
260 cgf.cgm.errorNYI(e->getSourceRange(),
261 "AggExprEmitter: VisitCXXScalarValueInitExpr");
262 }
263 void VisitCXXTypeidExpr(CXXTypeidExpr *e) {
264 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCXXTypeidExpr");
265 }
266 void VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *e) {
267 cgf.cgm.errorNYI(e->getSourceRange(),
268 "AggExprEmitter: VisitMaterializeTemporaryExpr");
269 }
270 void VisitOpaqueValueExpr(OpaqueValueExpr *e) {
271 cgf.cgm.errorNYI(e->getSourceRange(),
272 "AggExprEmitter: VisitOpaqueValueExpr");
273 }
274
275 void VisitPseudoObjectExpr(PseudoObjectExpr *e) {
276 cgf.cgm.errorNYI(e->getSourceRange(),
277 "AggExprEmitter: VisitPseudoObjectExpr");
278 }
279
280 void VisitVAArgExpr(VAArgExpr *e) {
281 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitVAArgExpr");
282 }
283
284 void VisitCXXThrowExpr(const CXXThrowExpr *e) {
285 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCXXThrowExpr");
286 }
287 void VisitAtomicExpr(AtomicExpr *e) {
288 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitAtomicExpr");
289 }
290};
291
292} // namespace
293
294static bool isTrivialFiller(Expr *e) {
295 if (!e)
296 return true;
297
298 if (isa<ImplicitValueInitExpr>(e))
299 return true;
300
301 if (auto *ile = dyn_cast<InitListExpr>(e)) {
302 if (ile->getNumInits())
303 return false;
304 return isTrivialFiller(ile->getArrayFiller());
305 }
306
307 if (const auto *cons = dyn_cast_or_null<CXXConstructExpr>(e))
308 return cons->getConstructor()->isDefaultConstructor() &&
309 cons->getConstructor()->isTrivial();
310
311 return false;
312}
313
314/// Given an expression with aggregate type that represents a value lvalue, this
315/// method emits the address of the lvalue, then loads the result into DestPtr.
316void AggExprEmitter::emitAggLoadOfLValue(const Expr *e) {
317 LValue lv = cgf.emitLValue(e);
318
319 // If the type of the l-value is atomic, then do an atomic load.
321
322 emitFinalDestCopy(e->getType(), lv);
323}
324
325void AggExprEmitter::emitArrayInit(Address destPtr, cir::ArrayType arrayTy,
326 QualType arrayQTy, Expr *e,
327 ArrayRef<Expr *> args, Expr *arrayFiller) {
328 CIRGenBuilderTy &builder = cgf.getBuilder();
329 const mlir::Location loc = cgf.getLoc(e->getSourceRange());
330
331 const uint64_t numInitElements = args.size();
332
333 const QualType elementType =
334 cgf.getContext().getAsArrayType(arrayQTy)->getElementType();
335
336 if (elementType.isDestructedType() && cgf.cgm.getLangOpts().Exceptions) {
337 cgf.cgm.errorNYI(loc, "initialized array requires destruction");
338 return;
339 }
340
341 const QualType elementPtrType = cgf.getContext().getPointerType(elementType);
342
343 const mlir::Type cirElementType = cgf.convertType(elementType);
344 const cir::PointerType cirElementPtrType =
345 builder.getPointerTo(cirElementType);
346
347 auto begin = cir::CastOp::create(builder, loc, cirElementPtrType,
348 cir::CastKind::array_to_ptrdecay,
349 destPtr.getPointer());
350
351 const CharUnits elementSize =
352 cgf.getContext().getTypeSizeInChars(elementType);
353 const CharUnits elementAlign =
354 destPtr.getAlignment().alignmentOfArrayElement(elementSize);
355
356 // The 'current element to initialize'. The invariants on this
357 // variable are complicated. Essentially, after each iteration of
358 // the loop, it points to the last initialized element, except
359 // that it points to the beginning of the array before any
360 // elements have been initialized.
361 mlir::Value element = begin;
362
363 // Don't build the 'one' before the cycle to avoid
364 // emmiting the redundant `cir.const 1` instrs.
365 mlir::Value one;
366
367 // Emit the explicit initializers.
368 for (uint64_t i = 0; i != numInitElements; ++i) {
369 // Advance to the next element.
370 if (i > 0) {
371 one = builder.getConstantInt(loc, cgf.PtrDiffTy, i);
372 element = builder.createPtrStride(loc, begin, one);
373 }
374
375 const Address address = Address(element, cirElementType, elementAlign);
376 const LValue elementLV = cgf.makeAddrLValue(address, elementType);
377 emitInitializationToLValue(args[i], elementLV);
378 }
379
380 const uint64_t numArrayElements = arrayTy.getSize();
381
382 // Check whether there's a non-trivial array-fill expression.
383 const bool hasTrivialFiller = isTrivialFiller(arrayFiller);
384
385 // Any remaining elements need to be zero-initialized, possibly
386 // using the filler expression. We can skip this if the we're
387 // emitting to zeroed memory.
388 if (numInitElements != numArrayElements &&
389 !(dest.isZeroed() && hasTrivialFiller &&
390 cgf.getTypes().isZeroInitializable(elementType))) {
391 // Advance to the start of the rest of the array.
392 if (numInitElements) {
393 one = builder.getConstantInt(loc, cgf.PtrDiffTy, 1);
394 element = cir::PtrStrideOp::create(builder, loc, cirElementPtrType,
395 element, one);
396 }
397
398 // Allocate the temporary variable
399 // to store the pointer to first unitialized element
400 const Address tmpAddr = cgf.createTempAlloca(
401 cirElementPtrType, cgf.getPointerAlign(), loc, "arrayinit.temp");
402 LValue tmpLV = cgf.makeAddrLValue(tmpAddr, elementPtrType);
403 cgf.emitStoreThroughLValue(RValue::get(element), tmpLV);
404
405 // Compute the end of array
406 cir::ConstantOp numArrayElementsConst = builder.getConstInt(
407 loc, mlir::cast<cir::IntType>(cgf.PtrDiffTy), numArrayElements);
408 mlir::Value end = cir::PtrStrideOp::create(builder, loc, cirElementPtrType,
409 begin, numArrayElementsConst);
410
411 builder.createDoWhile(
412 loc,
413 /*condBuilder=*/
414 [&](mlir::OpBuilder &b, mlir::Location loc) {
415 cir::LoadOp currentElement = builder.createLoad(loc, tmpAddr);
416 mlir::Type boolTy = cgf.convertType(cgf.getContext().BoolTy);
417 cir::CmpOp cmp = cir::CmpOp::create(
418 builder, loc, boolTy, cir::CmpOpKind::ne, currentElement, end);
419 builder.createCondition(cmp);
420 },
421 /*bodyBuilder=*/
422 [&](mlir::OpBuilder &b, mlir::Location loc) {
423 cir::LoadOp currentElement = builder.createLoad(loc, tmpAddr);
424
426
427 // Emit the actual filler expression.
428 LValue elementLV = cgf.makeAddrLValue(
429 Address(currentElement, cirElementType, elementAlign),
430 elementType);
431 if (arrayFiller)
432 emitInitializationToLValue(arrayFiller, elementLV);
433 else
434 emitNullInitializationToLValue(loc, elementLV);
435
436 // Tell the EH cleanup that we finished with the last element.
437 if (cgf.cgm.getLangOpts().Exceptions) {
438 cgf.cgm.errorNYI(loc, "update destructed array element for EH");
439 return;
440 }
441
442 // Advance pointer and store them to temporary variable
443 cir::ConstantOp one = builder.getConstInt(
444 loc, mlir::cast<cir::IntType>(cgf.PtrDiffTy), 1);
445 auto nextElement = cir::PtrStrideOp::create(
446 builder, loc, cirElementPtrType, currentElement, one);
447 cgf.emitStoreThroughLValue(RValue::get(nextElement), tmpLV);
448
449 builder.createYield(loc);
450 });
451 }
452}
453
454/// Perform the final copy to destPtr, if desired.
455void AggExprEmitter::emitFinalDestCopy(QualType type, const LValue &src) {
456 // If dest is ignored, then we're evaluating an aggregate expression
457 // in a context that doesn't care about the result. Note that loads
458 // from volatile l-values force the existence of a non-ignored
459 // destination.
460 if (dest.isIgnored())
461 return;
462
463 cgf.cgm.errorNYI("emitFinalDestCopy: non-ignored dest is NYI");
464}
465
466void AggExprEmitter::emitInitializationToLValue(Expr *e, LValue lv) {
467 const QualType type = lv.getType();
468
469 if (isa<ImplicitValueInitExpr, CXXScalarValueInitExpr>(e)) {
470 const mlir::Location loc = e->getSourceRange().isValid()
471 ? cgf.getLoc(e->getSourceRange())
472 : *cgf.currSrcLoc;
473 return emitNullInitializationToLValue(loc, lv);
474 }
475
476 if (isa<NoInitExpr>(e))
477 return;
478
479 if (type->isReferenceType())
480 cgf.cgm.errorNYI("emitInitializationToLValue ReferenceType");
481
482 switch (cgf.getEvaluationKind(type)) {
483 case cir::TEK_Complex:
484 cgf.cgm.errorNYI("emitInitializationToLValue TEK_Complex");
485 break;
490 dest.isZeroed()));
491
492 return;
493 case cir::TEK_Scalar:
494 if (lv.isSimple())
495 cgf.emitScalarInit(e, cgf.getLoc(e->getSourceRange()), lv);
496 else
498 return;
499 }
500}
501
502void AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *e) {
503 AggValueSlot slot = ensureSlot(cgf.getLoc(e->getSourceRange()), e->getType());
504 cgf.emitCXXConstructExpr(e, slot);
505}
506
507void AggExprEmitter::emitNullInitializationToLValue(mlir::Location loc,
508 LValue lv) {
509 const QualType type = lv.getType();
510
511 // If the destination slot is already zeroed out before the aggregate is
512 // copied into it, we don't have to emit any zeros here.
513 if (dest.isZeroed() && cgf.getTypes().isZeroInitializable(type))
514 return;
515
516 if (cgf.hasScalarEvaluationKind(type)) {
517 // For non-aggregates, we can store the appropriate null constant.
518 mlir::Value null = cgf.cgm.emitNullConstant(type, loc);
519 if (lv.isSimple()) {
520 cgf.emitStoreOfScalar(null, lv, /* isInitialization */ true);
521 return;
522 }
523
524 cgf.cgm.errorNYI("emitStoreThroughBitfieldLValue");
525 return;
526 }
527
528 // There's a potential optimization opportunity in combining
529 // memsets; that would be easy for arrays, but relatively
530 // difficult for structures with the current code.
531 cgf.emitNullInitialization(loc, lv.getAddress(), lv.getType());
532}
533
534void AggExprEmitter::VisitCallExpr(const CallExpr *e) {
536 cgf.cgm.errorNYI(e->getSourceRange(), "reference return type");
537 return;
538 }
539
540 withReturnValueSlot(
541 e, [&](ReturnValueSlot slot) { return cgf.emitCallExpr(e, slot); });
542}
543
544void AggExprEmitter::withReturnValueSlot(
545 const Expr *e, llvm::function_ref<RValue(ReturnValueSlot)> fn) {
546 QualType retTy = e->getType();
547
549 bool requiresDestruction =
551 if (requiresDestruction)
552 cgf.cgm.errorNYI(
553 e->getSourceRange(),
554 "withReturnValueSlot: return value requiring destruction is NYI");
555
556 // If it makes no observable difference, save a memcpy + temporary.
557 //
558 // We need to always provide our own temporary if destruction is required.
559 // Otherwise, fn will emit its own, notice that it's "unused", and end its
560 // lifetime before we have the chance to emit a proper destructor call.
563
564 Address retAddr = dest.getAddress();
566
569 fn(ReturnValueSlot(retAddr));
570}
571
572void AggExprEmitter::VisitInitListExpr(InitListExpr *e) {
574 llvm_unreachable("GNU array range designator extension");
575
576 if (e->isTransparent())
577 return Visit(e->getInit(0));
578
579 visitCXXParenListOrInitListExpr(
581}
582
583void AggExprEmitter::visitCXXParenListOrInitListExpr(
584 Expr *e, ArrayRef<Expr *> args, FieldDecl *initializedFieldInUnion,
585 Expr *arrayFiller) {
586
587 const AggValueSlot dest =
588 ensureSlot(cgf.getLoc(e->getSourceRange()), e->getType());
589
590 if (e->getType()->isConstantArrayType()) {
591 cir::ArrayType arrayTy =
592 cast<cir::ArrayType>(dest.getAddress().getElementType());
593 emitArrayInit(dest.getAddress(), arrayTy, e->getType(), e, args,
594 arrayFiller);
595 return;
596 } else if (e->getType()->isVariableArrayType()) {
597 cgf.cgm.errorNYI(e->getSourceRange(),
598 "visitCXXParenListOrInitListExpr variable array type");
599 return;
600 }
601
602 if (e->getType()->isArrayType()) {
603 cgf.cgm.errorNYI(e->getSourceRange(),
604 "visitCXXParenListOrInitListExpr array type");
605 return;
606 }
607
608 assert(e->getType()->isRecordType() && "Only support structs/unions here!");
609
610 // Do struct initialization; this code just sets each individual member
611 // to the approprate value. This makes bitfield support automatic;
612 // the disadvantage is that the generated code is more difficult for
613 // the optimizer, especially with bitfields.
614 unsigned numInitElements = args.size();
615 auto *record = e->getType()->castAsRecordDecl();
616
617 // We'll need to enter cleanup scopes in case any of the element
618 // initializers throws an exception.
620
621 unsigned curInitIndex = 0;
622
623 // Emit initialization of base classes.
624 if (auto *cxxrd = dyn_cast<CXXRecordDecl>(record)) {
625 assert(numInitElements >= cxxrd->getNumBases() &&
626 "missing initializer for base class");
627 if (cxxrd->getNumBases() > 0) {
628 cgf.cgm.errorNYI(e->getSourceRange(),
629 "visitCXXParenListOrInitListExpr base class init");
630 return;
631 }
632 }
633
634 LValue destLV = cgf.makeAddrLValue(dest.getAddress(), e->getType());
635
636 if (record->isUnion()) {
637 cgf.cgm.errorNYI(e->getSourceRange(),
638 "visitCXXParenListOrInitListExpr union type");
639 return;
640 }
641
642 // Here we iterate over the fields; this makes it simpler to both
643 // default-initialize fields and skip over unnamed fields.
644 for (const FieldDecl *field : record->fields()) {
645 // We're done once we hit the flexible array member.
646 if (field->getType()->isIncompleteArrayType())
647 break;
648
649 // Always skip anonymous bitfields.
650 if (field->isUnnamedBitField())
651 continue;
652
653 // We're done if we reach the end of the explicit initializers, we
654 // have a zeroed object, and the rest of the fields are
655 // zero-initializable.
656 if (curInitIndex == numInitElements && dest.isZeroed() &&
658 break;
659 LValue lv =
660 cgf.emitLValueForFieldInitialization(destLV, field, field->getName());
661 // We never generate write-barriers for initialized fields.
663
664 if (curInitIndex < numInitElements) {
665 // Store the initializer into the field.
667 cgf, cgf.getLoc(record->getSourceRange())};
668 emitInitializationToLValue(args[curInitIndex++], lv);
669 } else {
670 // We're out of initializers; default-initialize to null
671 emitNullInitializationToLValue(cgf.getLoc(e->getSourceRange()), lv);
672 }
673
674 // Push a destructor if necessary.
675 // FIXME: if we have an array of structures, all explicitly
676 // initialized, we can end up pushing a linear number of cleanups.
677 if (field->getType().isDestructedType()) {
678 cgf.cgm.errorNYI(e->getSourceRange(),
679 "visitCXXParenListOrInitListExpr destructor");
680 return;
681 }
682
683 // From classic codegen, maybe not useful for CIR:
684 // If the GEP didn't get used because of a dead zero init or something
685 // else, clean it up for -O0 builds and general tidiness.
686 }
687}
688
689// TODO(cir): This could be shared with classic codegen.
691 const CXXRecordDecl *rd, const CXXRecordDecl *baseRD, bool isVirtual) {
692 // If the most-derived object is a field declared with [[no_unique_address]],
693 // the tail padding of any virtual base could be reused for other subobjects
694 // of that field's class.
695 if (isVirtual)
697
698 // If the base class is laid out entirely within the nvsize of the derived
699 // class, its tail padding cannot yet be initialized, so we can issue
700 // stores at the full width of the base class.
701 const ASTRecordLayout &layout = getContext().getASTRecordLayout(rd);
702 if (layout.getBaseClassOffset(baseRD) +
703 getContext().getASTRecordLayout(baseRD).getSize() <=
704 layout.getNonVirtualSize())
706
707 // The tail padding may contain values we need to preserve.
709}
710
712 AggExprEmitter(*this, slot).Visit(const_cast<Expr *>(e));
713}
714
716 assert(hasAggregateEvaluationKind(e->getType()) && "Invalid argument!");
718 LValue lv = makeAddrLValue(temp, e->getType());
722 return lv;
723}
static bool isTrivialFiller(Expr *e)
__device__ __2f16 b
__device__ __2f16 float __ockl_bool s
cir::ConditionOp createCondition(mlir::Value condition)
Create a loop condition.
cir::PtrStrideOp createPtrStride(mlir::Location loc, mlir::Value base, mlir::Value stride)
cir::PointerType getPointerTo(mlir::Type ty)
cir::DoWhileOp createDoWhile(mlir::Location loc, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> condBuilder, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> bodyBuilder)
Create a do-while operation.
cir::ConstantOp getConstantInt(mlir::Location loc, mlir::Type ty, int64_t value)
cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value={})
Create a yield operation.
const ASTRecordLayout & getASTRecordLayout(const RecordDecl *D) const
Get or compute information about the layout of the specified record (struct/union/class) D,...
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
CanQualType BoolTy
Definition: ASTContext.h:1223
bool hasSameUnqualifiedType(QualType T1, QualType T2) const
Determine whether the given types are equivalent after cvr-qualifiers have been removed.
Definition: ASTContext.h:2898
const ArrayType * getAsArrayType(QualType T) const
Type Query functions.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
ASTRecordLayout - This class contains layout information for one RecordDecl, which is a struct/union/...
Definition: RecordLayout.h:38
CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const
getBaseClassOffset - Get the offset, in chars, for the given base class.
Definition: RecordLayout.h:250
CharUnits getNonVirtualSize() const
getNonVirtualSize - Get the non-virtual size (in chars) of an object, which is the size of the object...
Definition: RecordLayout.h:211
AbstractConditionalOperator - An abstract base class for ConditionalOperator and BinaryConditionalOpe...
Definition: Expr.h:4289
Represents a loop initializing the elements of an array.
Definition: Expr.h:5904
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Definition: Expr.h:2723
QualType getElementType() const
Definition: TypeBase.h:3750
AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*, __atomic_load,...
Definition: Expr.h:6816
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:3974
mlir::Value getPointer() const
Definition: Address.h:81
mlir::Type getElementType() const
Definition: Address.h:101
clang::CharUnits getAlignment() const
Definition: Address.h:109
An aggregate value slot.
Definition: CIRGenValue.h:302
IsZeroed_t isZeroed() const
Definition: CIRGenValue.h:382
static AggValueSlot forLValue(const LValue &LV, IsDestructed_t isDestructed, IsAliased_t isAliased, Overlap_t mayOverlap, IsZeroed_t isZeroed=IsNotZeroed)
Definition: CIRGenValue.h:367
Address getAddress() const
Definition: CIRGenValue.h:376
cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal)
cir::LoadOp createLoad(mlir::Location loc, Address addr, bool isVolatile=false)
An RAII object to record that we're evaluating a statement expression.
static bool hasScalarEvaluationKind(clang::QualType type)
mlir::Type convertType(clang::QualType t)
static cir::TypeEvaluationKind getEvaluationKind(clang::QualType type)
Return the cir::TypeEvaluationKind of QualType type.
CIRGenTypes & getTypes() const
cir::AllocaOp createTempAlloca(mlir::Type ty, mlir::Location loc, const Twine &name="tmp", mlir::Value arraySize=nullptr, bool insertIntoFnEntryBlock=false)
This creates an alloca and inserts it into the entry block if ArraySize is nullptr,...
RValue emitCallExpr(const clang::CallExpr *e, ReturnValueSlot returnValue=ReturnValueSlot())
LValue emitLValue(const clang::Expr *e)
Emit code to compute a designator that specifies the location of the expression.
void emitStoreOfScalar(mlir::Value value, Address addr, bool isVolatile, clang::QualType ty, bool isInit=false, bool isNontemporal=false)
Definition: CIRGenExpr.cpp:312
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
void emitNullInitialization(mlir::Location loc, Address destPtr, QualType ty)
void emitCXXConstructExpr(const clang::CXXConstructExpr *e, AggValueSlot dest)
LValue emitAggExprToLValue(const Expr *e)
static bool hasAggregateEvaluationKind(clang::QualType type)
void emitScalarInit(const clang::Expr *init, mlir::Location loc, LValue lvalue, bool capturedByInit=false)
Definition: CIRGenDecl.cpp:473
LValue emitLValueForFieldInitialization(LValue base, const clang::FieldDecl *field, llvm::StringRef fieldName)
Like emitLValueForField, excpet that if the Field is a reference, this will return the address of the...
Definition: CIRGenExpr.cpp:501
mlir::Value emitScalarExpr(const clang::Expr *e)
Emit the computation of the specified expression of scalar type.
CIRGenBuilderTy & getBuilder()
AggValueSlot::Overlap_t getOverlapForBaseInit(const CXXRecordDecl *rd, const CXXRecordDecl *baseRD, bool isVirtual)
Determine whether a base class initialization may overlap some other object.
LValue makeAddrLValue(Address addr, QualType ty, AlignmentSource source=AlignmentSource::Type)
std::optional< mlir::Location > currSrcLoc
Use to track source locations across nested visitor traversals.
clang::ASTContext & getContext() const
mlir::LogicalResult emitCompoundStmt(const clang::CompoundStmt &s, Address *lastValue=nullptr, AggValueSlot slot=AggValueSlot::ignored())
Definition: CIRGenStmt.cpp:87
void emitStoreThroughLValue(RValue src, LValue dst, bool isInit=false)
Store the specified rvalue into the specified lvalue, where both are guaranteed to the have the same ...
Definition: CIRGenExpr.cpp:246
Address createMemTemp(QualType t, mlir::Location loc, const Twine &name="tmp", Address *alloca=nullptr, mlir::OpBuilder::InsertPoint ip={})
Create a temporary memory object of the given type, with appropriate alignmen and cast it to the defa...
void emitAggExpr(const clang::Expr *e, AggValueSlot slot)
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
const clang::LangOptions & getLangOpts() const
Definition: CIRGenModule.h:107
mlir::Value emitNullConstant(QualType t, mlir::Location loc)
Return the result of value-initializing the given type, i.e.
bool isZeroInitializable(clang::QualType ty)
Return whether a type can be zero-initialized (in the C++ sense) with an LLVM zeroinitializer.
Address getAddress() const
Definition: CIRGenValue.h:211
clang::QualType getType() const
Definition: CIRGenValue.h:202
bool isSimple() const
Definition: CIRGenValue.h:190
This trivial value class is used to represent the result of an expression that is evaluated.
Definition: CIRGenValue.h:33
static RValue get(mlir::Value v)
Definition: CIRGenValue.h:82
Contains the address where the return value of a function can be stored, and whether the address is v...
Definition: CIRGenCall.h:252
Represents binding an expression to a temporary.
Definition: ExprCXX.h:1494
const Expr * getSubExpr() const
Definition: ExprCXX.h:1516
Represents a call to a C++ constructor.
Definition: ExprCXX.h:1549
A default argument (C++ [dcl.fct.default]).
Definition: ExprCXX.h:1271
A use of a default initializer in a constructor or in aggregate initialization.
Definition: ExprCXX.h:1378
Represents an explicit C++ type conversion that uses "functional" notation (C++ [expr....
Definition: ExprCXX.h:1833
Represents a call to an inherited base class constructor from an inheriting constructor.
Definition: ExprCXX.h:1753
Represents a list-initialization with parenthesis.
Definition: ExprCXX.h:5135
SourceRange getSourceRange() const LLVM_READONLY
Definition: ExprCXX.h:5195
Represents a C++ struct/union/class.
Definition: DeclCXX.h:258
A rewritten comparison expression that was originally written using operator syntax.
Definition: ExprCXX.h:286
SourceRange getSourceRange() const LLVM_READONLY
Definition: ExprCXX.h:353
An expression "T()" which creates an rvalue of a non-class type T.
Definition: ExprCXX.h:2198
Implicit construction of a std::initializer_list<T> object from an array temporary within list-initia...
Definition: ExprCXX.h:800
SourceRange getSourceRange() const LLVM_READONLY
Retrieve the source range of the expression.
Definition: ExprCXX.h:828
A C++ throw-expression (C++ [except.throw]).
Definition: ExprCXX.h:1209
A C++ typeid expression (C++ [expr.typeid]), which gets the type_info that corresponds to the supplie...
Definition: ExprCXX.h:848
SourceRange getSourceRange() const LLVM_READONLY
Definition: ExprCXX.h:902
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2879
QualType getCallReturnType(const ASTContext &Ctx) const
getCallReturnType - Get the return type of the call expr.
Definition: Expr.cpp:1599
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition: Expr.h:3612
CastKind getCastKind() const
Definition: Expr.h:3656
static const char * getCastKindName(CastKind CK)
Definition: Expr.cpp:1946
Expr * getSubExpr()
Definition: Expr.h:3662
CharUnits - This is an opaque type for sizes expressed in character units.
Definition: CharUnits.h:38
CharUnits alignmentOfArrayElement(CharUnits elementSize) const
Given that this is the alignment of the first element of an array, return the minimum alignment of an...
Definition: CharUnits.h:214
ChooseExpr - GNU builtin-in function __builtin_choose_expr.
Definition: Expr.h:4784
Represents a 'co_await' expression.
Definition: ExprCXX.h:5363
CompoundLiteralExpr - [C99 6.5.2.5].
Definition: Expr.h:3541
ConstantExpr - An expression that occurs in a constant context and optionally the result of evaluatin...
Definition: Expr.h:1084
Represents a 'co_yield' expression.
Definition: ExprCXX.h:5444
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1272
Represents an expression – generally a full-expression – that introduces cleanups to be run at the en...
Definition: ExprCXX.h:3655
This represents one expression.
Definition: Expr.h:112
QualType getType() const
Definition: Expr.h:144
Represents a member of a struct/union/class.
Definition: Decl.h:3157
Represents a C11 generic selection.
Definition: Expr.h:6114
Represents an implicitly-generated value initialization of an object of a given type.
Definition: Expr.h:5993
Describes an C or C++ initializer list.
Definition: Expr.h:5235
bool isTransparent() const
Is this a transparent initializer list (that is, an InitListExpr that is purely syntactic,...
Definition: Expr.cpp:2457
FieldDecl * getInitializedFieldInUnion()
If this initializes a union, specifies which field in the union to initialize.
Definition: Expr.h:5361
bool hadArrayRangeDesignator() const
Definition: Expr.h:5419
Expr * getArrayFiller()
If this initializer list initializes an array with more elements than there are initializers in the l...
Definition: Expr.h:5337
const Expr * getInit(unsigned Init) const
Definition: Expr.h:5289
ArrayRef< Expr * > inits()
Definition: Expr.h:5285
A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...
Definition: ExprCXX.h:1970
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
Definition: ExprCXX.h:4914
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:3300
Represents a place-holder for an object not to be initialized by anything.
Definition: Expr.h:5813
ObjCIvarRefExpr - A reference to an ObjC instance variable.
Definition: ExprObjC.h:548
An expression that sends a message to the given Objective-C object or class.
Definition: ExprObjC.h:940
OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class.
Definition: Expr.h:1180
ParenExpr - This represents a parenthesized expression, e.g.
Definition: Expr.h:2184
[C99 6.4.2.2] - A predefined identifier such as func.
Definition: Expr.h:2007
PseudoObjectExpr - An expression which accesses a pseudo-object l-value.
Definition: Expr.h:6692
A (possibly-)qualified type.
Definition: TypeBase.h:937
bool isVolatileQualified() const
Determine whether this type is volatile-qualified.
Definition: TypeBase.h:8427
@ DK_nontrivial_c_struct
Definition: TypeBase.h:1538
DestructionKind isDestructedType() const
Returns a nonzero value if objects of this type require non-trivial work to clean up after.
Definition: TypeBase.h:1545
bool isValid() const
StmtExpr - This is the GNU Statement Expression extension: ({int X=4; X;}).
Definition: Expr.h:4531
CompoundStmt * getSubStmt()
Definition: Expr.h:4548
RetTy Visit(PTR(Stmt) S, ParamTys... P)
Definition: StmtVisitor.h:45
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
Definition: StmtVisitor.h:186
Stmt - This represents one statement.
Definition: Stmt.h:85
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:334
StringLiteral - This represents a string literal expression, e.g.
Definition: Expr.h:1801
Represents a reference to a non-type template parameter that has been substituted with a template arg...
Definition: ExprCXX.h:4658
bool isConstantArrayType() const
Definition: TypeBase.h:8683
bool isArrayType() const
Definition: TypeBase.h:8679
bool isReferenceType() const
Definition: TypeBase.h:8604
bool isVariableArrayType() const
Definition: TypeBase.h:8691
RecordDecl * castAsRecordDecl() const
Definition: Type.h:48
bool isRecordType() const
Definition: TypeBase.h:8707
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Definition: Expr.h:2246
Represents a call to the builtin function __builtin_va_arg.
Definition: Expr.h:4893
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
The JSON file list parser is used to communicate input to InstallAPI.
unsigned long uint64_t
static bool emitLifetimeMarkers()
static bool aggValueSlotDestructedFlag()
static bool aggValueSlotGC()
static bool aggValueSlotAlias()
static bool opLoadStoreAtomic()
static bool aggValueSlotVolatile()
static bool constEmitterAggILE()
static bool requiresCleanups()
static bool setNonGC()
clang::CharUnits getPointerAlign() const