@@ -60,6 +60,23 @@ CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const {
6060 return *this ;
6161}
6262
63+ void CIRGenFunction::emitAggregateStore (mlir::Value value, Address dest) {
64+ // In classic codegen:
65+ // Function to store a first-class aggregate into memory. We prefer to
66+ // store the elements rather than the aggregate to be more friendly to
67+ // fast-isel.
68+ // In CIR codegen:
69+ // Emit the most simple cir.store possible (e.g. a store for a whole
70+ // record), which can later be broken down in other CIR levels (or prior
71+ // to dialect codegen).
72+
73+ // Stored result for the callers of this function expected to be in the same
74+ // scope as the value, don't make assumptions about current insertion point.
75+ mlir::OpBuilder::InsertionGuard guard (builder);
76+ builder.setInsertionPointAfter (value.getDefiningOp ());
77+ builder.createStore (*currSrcLoc, value, dest);
78+ }
79+
6380// / Returns the canonical formal type of the given C++ method.
6481static CanQual<FunctionProtoType> getFormalType (const CXXMethodDecl *md) {
6582 return md->getType ()
@@ -439,8 +456,49 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
439456 assert (!cir::MissingFeatures::opCallBitcastArg ());
440457 cirCallArgs[argNo] = v;
441458 } else {
442- assert (!cir::MissingFeatures::opCallAggregateArgs ());
443- cgm.errorNYI (" emitCall: aggregate function call argument" );
459+ Address src = Address::invalid ();
460+ if (!arg.isAggregate ())
461+ cgm.errorNYI (loc, " emitCall: non-aggregate call argument" );
462+ else
463+ src = arg.hasLValue () ? arg.getKnownLValue ().getAddress ()
464+ : arg.getKnownRValue ().getAggregateAddress ();
465+
466+ // Fast-isel and the optimizer generally like scalar values better than
467+ // FCAs, so we flatten them if this is safe to do for this argument.
468+ auto argRecordTy = cast<cir::RecordType>(argType);
469+ mlir::Type srcTy = src.getElementType ();
470+ // FIXME(cir): get proper location for each argument.
471+ mlir::Location argLoc = loc;
472+
473+ // If the source type is smaller than the destination type of the
474+ // coerce-to logic, copy the source value into a temp alloca the size
475+ // of the destination type to allow loading all of it. The bits past
476+ // the source value are left undef.
477+ // FIXME(cir): add data layout info and compare sizes instead of
478+ // matching the types.
479+ //
480+ // uint64_t SrcSize = CGM.getDataLayout().getTypeAllocSize(SrcTy);
481+ // uint64_t DstSize = CGM.getDataLayout().getTypeAllocSize(STy);
482+ // if (SrcSize < DstSize) {
483+ assert (!cir::MissingFeatures::dataLayoutTypeAllocSize ());
484+ if (srcTy != argRecordTy) {
485+ cgm.errorNYI (loc, " emitCall: source type does not match argument type" );
486+ } else {
487+ // FIXME(cir): this currently only runs when the types are exactly the
488+ // same, but should be when alloc sizes are the same, fix this as soon
489+ // as datalayout gets introduced.
490+ assert (!cir::MissingFeatures::dataLayoutTypeAllocSize ());
491+ }
492+
493+ // assert(NumCIRArgs == STy.getMembers().size());
494+ // In LLVMGen: Still only pass the struct without any gaps but mark it
495+ // as such somehow.
496+ //
497+ // In CIRGen: Emit a load from the "whole" struct,
498+ // which shall be broken later by some lowering step into multiple
499+ // loads.
500+ assert (!cir::MissingFeatures::lowerAggregateLoadStore ());
501+ cirCallArgs[argNo] = builder.createLoad (argLoc, src);
444502 }
445503 }
446504
@@ -479,6 +537,7 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
479537
480538 assert (!cir::MissingFeatures::opCallAttrs ());
481539
540+ mlir::Location callLoc = loc;
482541 cir::CIRCallOpInterface theCall = emitCallLikeOp (
483542 *this , loc, indirectFuncTy, indirectFuncVal, directFuncOp, cirCallArgs);
484543
@@ -492,6 +551,19 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
492551 if (isa<cir::VoidType>(retCIRTy))
493552 return getUndefRValue (retTy);
494553 switch (getEvaluationKind (retTy)) {
554+ case cir::TEK_Aggregate: {
555+ Address destPtr = returnValue.getValue ();
556+
557+ if (!destPtr.isValid ())
558+ destPtr = createMemTemp (retTy, callLoc, getCounterAggTmpAsString ());
559+
560+ mlir::ResultRange results = theCall->getOpResults ();
561+ assert (results.size () <= 1 && " multiple returns from a call" );
562+
563+ SourceLocRAIIObject loc{*this , callLoc};
564+ emitAggregateStore (results[0 ], destPtr);
565+ return RValue::getAggregate (destPtr);
566+ }
495567 case cir::TEK_Scalar: {
496568 mlir::ResultRange results = theCall->getOpResults ();
497569 assert (results.size () == 1 && " unexpected number of returns" );
@@ -508,7 +580,6 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
508580 return RValue::get (results[0 ]);
509581 }
510582 case cir::TEK_Complex:
511- case cir::TEK_Aggregate:
512583 cgm.errorNYI (loc, " unsupported evaluation kind of function call result" );
513584 return getUndefRValue (retTy);
514585 }
@@ -527,10 +598,21 @@ void CIRGenFunction::emitCallArg(CallArgList &args, const clang::Expr *e,
527598
528599 bool hasAggregateEvalKind = hasAggregateEvaluationKind (argType);
529600
530- if (hasAggregateEvalKind) {
531- assert (!cir::MissingFeatures::opCallAggregateArgs ());
532- cgm.errorNYI (e->getSourceRange (),
533- " emitCallArg: aggregate function call argument" );
601+ // In the Microsoft C++ ABI, aggregate arguments are destructed by the callee.
602+ // However, we still have to push an EH-only cleanup in case we unwind before
603+ // we make it to the call.
604+ if (argType->isRecordType () &&
605+ argType->castAs <RecordType>()->getDecl ()->isParamDestroyedInCallee ()) {
606+ assert (!cir::MissingFeatures::msabi ());
607+ cgm.errorNYI (e->getSourceRange (), " emitCallArg: msabi is NYI" );
608+ }
609+
610+ if (hasAggregateEvalKind && isa<ImplicitCastExpr>(e) &&
611+ cast<CastExpr>(e)->getCastKind () == CK_LValueToRValue) {
612+ LValue lv = emitLValue (cast<CastExpr>(e)->getSubExpr ());
613+ assert (lv.isSimple ());
614+ args.addUncopiedAggregate (lv, argType);
615+ return ;
534616 }
535617
536618 args.add (emitAnyExprToTemp (e), argType);
@@ -551,12 +633,13 @@ QualType CIRGenFunction::getVarArgType(const Expr *arg) {
551633// / Similar to emitAnyExpr(), however, the result will always be accessible
552634// / even if no aggregate location is provided.
553635RValue CIRGenFunction::emitAnyExprToTemp (const Expr *e) {
554- assert (! cir::MissingFeatures::opCallAggregateArgs () );
636+ AggValueSlot aggSlot = AggValueSlot::ignored ( );
555637
556638 if (hasAggregateEvaluationKind (e->getType ()))
557- cgm.errorNYI (e->getSourceRange (), " emit aggregate value to temp" );
639+ aggSlot = createAggTemp (e->getType (), getLoc (e->getSourceRange ()),
640+ getCounterAggTmpAsString ());
558641
559- return emitAnyExpr (e);
642+ return emitAnyExpr (e, aggSlot );
560643}
561644
562645void CIRGenFunction::emitCallArgs (
0 commit comments