Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
213799 views
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
23
using namespace clang;
24
using namespace clang::CIRGen;
25
26
namespace {
27
class 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
49
public:
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
85
static bool isTrivialFiller(Expr *e) {
86
if (!e)
87
return true;
88
89
if (isa<ImplicitValueInitExpr>(e))
90
return true;
91
92
if (auto *ile = dyn_cast<InitListExpr>(e)) {
93
if (ile->getNumInits())
94
return false;
95
return isTrivialFiller(ile->getArrayFiller());
96
}
97
98
if (const auto *cons = dyn_cast_or_null<CXXConstructExpr>(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.
107
void 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(e->getType(), lv);
114
}
115
116
void 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(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(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(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(address, elementType);
168
emitInitializationToLValue(args[i], 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(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(tmpAddr, elementPtrType);
194
cgf.emitStoreThroughLValue(RValue::get(element), 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
Address(currentElement, cirElementType, elementAlign), elementType);
203
204
if (arrayFiller)
205
emitInitializationToLValue(arrayFiller, 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::get(nextElement), tmpLV);
214
}
215
}
216
}
217
218
/// Perform the final copy to destPtr, if desired.
219
void 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("emitFinalDestCopy: non-ignored dest is NYI");
228
}
229
230
void AggExprEmitter::emitInitializationToLValue(Expr *e, LValue lv) {
231
const QualType type = lv.getType();
232
233
if (isa<ImplicitValueInitExpr, CXXScalarValueInitExpr>(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>(e))
241
return;
242
243
if (type->isReferenceType())
244
cgf.cgm.errorNYI("emitInitializationToLValue ReferenceType");
245
246
switch (cgf.getEvaluationKind(type)) {
247
case cir::TEK_Complex:
248
cgf.cgm.errorNYI("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::get(cgf.emitScalarExpr(e)), lv);
262
return;
263
}
264
}
265
266
void AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *e) {
267
AggValueSlot slot = ensureSlot(cgf.getLoc(e->getSourceRange()), e->getType());
268
cgf.emitCXXConstructExpr(e, slot);
269
}
270
271
void 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("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
298
void AggExprEmitter::VisitCallExpr(const CallExpr *e) {
299
if (e->getCallReturnType(cgf.getContext())->isReferenceType()) {
300
cgf.cgm.errorNYI(e->getSourceRange(), "reference return type");
301
return;
302
}
303
304
withReturnValueSlot(
305
e, [&](ReturnValueSlot slot) { return cgf.emitCallExpr(e, slot); });
306
}
307
308
void 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
336
void 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->getInit(0));
342
343
visitCXXParenListOrInitListExpr(
344
e, e->inits(), e->getInitializedFieldInUnion(), e->getArrayFiller());
345
}
346
347
void 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(dest.getAddress(), arrayTy, e->getType(), e, args,
358
arrayFiller);
359
return;
360
}
361
362
cgf.cgm.errorNYI(
363
"visitCXXParenListOrInitListExpr Record or VariableSizeArray type");
364
}
365
366
// TODO(cir): This could be shared with classic codegen.
367
AggValueSlot::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(rd);
379
if (layout.getBaseClassOffset(baseRD) +
380
getContext().getASTRecordLayout(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
388
void CIRGenFunction::emitAggExpr(const Expr *e, AggValueSlot slot) {
389
AggExprEmitter(*this, slot).Visit(const_cast<Expr *>(e));
390
}
391
392
LValue 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(temp, e->getType());
396
emitAggExpr(e, AggValueSlot::forLValue(lv, AggValueSlot::IsNotDestructed,
397
AggValueSlot::IsNotAliased,
398
AggValueSlot::DoesNotOverlap));
399
return lv;
400
}
401
402