summaryrefslogtreecommitdiff
path: root/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp')
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp311
1 files changed, 306 insertions, 5 deletions
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index 2a3c98c45825..dc34d2b3baa8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -62,12 +62,19 @@ public:
/// Perform the final copy to DestPtr, if desired.
void emitFinalDestCopy(QualType type, const LValue &src);
+ void emitCopy(QualType type, const AggValueSlot &dest,
+ const AggValueSlot &src);
+
void emitInitializationToLValue(Expr *e, LValue lv);
void emitNullInitializationToLValue(mlir::Location loc, LValue lv);
void Visit(Expr *e) { StmtVisitor<AggExprEmitter>::Visit(e); }
+ void VisitArraySubscriptExpr(ArraySubscriptExpr *e) {
+ emitAggLoadOfLValue(e);
+ }
+
void VisitCallExpr(const CallExpr *e);
void VisitStmtExpr(const StmtExpr *e) {
CIRGenFunction::StmtExprEvaluation eval(cgf);
@@ -84,6 +91,197 @@ public:
void visitCXXParenListOrInitListExpr(Expr *e, ArrayRef<Expr *> args,
FieldDecl *initializedFieldInUnion,
Expr *arrayFiller);
+ void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *die) {
+ CIRGenFunction::CXXDefaultInitExprScope Scope(cgf, die);
+ Visit(die->getExpr());
+ }
+ void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *e) {
+ assert(!cir::MissingFeatures::aggValueSlotDestructedFlag());
+ Visit(e->getSubExpr());
+ }
+
+ // Stubs -- These should be moved up when they are implemented.
+ void VisitCastExpr(CastExpr *e) {
+ switch (e->getCastKind()) {
+ case CK_LValueToRValue:
+ // If we're loading from a volatile type, force the destination
+ // into existence.
+ if (e->getSubExpr()->getType().isVolatileQualified())
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: volatile lvalue-to-rvalue cast");
+ [[fallthrough]];
+ case CK_NoOp:
+ case CK_UserDefinedConversion:
+ case CK_ConstructorConversion:
+ assert(cgf.getContext().hasSameUnqualifiedType(e->getSubExpr()->getType(),
+ e->getType()) &&
+ "Implicit cast types must be compatible");
+ Visit(e->getSubExpr());
+ break;
+ default:
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ std::string("AggExprEmitter: VisitCastExpr: ") +
+ e->getCastKindName());
+ break;
+ }
+ }
+ void VisitStmt(Stmt *s) {
+ cgf.cgm.errorNYI(s->getSourceRange(),
+ std::string("AggExprEmitter::VisitStmt: ") +
+ s->getStmtClassName());
+ }
+ void VisitParenExpr(ParenExpr *pe) {
+ cgf.cgm.errorNYI(pe->getSourceRange(), "AggExprEmitter: VisitParenExpr");
+ }
+ void VisitGenericSelectionExpr(GenericSelectionExpr *ge) {
+ cgf.cgm.errorNYI(ge->getSourceRange(),
+ "AggExprEmitter: VisitGenericSelectionExpr");
+ }
+ void VisitCoawaitExpr(CoawaitExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCoawaitExpr");
+ }
+ void VisitCoyieldExpr(CoyieldExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCoyieldExpr");
+ }
+ void VisitUnaryCoawait(UnaryOperator *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitUnaryCoawait");
+ }
+ void VisitUnaryExtension(UnaryOperator *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitUnaryExtension");
+ }
+ void VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitSubstNonTypeTemplateParmExpr");
+ }
+ void VisitConstantExpr(ConstantExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitConstantExpr");
+ }
+ void VisitMemberExpr(MemberExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitMemberExpr");
+ }
+ void VisitUnaryDeref(UnaryOperator *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitUnaryDeref");
+ }
+ void VisitStringLiteral(StringLiteral *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitStringLiteral");
+ }
+ void VisitCompoundLiteralExpr(CompoundLiteralExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitCompoundLiteralExpr");
+ }
+ void VisitPredefinedExpr(const PredefinedExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitPredefinedExpr");
+ }
+ void VisitBinaryOperator(const BinaryOperator *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitBinaryOperator");
+ }
+ void VisitPointerToDataMemberBinaryOperator(const BinaryOperator *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitPointerToDataMemberBinaryOperator");
+ }
+ void VisitBinAssign(const BinaryOperator *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitBinAssign");
+ }
+ void VisitBinComma(const BinaryOperator *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitBinComma");
+ }
+ void VisitBinCmp(const BinaryOperator *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitBinCmp");
+ }
+ void VisitCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitCXXRewrittenBinaryOperator");
+ }
+ void VisitObjCMessageExpr(ObjCMessageExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitObjCMessageExpr");
+ }
+ void VisitObjCIVarRefExpr(ObjCIvarRefExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitObjCIVarRefExpr");
+ }
+
+ void VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitDesignatedInitUpdateExpr");
+ }
+ void VisitAbstractConditionalOperator(const AbstractConditionalOperator *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitAbstractConditionalOperator");
+ }
+ void VisitChooseExpr(const ChooseExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitChooseExpr");
+ }
+ void VisitCXXParenListInitExpr(CXXParenListInitExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitCXXParenListInitExpr");
+ }
+ void VisitArrayInitLoopExpr(const ArrayInitLoopExpr *e,
+ llvm::Value *outerBegin = nullptr) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitArrayInitLoopExpr");
+ }
+ void VisitImplicitValueInitExpr(ImplicitValueInitExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitImplicitValueInitExpr");
+ }
+ void VisitNoInitExpr(NoInitExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitNoInitExpr");
+ }
+ void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *dae) {
+ cgf.cgm.errorNYI(dae->getSourceRange(),
+ "AggExprEmitter: VisitCXXDefaultArgExpr");
+ }
+ void VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitCXXInheritedCtorInitExpr");
+ }
+ void VisitLambdaExpr(LambdaExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitLambdaExpr");
+ }
+ void VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitCXXStdInitializerListExpr");
+ }
+
+ void VisitExprWithCleanups(ExprWithCleanups *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitExprWithCleanups");
+ }
+ void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitCXXScalarValueInitExpr");
+ }
+ void VisitCXXTypeidExpr(CXXTypeidExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCXXTypeidExpr");
+ }
+ void VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitMaterializeTemporaryExpr");
+ }
+ void VisitOpaqueValueExpr(OpaqueValueExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitOpaqueValueExpr");
+ }
+
+ void VisitPseudoObjectExpr(PseudoObjectExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "AggExprEmitter: VisitPseudoObjectExpr");
+ }
+
+ void VisitVAArgExpr(VAArgExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitVAArgExpr");
+ }
+
+ void VisitCXXThrowExpr(const CXXThrowExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCXXThrowExpr");
+ }
+ void VisitAtomicExpr(AtomicExpr *e) {
+ cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitAtomicExpr");
+ }
};
} // namespace
@@ -257,7 +455,31 @@ void AggExprEmitter::emitFinalDestCopy(QualType type, const LValue &src) {
if (dest.isIgnored())
return;
- cgf.cgm.errorNYI("emitFinalDestCopy: non-ignored dest is NYI");
+ assert(!cir::MissingFeatures::aggValueSlotVolatile());
+ assert(!cir::MissingFeatures::aggEmitFinalDestCopyRValue());
+ assert(!cir::MissingFeatures::aggValueSlotGC());
+
+ AggValueSlot srcAgg = AggValueSlot::forLValue(src, AggValueSlot::IsDestructed,
+ AggValueSlot::IsAliased,
+ AggValueSlot::MayOverlap);
+ emitCopy(type, dest, srcAgg);
+}
+
+/// Perform a copy from the source into the destination.
+///
+/// \param type - the type of the aggregate being copied; qualifiers are
+/// ignored
+void AggExprEmitter::emitCopy(QualType type, const AggValueSlot &dest,
+ const AggValueSlot &src) {
+ assert(!cir::MissingFeatures::aggValueSlotGC());
+
+ // If the result of the assignment is used, copy the LHS there also.
+ // It's volatile if either side is. Use the minimum alignment of
+ // the two sides.
+ LValue destLV = cgf.makeAddrLValue(dest.getAddress(), type);
+ LValue srcLV = cgf.makeAddrLValue(src.getAddress(), type);
+ assert(!cir::MissingFeatures::aggValueSlotVolatile());
+ cgf.emitAggregateCopy(destLV, srcLV, type, dest.mayOverlap());
}
void AggExprEmitter::emitInitializationToLValue(Expr *e, LValue lv) {
@@ -409,10 +631,7 @@ void AggExprEmitter::visitCXXParenListOrInitListExpr(
// the disadvantage is that the generated code is more difficult for
// the optimizer, especially with bitfields.
unsigned numInitElements = args.size();
- RecordDecl *record = e->getType()
- ->castAs<RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
+ auto *record = e->getType()->castAsRecordDecl();
// We'll need to enter cleanup scopes in case any of the element
// initializers throws an exception.
@@ -512,6 +731,88 @@ void CIRGenFunction::emitAggExpr(const Expr *e, AggValueSlot slot) {
AggExprEmitter(*this, slot).Visit(const_cast<Expr *>(e));
}
+void CIRGenFunction::emitAggregateCopy(LValue dest, LValue src, QualType ty,
+ AggValueSlot::Overlap_t mayOverlap) {
+ // TODO(cir): this function needs improvements, commented code for now since
+ // this will be touched again soon.
+ assert(!ty->isAnyComplexType() && "Unexpected copy of complex");
+
+ Address destPtr = dest.getAddress();
+ Address srcPtr = src.getAddress();
+
+ if (getLangOpts().CPlusPlus) {
+ if (auto *record = ty->getAsCXXRecordDecl()) {
+ assert((record->hasTrivialCopyConstructor() ||
+ record->hasTrivialCopyAssignment() ||
+ record->hasTrivialMoveConstructor() ||
+ record->hasTrivialMoveAssignment() ||
+ record->hasAttr<TrivialABIAttr>() || record->isUnion()) &&
+ "Trying to aggregate-copy a type without a trivial copy/move "
+ "constructor or assignment operator");
+ // Ignore empty classes in C++.
+ if (record->isEmpty())
+ return;
+ }
+ }
+
+ assert(!cir::MissingFeatures::cudaSupport());
+
+ // Aggregate assignment turns into llvm.memcpy. This is almost valid per
+ // C99 6.5.16.1p3, which states "If the value being stored in an object is
+ // read from another object that overlaps in anyway the storage of the first
+ // object, then the overlap shall be exact and the two objects shall have
+ // qualified or unqualified versions of a compatible type."
+ //
+ // memcpy is not defined if the source and destination pointers are exactly
+ // equal, but other compilers do this optimization, and almost every memcpy
+ // implementation handles this case safely. If there is a libc that does not
+ // safely handle this, we can add a target hook.
+
+ // Get data size info for this aggregate. Don't copy the tail padding if this
+ // might be a potentially-overlapping subobject, since the tail padding might
+ // be occupied by a different object. Otherwise, copying it is fine.
+ TypeInfoChars typeInfo;
+ if (mayOverlap)
+ typeInfo = getContext().getTypeInfoDataSizeInChars(ty);
+ else
+ typeInfo = getContext().getTypeInfoInChars(ty);
+
+ assert(!cir::MissingFeatures::aggValueSlotVolatile());
+
+ // NOTE(cir): original codegen would normally convert destPtr and srcPtr to
+ // i8* since memcpy operates on bytes. We don't need that in CIR because
+ // cir.copy will operate on any CIR pointer that points to a sized type.
+
+ // Don't do any of the memmove_collectable tests if GC isn't set.
+ if (cgm.getLangOpts().getGC() != LangOptions::NonGC)
+ cgm.errorNYI("emitAggregateCopy: GC");
+
+ [[maybe_unused]] cir::CopyOp copyOp =
+ builder.createCopy(destPtr.getPointer(), srcPtr.getPointer());
+
+ assert(!cir::MissingFeatures::opTBAA());
+}
+
+// TODO(cir): This could be shared with classic codegen.
+AggValueSlot::Overlap_t
+CIRGenFunction::getOverlapForFieldInit(const FieldDecl *fd) {
+ if (!fd->hasAttr<NoUniqueAddressAttr>() || !fd->getType()->isRecordType())
+ return AggValueSlot::DoesNotOverlap;
+
+ // If the field lies entirely within the enclosing class's nvsize, its tail
+ // padding cannot overlap any already-initialized object. (The only subobjects
+ // with greater addresses that might already be initialized are vbases.)
+ const RecordDecl *classRD = fd->getParent();
+ const ASTRecordLayout &layout = getContext().getASTRecordLayout(classRD);
+ if (layout.getFieldOffset(fd->getFieldIndex()) +
+ getContext().getTypeSize(fd->getType()) <=
+ (uint64_t)getContext().toBits(layout.getNonVirtualSize()))
+ return AggValueSlot::DoesNotOverlap;
+
+ // The tail padding may contain values we need to preserve.
+ return AggValueSlot::MayOverlap;
+}
+
LValue CIRGenFunction::emitAggExprToLValue(const Expr *e) {
assert(hasAggregateEvaluationKind(e->getType()) && "Invalid argument!");
Address temp = createMemTemp(e->getType(), getLoc(e->getSourceRange()));