1313#include " CIRGenFunction.h"
1414#include " mlir/Support/LLVM.h"
1515#include " clang/AST/StmtCXX.h"
16+ #include " clang/AST/StmtVisitor.h"
1617#include " clang/Basic/TargetInfo.h"
1718#include " clang/CIR/Dialect/IR/CIRTypes.h"
1819#include " clang/CIR/MissingFeatures.h"
@@ -33,6 +34,65 @@ struct clang::CIRGen::CGCoroData {
3334CIRGenFunction::CGCoroInfo::CGCoroInfo () {}
3435CIRGenFunction::CGCoroInfo::~CGCoroInfo () {}
3536
37+ namespace {
38+ // FIXME: both GetParamRef and ParamReferenceReplacerRAII are good template
39+ // candidates to be shared among LLVM / CIR codegen.
40+
41+ // Hunts for the parameter reference in the parameter copy/move declaration.
42+ struct GetParamRef : public StmtVisitor <GetParamRef> {
43+ public:
44+ DeclRefExpr *expr = nullptr ;
45+ GetParamRef () {}
46+ void VisitDeclRefExpr (DeclRefExpr *e) {
47+ assert (expr == nullptr && " multilple declref in param move" );
48+ expr = e;
49+ }
50+ void VisitStmt (Stmt *s) {
51+ for (auto *c : s->children ()) {
52+ if (c)
53+ Visit (c);
54+ }
55+ }
56+ };
57+
58+ // This class replaces references to parameters to their copies by changing
59+ // the addresses in CGF.LocalDeclMap and restoring back the original values in
60+ // its destructor.
61+ struct ParamReferenceReplacerRAII {
62+ CIRGenFunction::DeclMapTy savedLocals;
63+ CIRGenFunction::DeclMapTy &localDeclMap;
64+
65+ ParamReferenceReplacerRAII (CIRGenFunction::DeclMapTy &localDeclMap)
66+ : localDeclMap(localDeclMap) {}
67+
68+ void addCopy (DeclStmt const *pm) {
69+ // Figure out what param it refers to.
70+
71+ assert (pm->isSingleDecl ());
72+ VarDecl const *vd = static_cast <VarDecl const *>(pm->getSingleDecl ());
73+ Expr const *initExpr = vd->getInit ();
74+ GetParamRef visitor;
75+ visitor.Visit (const_cast <Expr *>(initExpr));
76+ assert (visitor.expr );
77+ DeclRefExpr *dreOrig = visitor.expr ;
78+ auto *pd = dreOrig->getDecl ();
79+
80+ auto it = localDeclMap.find (pd);
81+ assert (it != localDeclMap.end () && " parameter is not found" );
82+ savedLocals.insert ({pd, it->second });
83+
84+ auto copyIt = localDeclMap.find (vd);
85+ assert (copyIt != localDeclMap.end () && " parameter copy is not found" );
86+ it->second = copyIt->getSecond ();
87+ }
88+
89+ ~ParamReferenceReplacerRAII () {
90+ for (auto &&savedLocal : savedLocals) {
91+ localDeclMap.insert ({savedLocal.first , savedLocal.second });
92+ }
93+ }
94+ };
95+ } // namespace
3696static void createCoroData (CIRGenFunction &cgf,
3797 CIRGenFunction::CGCoroInfo &curCoro,
3898 cir::CallOp coroId) {
@@ -149,7 +209,46 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt &s) {
149209 if (s.getReturnStmtOnAllocFailure ())
150210 cgm.errorNYI (" handle coroutine return alloc failure" );
151211
152- assert (!cir::MissingFeatures::generateDebugInfo ());
153- assert (!cir::MissingFeatures::emitBodyAndFallthrough ());
212+ {
213+ assert (!cir::MissingFeatures::generateDebugInfo ());
214+ ParamReferenceReplacerRAII paramReplacer (localDeclMap);
215+ // Create mapping between parameters and copy-params for coroutine
216+ // function.
217+ llvm::ArrayRef<const Stmt *> paramMoves = s.getParamMoves ();
218+ assert ((paramMoves.size () == 0 || (paramMoves.size () == fnArgs.size ())) &&
219+ " ParamMoves and FnArgs should be the same size for coroutine "
220+ " function" );
221+ // For zipping the arg map into debug info.
222+ assert (!cir::MissingFeatures::generateDebugInfo ());
223+
224+ // Create parameter copies. We do it before creating a promise, since an
225+ // evolution of coroutine TS may allow promise constructor to observe
226+ // parameter copies.
227+ for (auto *pm : paramMoves) {
228+ if (emitStmt (pm, /* useCurrentScope=*/ true ).failed ())
229+ return mlir::failure ();
230+ paramReplacer.addCopy (cast<DeclStmt>(pm));
231+ }
232+
233+ if (emitStmt (s.getPromiseDeclStmt (), /* useCurrentScope=*/ true ).failed ())
234+ return mlir::failure ();
235+ // returnValue should be valid as long as the coroutine's return type
236+ // is not void. The assertion could help us to reduce the check later.
237+ assert (returnValue.isValid () == (bool )s.getReturnStmt ());
238+ // Now we have the promise, initialize the GRO.
239+ // We need to emit `get_return_object` first. According to:
240+ // [dcl.fct.def.coroutine]p7
241+ // The call to get_return_object is sequenced before the call to
242+ // initial_suspend and is invoked at most once.
243+ //
244+ // So we couldn't emit return value when we emit return statment,
245+ // otherwise the call to get_return_object wouldn't be in front
246+ // of initial_suspend.
247+ if (returnValue.isValid ())
248+ emitAnyExprToMem (s.getReturnValue (), returnValue,
249+ s.getReturnValue ()->getType ().getQualifiers (),
250+ /* isInit*/ true );
251+ assert (!cir::MissingFeatures::emitBodyAndFallthrough ());
252+ }
154253 return mlir::success ();
155254}
0 commit comments