@@ -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 ()
@@ -399,8 +416,48 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
399
416
assert (!cir::MissingFeatures::opCallBitcastArg ());
400
417
cirCallArgs[argNo] = v;
401
418
} else {
402
- assert (!cir::MissingFeatures::opCallAggregateArgs ());
403
- cgm.errorNYI (" emitCall: aggregate function call argument" );
419
+ Address src = Address::invalid ();
420
+ if (!arg.isAggregate ())
421
+ cgm.errorNYI (loc, " emitCall: non-aggregate call argument" );
422
+ else
423
+ src = arg.hasLValue () ? arg.getKnownLValue ().getAddress ()
424
+ : arg.getKnownRValue ().getAggregateAddress ();
425
+
426
+ // Fast-isel and the optimizer generally like scalar values better than
427
+ // FCAs, so we flatten them if this is safe to do for this argument.
428
+ auto argRecordTy = cast<cir::RecordType>(argType);
429
+ mlir::Type srcTy = src.getElementType ();
430
+ // FIXME(cir): get proper location for each argument.
431
+ mlir::Location argLoc = loc;
432
+
433
+ // If the source type is smaller than the destination type of the
434
+ // coerce-to logic, copy the source value into a temp alloca the size
435
+ // of the destination type to allow loading all of it. The bits past
436
+ // the source value are left undef.
437
+ // FIXME(cir): add data layout info and compare sizes instead of
438
+ // matching the types.
439
+ //
440
+ // uint64_t SrcSize = CGM.getDataLayout().getTypeAllocSize(SrcTy);
441
+ // uint64_t DstSize = CGM.getDataLayout().getTypeAllocSize(STy);
442
+ // if (SrcSize < DstSize) {
443
+ if (srcTy != argRecordTy) {
444
+ cgm.errorNYI (loc, " emitCall: source type does not match argument type" );
445
+ } else {
446
+ // FIXME(cir): this currently only runs when the types are different,
447
+ // but should be when alloc sizes are different, fix this as soon as
448
+ // datalayout gets introduced.
449
+ src = builder.createElementBitCast (argLoc, src, argRecordTy);
450
+ }
451
+
452
+ // assert(NumCIRArgs == STy.getMembers().size());
453
+ // In LLVMGen: Still only pass the struct without any gaps but mark it
454
+ // as such somehow.
455
+ //
456
+ // In CIRGen: Emit a load from the "whole" struct,
457
+ // which shall be broken later by some lowering step into multiple
458
+ // loads.
459
+ assert (!cir::MissingFeatures::lowerAggregateLoadStore ());
460
+ cirCallArgs[argNo] = builder.createLoad (argLoc, src);
404
461
}
405
462
}
406
463
@@ -439,6 +496,7 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
439
496
440
497
assert (!cir::MissingFeatures::opCallAttrs ());
441
498
499
+ mlir::Location callLoc = loc;
442
500
cir::CIRCallOpInterface theCall = emitCallLikeOp (
443
501
*this , loc, indirectFuncTy, indirectFuncVal, directFuncOp, cirCallArgs);
444
502
@@ -452,6 +510,19 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
452
510
if (isa<cir::VoidType>(retCIRTy))
453
511
return getUndefRValue (retTy);
454
512
switch (getEvaluationKind (retTy)) {
513
+ case cir::TEK_Aggregate: {
514
+ Address destPtr = returnValue.getValue ();
515
+
516
+ if (!destPtr.isValid ())
517
+ destPtr = createMemTemp (retTy, callLoc, getCounterAggTmpAsString ());
518
+
519
+ mlir::ResultRange results = theCall->getOpResults ();
520
+ assert (results.size () <= 1 && " multiple returns from a call" );
521
+
522
+ SourceLocRAIIObject loc{*this , callLoc};
523
+ emitAggregateStore (results[0 ], destPtr);
524
+ return RValue::getAggregate (destPtr);
525
+ }
455
526
case cir::TEK_Scalar: {
456
527
mlir::ResultRange results = theCall->getOpResults ();
457
528
assert (results.size () == 1 && " unexpected number of returns" );
@@ -468,7 +539,6 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
468
539
return RValue::get (results[0 ]);
469
540
}
470
541
case cir::TEK_Complex:
471
- case cir::TEK_Aggregate:
472
542
cgm.errorNYI (loc, " unsupported evaluation kind of function call result" );
473
543
return getUndefRValue (retTy);
474
544
}
@@ -487,10 +557,21 @@ void CIRGenFunction::emitCallArg(CallArgList &args, const clang::Expr *e,
487
557
488
558
bool hasAggregateEvalKind = hasAggregateEvaluationKind (argType);
489
559
490
- if (hasAggregateEvalKind) {
491
- assert (!cir::MissingFeatures::opCallAggregateArgs ());
492
- cgm.errorNYI (e->getSourceRange (),
493
- " emitCallArg: aggregate function call argument" );
560
+ // In the Microsoft C++ ABI, aggregate arguments are destructed by the callee.
561
+ // However, we still have to push an EH-only cleanup in case we unwind before
562
+ // we make it to the call.
563
+ if (argType->isRecordType () &&
564
+ argType->castAs <RecordType>()->getDecl ()->isParamDestroyedInCallee ()) {
565
+ assert (!cir::MissingFeatures::msabi ());
566
+ cgm.errorNYI (e->getSourceRange (), " emitCallArg: msabi is NYI" );
567
+ }
568
+
569
+ if (hasAggregateEvalKind && isa<ImplicitCastExpr>(e) &&
570
+ cast<CastExpr>(e)->getCastKind () == CK_LValueToRValue) {
571
+ LValue lv = emitLValue (cast<CastExpr>(e)->getSubExpr ());
572
+ assert (lv.isSimple ());
573
+ args.addUncopiedAggregate (lv, argType);
574
+ return ;
494
575
}
495
576
496
577
args.add (emitAnyExprToTemp (e), argType);
@@ -511,12 +592,13 @@ QualType CIRGenFunction::getVarArgType(const Expr *arg) {
511
592
// / Similar to emitAnyExpr(), however, the result will always be accessible
512
593
// / even if no aggregate location is provided.
513
594
RValue CIRGenFunction::emitAnyExprToTemp (const Expr *e) {
514
- assert (! cir::MissingFeatures::opCallAggregateArgs () );
595
+ AggValueSlot aggSlot = AggValueSlot::ignored ( );
515
596
516
597
if (hasAggregateEvaluationKind (e->getType ()))
517
- cgm.errorNYI (e->getSourceRange (), " emit aggregate value to temp" );
598
+ aggSlot = createAggTemp (e->getType (), getLoc (e->getSourceRange ()),
599
+ getCounterAggTmpAsString ());
518
600
519
- return emitAnyExpr (e);
601
+ return emitAnyExpr (e, aggSlot );
520
602
}
521
603
522
604
void CIRGenFunction::emitCallArgs (
0 commit comments