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:
105 [[fallthrough]];
106 case CK_NoOp:
107 case CK_UserDefinedConversion:
108 case CK_ConstructorConversion:
110 e->getType()) &&
111 "Implicit cast types must be compatible");
112 Visit(e->getSubExpr());
113 break;
114 default:
115 cgf.cgm.errorNYI(e->getSourceRange(),
116 std::string("AggExprEmitter: VisitCastExpr: ") +
117 e->getCastKindName());
118 break;
119 }
120 }
121 void VisitStmt(Stmt *s) {
122 cgf.cgm.errorNYI(s->getSourceRange(),
123 std::string("AggExprEmitter::VisitStmt: ") +
124 s->getStmtClassName());
125 }
126 void VisitParenExpr(ParenExpr *pe) {
127 cgf.cgm.errorNYI(pe->getSourceRange(), "AggExprEmitter: VisitParenExpr");
128 }
129 void VisitGenericSelectionExpr(GenericSelectionExpr *ge) {
130 cgf.cgm.errorNYI(ge->getSourceRange(),
131 "AggExprEmitter: VisitGenericSelectionExpr");
132 }
133 void VisitCoawaitExpr(CoawaitExpr *e) {
134 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCoawaitExpr");
135 }
136 void VisitCoyieldExpr(CoyieldExpr *e) {
137 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCoyieldExpr");
138 }
139 void VisitUnaryCoawait(UnaryOperator *e) {
140 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitUnaryCoawait");
141 }
142 void VisitUnaryExtension(UnaryOperator *e) {
143 cgf.cgm.errorNYI(e->getSourceRange(),
144 "AggExprEmitter: VisitUnaryExtension");
145 }
146 void VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *e) {
147 cgf.cgm.errorNYI(e->getSourceRange(),
148 "AggExprEmitter: VisitSubstNonTypeTemplateParmExpr");
149 }
150 void VisitConstantExpr(ConstantExpr *e) {
151 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitConstantExpr");
152 }
153 void VisitMemberExpr(MemberExpr *e) {
154 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitMemberExpr");
155 }
156 void VisitUnaryDeref(UnaryOperator *e) {
157 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitUnaryDeref");
158 }
159 void VisitStringLiteral(StringLiteral *e) {
160 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitStringLiteral");
161 }
162 void VisitCompoundLiteralExpr(CompoundLiteralExpr *e) {
163 cgf.cgm.errorNYI(e->getSourceRange(),
164 "AggExprEmitter: VisitCompoundLiteralExpr");
165 }
166 void VisitArraySubscriptExpr(ArraySubscriptExpr *e) {
167 cgf.cgm.errorNYI(e->getSourceRange(),
168 "AggExprEmitter: VisitArraySubscriptExpr");
169 }
170 void VisitPredefinedExpr(const PredefinedExpr *e) {
171 cgf.cgm.errorNYI(e->getSourceRange(),
172 "AggExprEmitter: VisitPredefinedExpr");
173 }
174 void VisitBinaryOperator(const BinaryOperator *e) {
175 cgf.cgm.errorNYI(e->getSourceRange(),
176 "AggExprEmitter: VisitBinaryOperator");
177 }
178 void VisitPointerToDataMemberBinaryOperator(const BinaryOperator *e) {
179 cgf.cgm.errorNYI(e->getSourceRange(),
180 "AggExprEmitter: VisitPointerToDataMemberBinaryOperator");
181 }
182 void VisitBinAssign(const BinaryOperator *e) {
183 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitBinAssign");
184 }
185 void VisitBinComma(const BinaryOperator *e) {
186 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitBinComma");
187 }
188 void VisitBinCmp(const BinaryOperator *e) {
189 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitBinCmp");
190 }
191 void VisitCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *e) {
192 cgf.cgm.errorNYI(e->getSourceRange(),
193 "AggExprEmitter: VisitCXXRewrittenBinaryOperator");
194 }
195 void VisitObjCMessageExpr(ObjCMessageExpr *e) {
196 cgf.cgm.errorNYI(e->getSourceRange(),
197 "AggExprEmitter: VisitObjCMessageExpr");
198 }
199 void VisitObjCIVarRefExpr(ObjCIvarRefExpr *e) {
200 cgf.cgm.errorNYI(e->getSourceRange(),
201 "AggExprEmitter: VisitObjCIVarRefExpr");
202 }
203
204 void VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *e) {
205 cgf.cgm.errorNYI(e->getSourceRange(),
206 "AggExprEmitter: VisitDesignatedInitUpdateExpr");
207 }
208 void VisitAbstractConditionalOperator(const AbstractConditionalOperator *e) {
209 cgf.cgm.errorNYI(e->getSourceRange(),
210 "AggExprEmitter: VisitAbstractConditionalOperator");
211 }
212 void VisitChooseExpr(const ChooseExpr *e) {
213 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitChooseExpr");
214 }
215 void VisitCXXParenListInitExpr(CXXParenListInitExpr *e) {
216 cgf.cgm.errorNYI(e->getSourceRange(),
217 "AggExprEmitter: VisitCXXParenListInitExpr");
218 }
219 void VisitArrayInitLoopExpr(const ArrayInitLoopExpr *e,
220 llvm::Value *outerBegin = nullptr) {
221 cgf.cgm.errorNYI(e->getSourceRange(),
222 "AggExprEmitter: VisitArrayInitLoopExpr");
223 }
224 void VisitImplicitValueInitExpr(ImplicitValueInitExpr *e) {
225 cgf.cgm.errorNYI(e->getSourceRange(),
226 "AggExprEmitter: VisitImplicitValueInitExpr");
227 }
228 void VisitNoInitExpr(NoInitExpr *e) {
229 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitNoInitExpr");
230 }
231 void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *dae) {
232 cgf.cgm.errorNYI(dae->getSourceRange(),
233 "AggExprEmitter: VisitCXXDefaultArgExpr");
234 }
235 void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *die) {
236 cgf.cgm.errorNYI(die->getSourceRange(),
237 "AggExprEmitter: VisitCXXDefaultInitExpr");
238 }
239 void VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *e) {
240 cgf.cgm.errorNYI(e->getSourceRange(),
241 "AggExprEmitter: VisitCXXInheritedCtorInitExpr");
242 }
243 void VisitLambdaExpr(LambdaExpr *e) {
244 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitLambdaExpr");
245 }
246 void VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *e) {
247 cgf.cgm.errorNYI(e->getSourceRange(),
248 "AggExprEmitter: VisitCXXStdInitializerListExpr");
249 }
250
251 void VisitExprWithCleanups(ExprWithCleanups *e) {
252 cgf.cgm.errorNYI(e->getSourceRange(),
253 "AggExprEmitter: VisitExprWithCleanups");
254 }
255 void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *e) {
256 cgf.cgm.errorNYI(e->getSourceRange(),
257 "AggExprEmitter: VisitCXXScalarValueInitExpr");
258 }
259 void VisitCXXTypeidExpr(CXXTypeidExpr *e) {
260 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCXXTypeidExpr");
261 }
262 void VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *e) {
263 cgf.cgm.errorNYI(e->getSourceRange(),
264 "AggExprEmitter: VisitMaterializeTemporaryExpr");
265 }
266 void VisitOpaqueValueExpr(OpaqueValueExpr *e) {
267 cgf.cgm.errorNYI(e->getSourceRange(),
268 "AggExprEmitter: VisitOpaqueValueExpr");
269 }
270
271 void VisitPseudoObjectExpr(PseudoObjectExpr *e) {
272 cgf.cgm.errorNYI(e->getSourceRange(),
273 "AggExprEmitter: VisitPseudoObjectExpr");
274 }
275
276 void VisitVAArgExpr(VAArgExpr *e) {
277 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitVAArgExpr");
278 }
279
280 void VisitCXXThrowExpr(const CXXThrowExpr *e) {
281 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCXXThrowExpr");
282 }
283 void VisitAtomicExpr(AtomicExpr *e) {
284 cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitAtomicExpr");
285 }
286};
287
288} // namespace
289
290static bool isTrivialFiller(Expr *e) {
291 if (!e)
292 return true;
293
294 if (isa<ImplicitValueInitExpr>(e))
295 return true;
296
297 if (auto *ile = dyn_cast<InitListExpr>(e)) {
298 if (ile->getNumInits())
299 return false;
300 return isTrivialFiller(ile->getArrayFiller());
301 }
302
303 if (const auto *cons = dyn_cast_or_null<CXXConstructExpr>(e))
304 return cons->getConstructor()->isDefaultConstructor() &&
305 cons->getConstructor()->isTrivial();
306
307 return false;
308}
309
310/// Given an expression with aggregate type that represents a value lvalue, this
311/// method emits the address of the lvalue, then loads the result into DestPtr.
312void AggExprEmitter::emitAggLoadOfLValue(const Expr *e) {
313 LValue lv = cgf.emitLValue(e);
314
315 // If the type of the l-value is atomic, then do an atomic load.
317
318 emitFinalDestCopy(e->getType(), lv);
319}
320
321void AggExprEmitter::emitArrayInit(Address destPtr, cir::ArrayType arrayTy,
322 QualType arrayQTy, Expr *e,
323 ArrayRef<Expr *> args, Expr *arrayFiller) {
324 CIRGenBuilderTy &builder = cgf.getBuilder();
325 const mlir::Location loc = cgf.getLoc(e->getSourceRange());
326
327 const uint64_t numInitElements = args.size();
328
329 const QualType elementType =
330 cgf.getContext().getAsArrayType(arrayQTy)->getElementType();
331
332 if (elementType.isDestructedType() && cgf.cgm.getLangOpts().Exceptions) {
333 cgf.cgm.errorNYI(loc, "initialized array requires destruction");
334 return;
335 }
336
337 const QualType elementPtrType = cgf.getContext().getPointerType(elementType);
338
339 const mlir::Type cirElementType = cgf.convertType(elementType);
340 const cir::PointerType cirElementPtrType =
341 builder.getPointerTo(cirElementType);
342
343 auto begin = cir::CastOp::create(builder, loc, cirElementPtrType,
344 cir::CastKind::array_to_ptrdecay,
345 destPtr.getPointer());
346
347 const CharUnits elementSize =
348 cgf.getContext().getTypeSizeInChars(elementType);
349 const CharUnits elementAlign =
350 destPtr.getAlignment().alignmentOfArrayElement(elementSize);
351
352 // The 'current element to initialize'. The invariants on this
353 // variable are complicated. Essentially, after each iteration of
354 // the loop, it points to the last initialized element, except
355 // that it points to the beginning of the array before any
356 // elements have been initialized.
357 mlir::Value element = begin;
358
359 // Don't build the 'one' before the cycle to avoid
360 // emmiting the redundant `cir.const 1` instrs.
361 mlir::Value one;
362
363 // Emit the explicit initializers.
364 for (uint64_t i = 0; i != numInitElements; ++i) {
365 // Advance to the next element.
366 if (i > 0) {
367 one = builder.getConstantInt(loc, cgf.PtrDiffTy, i);
368 element = builder.createPtrStride(loc, begin, one);
369 }
370
371 const Address address = Address(element, cirElementType, elementAlign);
372 const LValue elementLV = cgf.makeAddrLValue(address, elementType);
373 emitInitializationToLValue(args[i], elementLV);
374 }
375
376 const uint64_t numArrayElements = arrayTy.getSize();
377
378 // Check whether there's a non-trivial array-fill expression.
379 const bool hasTrivialFiller = isTrivialFiller(arrayFiller);
380
381 // Any remaining elements need to be zero-initialized, possibly
382 // using the filler expression. We can skip this if the we're
383 // emitting to zeroed memory.
384 if (numInitElements != numArrayElements &&
385 !(dest.isZeroed() && hasTrivialFiller &&
386 cgf.getTypes().isZeroInitializable(elementType))) {
387 // Advance to the start of the rest of the array.
388 if (numInitElements) {
389 one = builder.getConstantInt(loc, cgf.PtrDiffTy, 1);
390 element = cir::PtrStrideOp::create(builder, loc, cirElementPtrType,
391 element, one);
392 }
393
394 // Allocate the temporary variable
395 // to store the pointer to first unitialized element
396 const Address tmpAddr = cgf.createTempAlloca(
397 cirElementPtrType, cgf.getPointerAlign(), loc, "arrayinit.temp");
398 LValue tmpLV = cgf.makeAddrLValue(tmpAddr, elementPtrType);
399 cgf.emitStoreThroughLValue(RValue::get(element), tmpLV);
400
401 // Compute the end of array
402 cir::ConstantOp numArrayElementsConst = builder.getConstInt(
403 loc, mlir::cast<cir::IntType>(cgf.PtrDiffTy), numArrayElements);
404 mlir::Value end = cir::PtrStrideOp::create(builder, loc, cirElementPtrType,
405 begin, numArrayElementsConst);
406
407 builder.createDoWhile(
408 loc,
409 /*condBuilder=*/
410 [&](mlir::OpBuilder &b, mlir::Location loc) {
411 cir::LoadOp currentElement = builder.createLoad(loc, tmpAddr);
412 mlir::Type boolTy = cgf.convertType(cgf.getContext().BoolTy);
413 cir::CmpOp cmp = cir::CmpOp::create(
414 builder, loc, boolTy, cir::CmpOpKind::ne, currentElement, end);
415 builder.createCondition(cmp);
416 },
417 /*bodyBuilder=*/
418 [&](mlir::OpBuilder &b, mlir::Location loc) {
419 cir::LoadOp currentElement = builder.createLoad(loc, tmpAddr);
420
422
423 // Emit the actual filler expression.
424 LValue elementLV = cgf.makeAddrLValue(
425 Address(currentElement, cirElementType, elementAlign),
426 elementType);
427 if (arrayFiller)
428 emitInitializationToLValue(arrayFiller, elementLV);
429 else
430 emitNullInitializationToLValue(loc, elementLV);
431
432 // Tell the EH cleanup that we finished with the last element.
433 if (cgf.cgm.getLangOpts().Exceptions) {
434 cgf.cgm.errorNYI(loc, "update destructed array element for EH");
435 return;
436 }
437
438 // Advance pointer and store them to temporary variable
439 cir::ConstantOp one = builder.getConstInt(
440 loc, mlir::cast<cir::IntType>(cgf.PtrDiffTy), 1);
441 auto nextElement = cir::PtrStrideOp::create(
442 builder, loc, cirElementPtrType, currentElement, one);
443 cgf.emitStoreThroughLValue(RValue::get(nextElement), tmpLV);
444
445 builder.createYield(loc);
446 });
447 }
448}
449
450/// Perform the final copy to destPtr, if desired.
451void AggExprEmitter::emitFinalDestCopy(QualType type, const LValue &src) {
452 // If dest is ignored, then we're evaluating an aggregate expression
453 // in a context that doesn't care about the result. Note that loads
454 // from volatile l-values force the existence of a non-ignored
455 // destination.
456 if (dest.isIgnored())
457 return;
458
459 cgf.cgm.errorNYI("emitFinalDestCopy: non-ignored dest is NYI");
460}
461
462void AggExprEmitter::emitInitializationToLValue(Expr *e, LValue lv) {
463 const QualType type = lv.getType();
464
465 if (isa<ImplicitValueInitExpr, CXXScalarValueInitExpr>(e)) {
466 const mlir::Location loc = e->getSourceRange().isValid()
467 ? cgf.getLoc(e->getSourceRange())
468 : *cgf.currSrcLoc;
469 return emitNullInitializationToLValue(loc, lv);
470 }
471
472 if (isa<NoInitExpr>(e))
473 return;
474
475 if (type->isReferenceType())
476 cgf.cgm.errorNYI("emitInitializationToLValue ReferenceType");
477
478 switch (cgf.getEvaluationKind(type)) {
479 case cir::TEK_Complex:
480 cgf.cgm.errorNYI("emitInitializationToLValue TEK_Complex");
481 break;
486 dest.isZeroed()));
487
488 return;
489 case cir::TEK_Scalar:
490 if (lv.isSimple())
491 cgf.emitScalarInit(e, cgf.getLoc(e->getSourceRange()), lv);
492 else
494 return;
495 }
496}
497
498void AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *e) {
499 AggValueSlot slot = ensureSlot(cgf.getLoc(e->getSourceRange()), e->getType());
500 cgf.emitCXXConstructExpr(e, slot);
501}
502
503void AggExprEmitter::emitNullInitializationToLValue(mlir::Location loc,
504 LValue lv) {
505 const QualType type = lv.getType();
506
507 // If the destination slot is already zeroed out before the aggregate is
508 // copied into it, we don't have to emit any zeros here.
509 if (dest.isZeroed() && cgf.getTypes().isZeroInitializable(type))
510 return;
511
512 if (cgf.hasScalarEvaluationKind(type)) {
513 // For non-aggregates, we can store the appropriate null constant.
514 mlir::Value null = cgf.cgm.emitNullConstant(type, loc);
515 if (lv.isSimple()) {
516 cgf.emitStoreOfScalar(null, lv, /* isInitialization */ true);
517 return;
518 }
519
520 cgf.cgm.errorNYI("emitStoreThroughBitfieldLValue");
521 return;
522 }
523
524 // There's a potential optimization opportunity in combining
525 // memsets; that would be easy for arrays, but relatively
526 // difficult for structures with the current code.
527 cgf.emitNullInitialization(loc, lv.getAddress(), lv.getType());
528}
529
530void AggExprEmitter::VisitCallExpr(const CallExpr *e) {
532 cgf.cgm.errorNYI(e->getSourceRange(), "reference return type");
533 return;
534 }
535
536 withReturnValueSlot(
537 e, [&](ReturnValueSlot slot) { return cgf.emitCallExpr(e, slot); });
538}
539
540void AggExprEmitter::withReturnValueSlot(
541 const Expr *e, llvm::function_ref<RValue(ReturnValueSlot)> fn) {
542 QualType retTy = e->getType();
543
545 bool requiresDestruction =
547 if (requiresDestruction)
548 cgf.cgm.errorNYI(
549 e->getSourceRange(),
550 "withReturnValueSlot: return value requiring destruction is NYI");
551
552 // If it makes no observable difference, save a memcpy + temporary.
553 //
554 // We need to always provide our own temporary if destruction is required.
555 // Otherwise, fn will emit its own, notice that it's "unused", and end its
556 // lifetime before we have the chance to emit a proper destructor call.
559
560 Address retAddr = dest.getAddress();
562
565 fn(ReturnValueSlot(retAddr));
566}
567
568void AggExprEmitter::VisitInitListExpr(InitListExpr *e) {
570 llvm_unreachable("GNU array range designator extension");
571
572 if (e->isTransparent())
573 return Visit(e->getInit(0));
574
575 visitCXXParenListOrInitListExpr(
577}
578
579void AggExprEmitter::visitCXXParenListOrInitListExpr(
580 Expr *e, ArrayRef<Expr *> args, FieldDecl *initializedFieldInUnion,
581 Expr *arrayFiller) {
582
583 const AggValueSlot dest =
584 ensureSlot(cgf.getLoc(e->getSourceRange()), e->getType());
585
586 if (e->getType()->isConstantArrayType()) {
587 cir::ArrayType arrayTy =
588 cast<cir::ArrayType>(dest.getAddress().getElementType());
589 emitArrayInit(dest.getAddress(), arrayTy, e->getType(), e, args,
590 arrayFiller);
591 return;
592 } else if (e->getType()->isVariableArrayType()) {
593 cgf.cgm.errorNYI(e->getSourceRange(),
594 "visitCXXParenListOrInitListExpr variable array type");
595 return;
596 }
597
598 if (e->getType()->isArrayType()) {
599 cgf.cgm.errorNYI(e->getSourceRange(),
600 "visitCXXParenListOrInitListExpr array type");
601 return;
602 }
603
604 assert(e->getType()->isRecordType() && "Only support structs/unions here!");
605
606 // Do struct initialization; this code just sets each individual member
607 // to the approprate value. This makes bitfield support automatic;
608 // the disadvantage is that the generated code is more difficult for
609 // the optimizer, especially with bitfields.
610 unsigned numInitElements = args.size();
611 auto *record = e->getType()->castAsRecordDecl();
612
613 // We'll need to enter cleanup scopes in case any of the element
614 // initializers throws an exception.
616
617 unsigned curInitIndex = 0;
618
619 // Emit initialization of base classes.
620 if (auto *cxxrd = dyn_cast<CXXRecordDecl>(record)) {
621 assert(numInitElements >= cxxrd->getNumBases() &&
622 "missing initializer for base class");
623 if (cxxrd->getNumBases() > 0) {
624 cgf.cgm.errorNYI(e->getSourceRange(),
625 "visitCXXParenListOrInitListExpr base class init");
626 return;
627 }
628 }
629
630 LValue destLV = cgf.makeAddrLValue(dest.getAddress(), e->getType());
631
632 if (record->isUnion()) {
633 cgf.cgm.errorNYI(e->getSourceRange(),
634 "visitCXXParenListOrInitListExpr union type");
635 return;
636 }
637
638 // Here we iterate over the fields; this makes it simpler to both
639 // default-initialize fields and skip over unnamed fields.
640 for (const FieldDecl *field : record->fields()) {
641 // We're done once we hit the flexible array member.
642 if (field->getType()->isIncompleteArrayType())
643 break;
644
645 // Always skip anonymous bitfields.
646 if (field->isUnnamedBitField())
647 continue;
648
649 // We're done if we reach the end of the explicit initializers, we
650 // have a zeroed object, and the rest of the fields are
651 // zero-initializable.
652 if (curInitIndex == numInitElements && dest.isZeroed() &&
654 break;
655 LValue lv =
656 cgf.emitLValueForFieldInitialization(destLV, field, field->getName());
657 // We never generate write-barriers for initialized fields.
659
660 if (curInitIndex < numInitElements) {
661 // Store the initializer into the field.
663 cgf, cgf.getLoc(record->getSourceRange())};
664 emitInitializationToLValue(args[curInitIndex++], lv);
665 } else {
666 // We're out of initializers; default-initialize to null
667 emitNullInitializationToLValue(cgf.getLoc(e->getSourceRange()), lv);
668 }
669
670 // Push a destructor if necessary.
671 // FIXME: if we have an array of structures, all explicitly
672 // initialized, we can end up pushing a linear number of cleanups.
673 if (field->getType().isDestructedType()) {
674 cgf.cgm.errorNYI(e->getSourceRange(),
675 "visitCXXParenListOrInitListExpr destructor");
676 return;
677 }
678
679 // From classic codegen, maybe not useful for CIR:
680 // If the GEP didn't get used because of a dead zero init or something
681 // else, clean it up for -O0 builds and general tidiness.
682 }
683}
684
685// TODO(cir): This could be shared with classic codegen.
687 const CXXRecordDecl *rd, const CXXRecordDecl *baseRD, bool isVirtual) {
688 // If the most-derived object is a field declared with [[no_unique_address]],
689 // the tail padding of any virtual base could be reused for other subobjects
690 // of that field's class.
691 if (isVirtual)
693
694 // If the base class is laid out entirely within the nvsize of the derived
695 // class, its tail padding cannot yet be initialized, so we can issue
696 // stores at the full width of the base class.
697 const ASTRecordLayout &layout = getContext().getASTRecordLayout(rd);
698 if (layout.getBaseClassOffset(baseRD) +
699 getContext().getASTRecordLayout(baseRD).getSize() <=
700 layout.getNonVirtualSize())
702
703 // The tail padding may contain values we need to preserve.
705}
706
708 AggExprEmitter(*this, slot).Visit(const_cast<Expr *>(e));
709}
710
712 assert(hasAggregateEvaluationKind(e->getType()) && "Invalid argument!");
714 LValue lv = makeAddrLValue(temp, e->getType());
718 return lv;
719}
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:500
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:3153
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
@ 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