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"
16#include "clang/CIR/Dialect/IR/CIRAttrs.h"
17
18#include "clang/AST/Expr.h"
19#include "clang/AST/RecordLayout.h"
20#include "clang/AST/StmtVisitor.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
69 void Visit(Expr *e) { StmtVisitor<AggExprEmitter>::Visit(e); }
70
71 void VisitCallExpr(const CallExpr *e);
72
73 void VisitDeclRefExpr(DeclRefExpr *e) { emitAggLoadOfLValue(e); }
74
75 void VisitInitListExpr(InitListExpr *e);
76 void VisitCXXConstructExpr(const CXXConstructExpr *e);
77
78 void visitCXXParenListOrInitListExpr(Expr *e, ArrayRef<Expr *> args,
79 FieldDecl *initializedFieldInUnion,
80 Expr *arrayFiller);
81};
82
83} // namespace
84
85static bool isTrivialFiller(Expr *e) {
86 if (!e)
87 return true;
88
89 if (isa<ImplicitValueInitExpr>(Val: e))
90 return true;
91
92 if (auto *ile = dyn_cast<InitListExpr>(Val: e)) {
93 if (ile->getNumInits())
94 return false;
95 return isTrivialFiller(e: ile->getArrayFiller());
96 }
97
98 if (const auto *cons = dyn_cast_or_null<CXXConstructExpr>(Val: e))
99 return cons->getConstructor()->isDefaultConstructor() &&
100 cons->getConstructor()->isTrivial();
101
102 return false;
103}
104
105/// Given an expression with aggregate type that represents a value lvalue, this
106/// method emits the address of the lvalue, then loads the result into DestPtr.
107void AggExprEmitter::emitAggLoadOfLValue(const Expr *e) {
108 LValue lv = cgf.emitLValue(e);
109
110 // If the type of the l-value is atomic, then do an atomic load.
111 assert(!cir::MissingFeatures::opLoadStoreAtomic());
112
113 emitFinalDestCopy(type: e->getType(), src: lv);
114}
115
116void AggExprEmitter::emitArrayInit(Address destPtr, cir::ArrayType arrayTy,
117 QualType arrayQTy, Expr *e,
118 ArrayRef<Expr *> args, Expr *arrayFiller) {
119 CIRGenBuilderTy &builder = cgf.getBuilder();
120 const mlir::Location loc = cgf.getLoc(e->getSourceRange());
121
122 const uint64_t numInitElements = args.size();
123
124 const QualType elementType =
125 cgf.getContext().getAsArrayType(T: arrayQTy)->getElementType();
126
127 if (elementType.isDestructedType()) {
128 cgf.cgm.errorNYI(loc, "dtorKind NYI");
129 return;
130 }
131
132 const QualType elementPtrType = cgf.getContext().getPointerType(T: elementType);
133
134 const mlir::Type cirElementType = cgf.convertType(elementType);
135 const cir::PointerType cirElementPtrType =
136 builder.getPointerTo(cirElementType);
137
138 auto begin = builder.create<cir::CastOp>(loc, cirElementPtrType,
139 cir::CastKind::array_to_ptrdecay,
140 destPtr.getPointer());
141
142 const CharUnits elementSize =
143 cgf.getContext().getTypeSizeInChars(T: elementType);
144 const CharUnits elementAlign =
145 destPtr.getAlignment().alignmentOfArrayElement(elementSize);
146
147 // The 'current element to initialize'. The invariants on this
148 // variable are complicated. Essentially, after each iteration of
149 // the loop, it points to the last initialized element, except
150 // that it points to the beginning of the array before any
151 // elements have been initialized.
152 mlir::Value element = begin;
153
154 // Don't build the 'one' before the cycle to avoid
155 // emmiting the redundant `cir.const 1` instrs.
156 mlir::Value one;
157
158 // Emit the explicit initializers.
159 for (uint64_t i = 0; i != numInitElements; ++i) {
160 // Advance to the next element.
161 if (i > 0) {
162 one = builder.getConstantInt(loc, cgf.PtrDiffTy, i);
163 element = builder.createPtrStride(loc, begin, one);
164 }
165
166 const Address address = Address(element, cirElementType, elementAlign);
167 const LValue elementLV = cgf.makeAddrLValue(addr: address, ty: elementType);
168 emitInitializationToLValue(e: args[i], lv: elementLV);
169 }
170
171 const uint64_t numArrayElements = arrayTy.getSize();
172
173 // Check whether there's a non-trivial array-fill expression.
174 const bool hasTrivialFiller = isTrivialFiller(e: arrayFiller);
175
176 // Any remaining elements need to be zero-initialized, possibly
177 // using the filler expression. We can skip this if the we're
178 // emitting to zeroed memory.
179 if (numInitElements != numArrayElements &&
180 !(dest.isZeroed() && hasTrivialFiller &&
181 cgf.getTypes().isZeroInitializable(elementType))) {
182 // Advance to the start of the rest of the array.
183 if (numInitElements) {
184 one = builder.getConstantInt(loc, cgf.PtrDiffTy, 1);
185 element = builder.create<cir::PtrStrideOp>(loc, cirElementPtrType,
186 element, one);
187 }
188
189 // Allocate the temporary variable
190 // to store the pointer to first unitialized element
191 const Address tmpAddr = cgf.createTempAlloca(
192 cirElementPtrType, cgf.getPointerAlign(), loc, "arrayinit.temp");
193 LValue tmpLV = cgf.makeAddrLValue(addr: tmpAddr, ty: elementPtrType);
194 cgf.emitStoreThroughLValue(RValue::src: get(element), dst: tmpLV);
195
196 // TODO(CIR): Replace this part later with cir::DoWhileOp
197 for (unsigned i = numInitElements; i != numArrayElements; ++i) {
198 cir::LoadOp currentElement = builder.createLoad(loc, tmpAddr);
199
200 // Emit the actual filler expression.
201 const LValue elementLV = cgf.makeAddrLValue(
202 addr: Address(currentElement, cirElementType, elementAlign), ty: elementType);
203
204 if (arrayFiller)
205 emitInitializationToLValue(e: arrayFiller, lv: elementLV);
206 else
207 emitNullInitializationToLValue(loc, elementLV);
208
209 // Advance pointer and store them to temporary variable
210 one = builder.getConstantInt(loc, cgf.PtrDiffTy, 1);
211 cir::PtrStrideOp nextElement =
212 builder.createPtrStride(loc, currentElement, one);
213 cgf.emitStoreThroughLValue(RValue::src: get(nextElement), dst: tmpLV);
214 }
215 }
216}
217
218/// Perform the final copy to destPtr, if desired.
219void AggExprEmitter::emitFinalDestCopy(QualType type, const LValue &src) {
220 // If dest is ignored, then we're evaluating an aggregate expression
221 // in a context that doesn't care about the result. Note that loads
222 // from volatile l-values force the existence of a non-ignored
223 // destination.
224 if (dest.isIgnored())
225 return;
226
227 cgf.cgm.errorNYI(feature: "emitFinalDestCopy: non-ignored dest is NYI");
228}
229
230void AggExprEmitter::emitInitializationToLValue(Expr *e, LValue lv) {
231 const QualType type = lv.getType();
232
233 if (isa<ImplicitValueInitExpr, CXXScalarValueInitExpr>(Val: e)) {
234 const mlir::Location loc = e->getSourceRange().isValid()
235 ? cgf.getLoc(e->getSourceRange())
236 : *cgf.currSrcLoc;
237 return emitNullInitializationToLValue(loc, lv);
238 }
239
240 if (isa<NoInitExpr>(Val: e))
241 return;
242
243 if (type->isReferenceType())
244 cgf.cgm.errorNYI(feature: "emitInitializationToLValue ReferenceType");
245
246 switch (cgf.getEvaluationKind(type)) {
247 case cir::TEK_Complex:
248 cgf.cgm.errorNYI(feature: "emitInitializationToLValue TEK_Complex");
249 break;
250 case cir::TEK_Aggregate:
251 cgf.emitAggExpr(e, AggValueSlot::forLValue(lv, AggValueSlot::IsDestructed,
252 AggValueSlot::IsNotAliased,
253 AggValueSlot::MayOverlap,
254 dest.isZeroed()));
255
256 return;
257 case cir::TEK_Scalar:
258 if (lv.isSimple())
259 cgf.emitScalarInit(e, cgf.getLoc(e->getSourceRange()), lv);
260 else
261 cgf.emitStoreThroughLValue(RValue::src: get(cgf.emitScalarExpr(e)), dst: lv);
262 return;
263 }
264}
265
266void AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *e) {
267 AggValueSlot slot = ensureSlot(cgf.getLoc(e->getSourceRange()), e->getType());
268 cgf.emitCXXConstructExpr(e, dest: slot);
269}
270
271void AggExprEmitter::emitNullInitializationToLValue(mlir::Location loc,
272 LValue lv) {
273 const QualType type = lv.getType();
274
275 // If the destination slot is already zeroed out before the aggregate is
276 // copied into it, we don't have to emit any zeros here.
277 if (dest.isZeroed() && cgf.getTypes().isZeroInitializable(type))
278 return;
279
280 if (cgf.hasScalarEvaluationKind(type)) {
281 // For non-aggregates, we can store the appropriate null constant.
282 mlir::Value null = cgf.cgm.emitNullConstant(type, loc);
283 if (lv.isSimple()) {
284 cgf.emitStoreOfScalar(null, lv, /* isInitialization */ true);
285 return;
286 }
287
288 cgf.cgm.errorNYI(feature: "emitStoreThroughBitfieldLValue");
289 return;
290 }
291
292 // There's a potential optimization opportunity in combining
293 // memsets; that would be easy for arrays, but relatively
294 // difficult for structures with the current code.
295 cgf.emitNullInitialization(loc, lv.getAddress(), lv.getType());
296}
297
298void AggExprEmitter::VisitCallExpr(const CallExpr *e) {
299 if (e->getCallReturnType(Ctx: cgf.getContext())->isReferenceType()) {
300 cgf.cgm.errorNYI(e->getSourceRange(), "reference return type");
301 return;
302 }
303
304 withReturnValueSlot(
305 e, fn: [&](ReturnValueSlot slot) { return cgf.emitCallExpr(e, returnValue: slot); });
306}
307
308void AggExprEmitter::withReturnValueSlot(
309 const Expr *e, llvm::function_ref<RValue(ReturnValueSlot)> fn) {
310 QualType retTy = e->getType();
311
312 assert(!cir::MissingFeatures::aggValueSlotDestructedFlag());
313 bool requiresDestruction =
314 retTy.isDestructedType() == QualType::DK_nontrivial_c_struct;
315 if (requiresDestruction)
316 cgf.cgm.errorNYI(
317 e->getSourceRange(),
318 "withReturnValueSlot: return value requiring destruction is NYI");
319
320 // If it makes no observable difference, save a memcpy + temporary.
321 //
322 // We need to always provide our own temporary if destruction is required.
323 // Otherwise, fn will emit its own, notice that it's "unused", and end its
324 // lifetime before we have the chance to emit a proper destructor call.
325 assert(!cir::MissingFeatures::aggValueSlotAlias());
326 assert(!cir::MissingFeatures::aggValueSlotGC());
327
328 Address retAddr = dest.getAddress();
329 assert(!cir::MissingFeatures::emitLifetimeMarkers());
330
331 assert(!cir::MissingFeatures::aggValueSlotVolatile());
332 assert(!cir::MissingFeatures::aggValueSlotDestructedFlag());
333 fn(ReturnValueSlot(retAddr));
334}
335
336void AggExprEmitter::VisitInitListExpr(InitListExpr *e) {
337 if (e->hadArrayRangeDesignator())
338 llvm_unreachable("GNU array range designator extension");
339
340 if (e->isTransparent())
341 return Visit(e: e->getInit(Init: 0));
342
343 visitCXXParenListOrInitListExpr(
344 e, args: e->inits(), initializedFieldInUnion: e->getInitializedFieldInUnion(), arrayFiller: e->getArrayFiller());
345}
346
347void AggExprEmitter::visitCXXParenListOrInitListExpr(
348 Expr *e, ArrayRef<Expr *> args, FieldDecl *initializedFieldInUnion,
349 Expr *arrayFiller) {
350
351 const AggValueSlot dest =
352 ensureSlot(cgf.getLoc(e->getSourceRange()), e->getType());
353
354 if (e->getType()->isConstantArrayType()) {
355 cir::ArrayType arrayTy =
356 cast<cir::ArrayType>(dest.getAddress().getElementType());
357 emitArrayInit(destPtr: dest.getAddress(), arrayTy: arrayTy, arrayQTy: e->getType(), e, args,
358 arrayFiller);
359 return;
360 }
361
362 cgf.cgm.errorNYI(
363 feature: "visitCXXParenListOrInitListExpr Record or VariableSizeArray type");
364}
365
366// TODO(cir): This could be shared with classic codegen.
367AggValueSlot::Overlap_t CIRGenFunction::getOverlapForBaseInit(
368 const CXXRecordDecl *rd, const CXXRecordDecl *baseRD, bool isVirtual) {
369 // If the most-derived object is a field declared with [[no_unique_address]],
370 // the tail padding of any virtual base could be reused for other subobjects
371 // of that field's class.
372 if (isVirtual)
373 return AggValueSlot::MayOverlap;
374
375 // If the base class is laid out entirely within the nvsize of the derived
376 // class, its tail padding cannot yet be initialized, so we can issue
377 // stores at the full width of the base class.
378 const ASTRecordLayout &layout = getContext().getASTRecordLayout(D: rd);
379 if (layout.getBaseClassOffset(Base: baseRD) +
380 getContext().getASTRecordLayout(D: baseRD).getSize() <=
381 layout.getNonVirtualSize())
382 return AggValueSlot::DoesNotOverlap;
383
384 // The tail padding may contain values we need to preserve.
385 return AggValueSlot::MayOverlap;
386}
387
388void CIRGenFunction::emitAggExpr(const Expr *e, AggValueSlot slot) {
389 AggExprEmitter(*this, slot).Visit(e: const_cast<Expr *>(e));
390}
391
392LValue CIRGenFunction::emitAggExprToLValue(const Expr *e) {
393 assert(hasAggregateEvaluationKind(e->getType()) && "Invalid argument!");
394 Address temp = createMemTemp(e->getType(), getLoc(e->getSourceRange()));
395 LValue lv = makeAddrLValue(addr: temp, ty: e->getType());
396 emitAggExpr(e, slot: AggValueSlot::forLValue(LV: lv, isDestructed: AggValueSlot::IsNotDestructed,
397 isAliased: AggValueSlot::IsNotAliased,
398 mayOverlap: AggValueSlot::DoesNotOverlap));
399 return lv;
400}
401

source code of clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp