Path: blob/main/contrib/llvm-project/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
213799 views
//===- CIRGenExprAggregrate.cpp - Emit CIR Code from Aggregate Expressions ===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This contains code to emit Aggregate Expr nodes as CIR code.9//10//===----------------------------------------------------------------------===//1112#include "CIRGenBuilder.h"13#include "CIRGenFunction.h"14#include "CIRGenValue.h"15#include "clang/CIR/Dialect/IR/CIRAttrs.h"1617#include "clang/AST/Expr.h"18#include "clang/AST/RecordLayout.h"19#include "clang/AST/StmtVisitor.h"20#include <cstdint>2122using namespace clang;23using namespace clang::CIRGen;2425namespace {26class AggExprEmitter : public StmtVisitor<AggExprEmitter> {2728CIRGenFunction &cgf;29AggValueSlot dest;3031// Calls `fn` with a valid return value slot, potentially creating a temporary32// to do so. If a temporary is created, an appropriate copy into `Dest` will33// be emitted, as will lifetime markers.34//35// The given function should take a ReturnValueSlot, and return an RValue that36// points to said slot.37void withReturnValueSlot(const Expr *e,38llvm::function_ref<RValue(ReturnValueSlot)> fn);3940AggValueSlot ensureSlot(mlir::Location loc, QualType t) {41if (!dest.isIgnored())42return dest;4344cgf.cgm.errorNYI(loc, "Slot for ignored address");45return dest;46}4748public:49AggExprEmitter(CIRGenFunction &cgf, AggValueSlot dest)50: cgf(cgf), dest(dest) {}5152/// Given an expression with aggregate type that represents a value lvalue,53/// this method emits the address of the lvalue, then loads the result into54/// DestPtr.55void emitAggLoadOfLValue(const Expr *e);5657void emitArrayInit(Address destPtr, cir::ArrayType arrayTy, QualType arrayQTy,58Expr *exprToVisit, ArrayRef<Expr *> args,59Expr *arrayFiller);6061/// Perform the final copy to DestPtr, if desired.62void emitFinalDestCopy(QualType type, const LValue &src);6364void emitInitializationToLValue(Expr *e, LValue lv);6566void emitNullInitializationToLValue(mlir::Location loc, LValue lv);6768void Visit(Expr *e) { StmtVisitor<AggExprEmitter>::Visit(e); }6970void VisitCallExpr(const CallExpr *e);7172void VisitDeclRefExpr(DeclRefExpr *e) { emitAggLoadOfLValue(e); }7374void VisitInitListExpr(InitListExpr *e);75void VisitCXXConstructExpr(const CXXConstructExpr *e);7677void visitCXXParenListOrInitListExpr(Expr *e, ArrayRef<Expr *> args,78FieldDecl *initializedFieldInUnion,79Expr *arrayFiller);80};8182} // namespace8384static bool isTrivialFiller(Expr *e) {85if (!e)86return true;8788if (isa<ImplicitValueInitExpr>(e))89return true;9091if (auto *ile = dyn_cast<InitListExpr>(e)) {92if (ile->getNumInits())93return false;94return isTrivialFiller(ile->getArrayFiller());95}9697if (const auto *cons = dyn_cast_or_null<CXXConstructExpr>(e))98return cons->getConstructor()->isDefaultConstructor() &&99cons->getConstructor()->isTrivial();100101return false;102}103104/// Given an expression with aggregate type that represents a value lvalue, this105/// method emits the address of the lvalue, then loads the result into DestPtr.106void AggExprEmitter::emitAggLoadOfLValue(const Expr *e) {107LValue lv = cgf.emitLValue(e);108109// If the type of the l-value is atomic, then do an atomic load.110assert(!cir::MissingFeatures::opLoadStoreAtomic());111112emitFinalDestCopy(e->getType(), lv);113}114115void AggExprEmitter::emitArrayInit(Address destPtr, cir::ArrayType arrayTy,116QualType arrayQTy, Expr *e,117ArrayRef<Expr *> args, Expr *arrayFiller) {118CIRGenBuilderTy &builder = cgf.getBuilder();119const mlir::Location loc = cgf.getLoc(e->getSourceRange());120121const uint64_t numInitElements = args.size();122123const QualType elementType =124cgf.getContext().getAsArrayType(arrayQTy)->getElementType();125126if (elementType.isDestructedType()) {127cgf.cgm.errorNYI(loc, "dtorKind NYI");128return;129}130131const QualType elementPtrType = cgf.getContext().getPointerType(elementType);132133const mlir::Type cirElementType = cgf.convertType(elementType);134const cir::PointerType cirElementPtrType =135builder.getPointerTo(cirElementType);136137auto begin = builder.create<cir::CastOp>(loc, cirElementPtrType,138cir::CastKind::array_to_ptrdecay,139destPtr.getPointer());140141const CharUnits elementSize =142cgf.getContext().getTypeSizeInChars(elementType);143const CharUnits elementAlign =144destPtr.getAlignment().alignmentOfArrayElement(elementSize);145146// The 'current element to initialize'. The invariants on this147// variable are complicated. Essentially, after each iteration of148// the loop, it points to the last initialized element, except149// that it points to the beginning of the array before any150// elements have been initialized.151mlir::Value element = begin;152153// Don't build the 'one' before the cycle to avoid154// emmiting the redundant `cir.const 1` instrs.155mlir::Value one;156157// Emit the explicit initializers.158for (uint64_t i = 0; i != numInitElements; ++i) {159// Advance to the next element.160if (i > 0) {161one = builder.getConstantInt(loc, cgf.PtrDiffTy, i);162element = builder.createPtrStride(loc, begin, one);163}164165const Address address = Address(element, cirElementType, elementAlign);166const LValue elementLV = cgf.makeAddrLValue(address, elementType);167emitInitializationToLValue(args[i], elementLV);168}169170const uint64_t numArrayElements = arrayTy.getSize();171172// Check whether there's a non-trivial array-fill expression.173const bool hasTrivialFiller = isTrivialFiller(arrayFiller);174175// Any remaining elements need to be zero-initialized, possibly176// using the filler expression. We can skip this if the we're177// emitting to zeroed memory.178if (numInitElements != numArrayElements &&179!(dest.isZeroed() && hasTrivialFiller &&180cgf.getTypes().isZeroInitializable(elementType))) {181// Advance to the start of the rest of the array.182if (numInitElements) {183one = builder.getConstantInt(loc, cgf.PtrDiffTy, 1);184element = builder.create<cir::PtrStrideOp>(loc, cirElementPtrType,185element, one);186}187188// Allocate the temporary variable189// to store the pointer to first unitialized element190const Address tmpAddr = cgf.createTempAlloca(191cirElementPtrType, cgf.getPointerAlign(), loc, "arrayinit.temp");192LValue tmpLV = cgf.makeAddrLValue(tmpAddr, elementPtrType);193cgf.emitStoreThroughLValue(RValue::get(element), tmpLV);194195// TODO(CIR): Replace this part later with cir::DoWhileOp196for (unsigned i = numInitElements; i != numArrayElements; ++i) {197cir::LoadOp currentElement = builder.createLoad(loc, tmpAddr);198199// Emit the actual filler expression.200const LValue elementLV = cgf.makeAddrLValue(201Address(currentElement, cirElementType, elementAlign), elementType);202203if (arrayFiller)204emitInitializationToLValue(arrayFiller, elementLV);205else206emitNullInitializationToLValue(loc, elementLV);207208// Advance pointer and store them to temporary variable209one = builder.getConstantInt(loc, cgf.PtrDiffTy, 1);210cir::PtrStrideOp nextElement =211builder.createPtrStride(loc, currentElement, one);212cgf.emitStoreThroughLValue(RValue::get(nextElement), tmpLV);213}214}215}216217/// Perform the final copy to destPtr, if desired.218void AggExprEmitter::emitFinalDestCopy(QualType type, const LValue &src) {219// If dest is ignored, then we're evaluating an aggregate expression220// in a context that doesn't care about the result. Note that loads221// from volatile l-values force the existence of a non-ignored222// destination.223if (dest.isIgnored())224return;225226cgf.cgm.errorNYI("emitFinalDestCopy: non-ignored dest is NYI");227}228229void AggExprEmitter::emitInitializationToLValue(Expr *e, LValue lv) {230const QualType type = lv.getType();231232if (isa<ImplicitValueInitExpr, CXXScalarValueInitExpr>(e)) {233const mlir::Location loc = e->getSourceRange().isValid()234? cgf.getLoc(e->getSourceRange())235: *cgf.currSrcLoc;236return emitNullInitializationToLValue(loc, lv);237}238239if (isa<NoInitExpr>(e))240return;241242if (type->isReferenceType())243cgf.cgm.errorNYI("emitInitializationToLValue ReferenceType");244245switch (cgf.getEvaluationKind(type)) {246case cir::TEK_Complex:247cgf.cgm.errorNYI("emitInitializationToLValue TEK_Complex");248break;249case cir::TEK_Aggregate:250cgf.emitAggExpr(e, AggValueSlot::forLValue(lv, AggValueSlot::IsDestructed,251AggValueSlot::IsNotAliased,252AggValueSlot::MayOverlap,253dest.isZeroed()));254255return;256case cir::TEK_Scalar:257if (lv.isSimple())258cgf.emitScalarInit(e, cgf.getLoc(e->getSourceRange()), lv);259else260cgf.emitStoreThroughLValue(RValue::get(cgf.emitScalarExpr(e)), lv);261return;262}263}264265void AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *e) {266AggValueSlot slot = ensureSlot(cgf.getLoc(e->getSourceRange()), e->getType());267cgf.emitCXXConstructExpr(e, slot);268}269270void AggExprEmitter::emitNullInitializationToLValue(mlir::Location loc,271LValue lv) {272const QualType type = lv.getType();273274// If the destination slot is already zeroed out before the aggregate is275// copied into it, we don't have to emit any zeros here.276if (dest.isZeroed() && cgf.getTypes().isZeroInitializable(type))277return;278279if (cgf.hasScalarEvaluationKind(type)) {280// For non-aggregates, we can store the appropriate null constant.281mlir::Value null = cgf.cgm.emitNullConstant(type, loc);282if (lv.isSimple()) {283cgf.emitStoreOfScalar(null, lv, /* isInitialization */ true);284return;285}286287cgf.cgm.errorNYI("emitStoreThroughBitfieldLValue");288return;289}290291// There's a potential optimization opportunity in combining292// memsets; that would be easy for arrays, but relatively293// difficult for structures with the current code.294cgf.emitNullInitialization(loc, lv.getAddress(), lv.getType());295}296297void AggExprEmitter::VisitCallExpr(const CallExpr *e) {298if (e->getCallReturnType(cgf.getContext())->isReferenceType()) {299cgf.cgm.errorNYI(e->getSourceRange(), "reference return type");300return;301}302303withReturnValueSlot(304e, [&](ReturnValueSlot slot) { return cgf.emitCallExpr(e, slot); });305}306307void AggExprEmitter::withReturnValueSlot(308const Expr *e, llvm::function_ref<RValue(ReturnValueSlot)> fn) {309QualType retTy = e->getType();310311assert(!cir::MissingFeatures::aggValueSlotDestructedFlag());312bool requiresDestruction =313retTy.isDestructedType() == QualType::DK_nontrivial_c_struct;314if (requiresDestruction)315cgf.cgm.errorNYI(316e->getSourceRange(),317"withReturnValueSlot: return value requiring destruction is NYI");318319// If it makes no observable difference, save a memcpy + temporary.320//321// We need to always provide our own temporary if destruction is required.322// Otherwise, fn will emit its own, notice that it's "unused", and end its323// lifetime before we have the chance to emit a proper destructor call.324assert(!cir::MissingFeatures::aggValueSlotAlias());325assert(!cir::MissingFeatures::aggValueSlotGC());326327Address retAddr = dest.getAddress();328assert(!cir::MissingFeatures::emitLifetimeMarkers());329330assert(!cir::MissingFeatures::aggValueSlotVolatile());331assert(!cir::MissingFeatures::aggValueSlotDestructedFlag());332fn(ReturnValueSlot(retAddr));333}334335void AggExprEmitter::VisitInitListExpr(InitListExpr *e) {336if (e->hadArrayRangeDesignator())337llvm_unreachable("GNU array range designator extension");338339if (e->isTransparent())340return Visit(e->getInit(0));341342visitCXXParenListOrInitListExpr(343e, e->inits(), e->getInitializedFieldInUnion(), e->getArrayFiller());344}345346void AggExprEmitter::visitCXXParenListOrInitListExpr(347Expr *e, ArrayRef<Expr *> args, FieldDecl *initializedFieldInUnion,348Expr *arrayFiller) {349350const AggValueSlot dest =351ensureSlot(cgf.getLoc(e->getSourceRange()), e->getType());352353if (e->getType()->isConstantArrayType()) {354cir::ArrayType arrayTy =355cast<cir::ArrayType>(dest.getAddress().getElementType());356emitArrayInit(dest.getAddress(), arrayTy, e->getType(), e, args,357arrayFiller);358return;359}360361cgf.cgm.errorNYI(362"visitCXXParenListOrInitListExpr Record or VariableSizeArray type");363}364365// TODO(cir): This could be shared with classic codegen.366AggValueSlot::Overlap_t CIRGenFunction::getOverlapForBaseInit(367const CXXRecordDecl *rd, const CXXRecordDecl *baseRD, bool isVirtual) {368// If the most-derived object is a field declared with [[no_unique_address]],369// the tail padding of any virtual base could be reused for other subobjects370// of that field's class.371if (isVirtual)372return AggValueSlot::MayOverlap;373374// If the base class is laid out entirely within the nvsize of the derived375// class, its tail padding cannot yet be initialized, so we can issue376// stores at the full width of the base class.377const ASTRecordLayout &layout = getContext().getASTRecordLayout(rd);378if (layout.getBaseClassOffset(baseRD) +379getContext().getASTRecordLayout(baseRD).getSize() <=380layout.getNonVirtualSize())381return AggValueSlot::DoesNotOverlap;382383// The tail padding may contain values we need to preserve.384return AggValueSlot::MayOverlap;385}386387void CIRGenFunction::emitAggExpr(const Expr *e, AggValueSlot slot) {388AggExprEmitter(*this, slot).Visit(const_cast<Expr *>(e));389}390391LValue CIRGenFunction::emitAggExprToLValue(const Expr *e) {392assert(hasAggregateEvaluationKind(e->getType()) && "Invalid argument!");393Address temp = createMemTemp(e->getType(), getLoc(e->getSourceRange()));394LValue lv = makeAddrLValue(temp, e->getType());395emitAggExpr(e, AggValueSlot::forLValue(lv, AggValueSlot::IsNotDestructed,396AggValueSlot::IsNotAliased,397AggValueSlot::DoesNotOverlap));398return lv;399}400401402