@@ -60,6 +60,23 @@ CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const {
60
60
return *this ;
61
61
}
62
62
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
+
63
80
// / Returns the canonical formal type of the given C++ method.
64
81
static CanQual<FunctionProtoType> getFormalType (const CXXMethodDecl *md) {
65
82
return md->getType ()
@@ -439,8 +456,49 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
439
456
assert (!cir::MissingFeatures::opCallBitcastArg ());
440
457
cirCallArgs[argNo] = v;
441
458
} 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);
444
502
}
445
503
}
446
504
@@ -479,6 +537,7 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
479
537
480
538
assert (!cir::MissingFeatures::opCallAttrs ());
481
539
540
+ mlir::Location callLoc = loc;
482
541
cir::CIRCallOpInterface theCall = emitCallLikeOp (
483
542
*this , loc, indirectFuncTy, indirectFuncVal, directFuncOp, cirCallArgs);
484
543
@@ -492,6 +551,19 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
492
551
if (isa<cir::VoidType>(retCIRTy))
493
552
return getUndefRValue (retTy);
494
553
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
+ }
495
567
case cir::TEK_Scalar: {
496
568
mlir::ResultRange results = theCall->getOpResults ();
497
569
assert (results.size () == 1 && " unexpected number of returns" );
@@ -508,7 +580,6 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
508
580
return RValue::get (results[0 ]);
509
581
}
510
582
case cir::TEK_Complex:
511
- case cir::TEK_Aggregate:
512
583
cgm.errorNYI (loc, " unsupported evaluation kind of function call result" );
513
584
return getUndefRValue (retTy);
514
585
}
@@ -527,10 +598,21 @@ void CIRGenFunction::emitCallArg(CallArgList &args, const clang::Expr *e,
527
598
528
599
bool hasAggregateEvalKind = hasAggregateEvaluationKind (argType);
529
600
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 ;
534
616
}
535
617
536
618
args.add (emitAnyExprToTemp (e), argType);
@@ -551,12 +633,13 @@ QualType CIRGenFunction::getVarArgType(const Expr *arg) {
551
633
// / Similar to emitAnyExpr(), however, the result will always be accessible
552
634
// / even if no aggregate location is provided.
553
635
RValue CIRGenFunction::emitAnyExprToTemp (const Expr *e) {
554
- assert (! cir::MissingFeatures::opCallAggregateArgs () );
636
+ AggValueSlot aggSlot = AggValueSlot::ignored ( );
555
637
556
638
if (hasAggregateEvaluationKind (e->getType ()))
557
- cgm.errorNYI (e->getSourceRange (), " emit aggregate value to temp" );
639
+ aggSlot = createAggTemp (e->getType (), getLoc (e->getSourceRange ()),
640
+ getCounterAggTmpAsString ());
558
641
559
- return emitAnyExpr (e);
642
+ return emitAnyExpr (e, aggSlot );
560
643
}
561
644
562
645
void CIRGenFunction::emitCallArgs (
0 commit comments