clang 22.0.0git
CIRGenCoroutine.cpp
Go to the documentation of this file.
1//===----- CGCoroutine.cpp - Emit CIR Code for C++ coroutines -------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This contains code dealing with C++ code generation of coroutines.
10//
11//===----------------------------------------------------------------------===//
12
13#include "CIRGenFunction.h"
14#include "mlir/Support/LLVM.h"
15#include "clang/AST/StmtCXX.h"
19
20using namespace clang;
21using namespace clang::CIRGen;
22
24 // Stores the __builtin_coro_id emitted in the function so that we can supply
25 // it as the first argument to other builtins.
26 cir::CallOp coroId = nullptr;
27
28 // Stores the result of __builtin_coro_begin call.
29 mlir::Value coroBegin = nullptr;
30};
31
32// Defining these here allows to keep CGCoroData private to this file.
35
38 cir::CallOp coroId) {
39 assert(!curCoro.data && "EmitCoroutineBodyStatement called twice?");
40
41 curCoro.data = std::make_unique<CGCoroData>();
42 curCoro.data->coroId = coroId;
43}
44
45cir::CallOp CIRGenFunction::emitCoroIDBuiltinCall(mlir::Location loc,
46 mlir::Value nullPtr) {
47 cir::IntType int32Ty = builder.getUInt32Ty();
48
49 const TargetInfo &ti = cgm.getASTContext().getTargetInfo();
50 unsigned newAlign = ti.getNewAlign() / ti.getCharWidth();
51
52 mlir::Operation *builtin = cgm.getGlobalValue(cgm.builtinCoroId);
53
54 cir::FuncOp fnOp;
55 if (!builtin) {
56 fnOp = cgm.createCIRBuiltinFunction(
57 loc, cgm.builtinCoroId,
58 cir::FuncType::get({int32Ty, voidPtrTy, voidPtrTy, voidPtrTy}, int32Ty),
59 /*FD=*/nullptr);
60 assert(fnOp && "should always succeed");
61 } else {
62 fnOp = cast<cir::FuncOp>(builtin);
63 }
64
65 return builder.createCallOp(loc, fnOp,
66 mlir::ValueRange{builder.getUInt32(newAlign, loc),
67 nullPtr, nullPtr, nullPtr});
68}
69
70cir::CallOp CIRGenFunction::emitCoroAllocBuiltinCall(mlir::Location loc) {
71 cir::BoolType boolTy = builder.getBoolTy();
72
73 mlir::Operation *builtin = cgm.getGlobalValue(cgm.builtinCoroAlloc);
74
75 cir::FuncOp fnOp;
76 if (!builtin) {
77 fnOp = cgm.createCIRBuiltinFunction(loc, cgm.builtinCoroAlloc,
78 cir::FuncType::get({uInt32Ty}, boolTy),
79 /*fd=*/nullptr);
80 assert(fnOp && "should always succeed");
81 } else {
82 fnOp = cast<cir::FuncOp>(builtin);
83 }
84
85 return builder.createCallOp(
86 loc, fnOp, mlir::ValueRange{curCoro.data->coroId.getResult()});
87}
88
89cir::CallOp
91 mlir::Value coroframeAddr) {
92 mlir::Operation *builtin = cgm.getGlobalValue(cgm.builtinCoroBegin);
93
94 cir::FuncOp fnOp;
95 if (!builtin) {
96 fnOp = cgm.createCIRBuiltinFunction(
97 loc, cgm.builtinCoroBegin,
98 cir::FuncType::get({uInt32Ty, voidPtrTy}, voidPtrTy),
99 /*fd=*/nullptr);
100 assert(fnOp && "should always succeed");
101 } else {
102 fnOp = cast<cir::FuncOp>(builtin);
103 }
104
105 return builder.createCallOp(
106 loc, fnOp,
107 mlir::ValueRange{curCoro.data->coroId.getResult(), coroframeAddr});
108}
109
110mlir::LogicalResult
112 mlir::Location openCurlyLoc = getLoc(s.getBeginLoc());
113 cir::ConstantOp nullPtrCst = builder.getNullPtr(voidPtrTy, openCurlyLoc);
114
115 auto fn = mlir::cast<cir::FuncOp>(curFn);
116 fn.setCoroutine(true);
117 cir::CallOp coroId = emitCoroIDBuiltinCall(openCurlyLoc, nullPtrCst);
118 createCoroData(*this, curCoro, coroId);
119
120 // Backend is allowed to elide memory allocations, to help it, emit
121 // auto mem = coro.alloc() ? 0 : ... allocation code ...;
122 cir::CallOp coroAlloc = emitCoroAllocBuiltinCall(openCurlyLoc);
123
124 // Initialize address of coroutine frame to null
125 CanQualType astVoidPtrTy = cgm.getASTContext().VoidPtrTy;
126 mlir::Type allocaTy = convertTypeForMem(astVoidPtrTy);
127 Address coroFrame =
128 createTempAlloca(allocaTy, getContext().getTypeAlignInChars(astVoidPtrTy),
129 openCurlyLoc, "__coro_frame_addr",
130 /*ArraySize=*/nullptr);
131
132 mlir::Value storeAddr = coroFrame.getPointer();
133 builder.CIRBaseBuilderTy::createStore(openCurlyLoc, nullPtrCst, storeAddr);
134 cir::IfOp::create(
135 builder, openCurlyLoc, coroAlloc.getResult(),
136 /*withElseRegion=*/false,
137 /*thenBuilder=*/[&](mlir::OpBuilder &b, mlir::Location loc) {
138 builder.CIRBaseBuilderTy::createStore(
139 loc, emitScalarExpr(s.getAllocate()), storeAddr);
140 cir::YieldOp::create(builder, loc);
141 });
142 curCoro.data->coroBegin =
144 openCurlyLoc,
145 cir::LoadOp::create(builder, openCurlyLoc, allocaTy, storeAddr))
146 .getResult();
147
148 // Handle allocation failure if 'ReturnStmtOnAllocFailure' was provided.
149 if (s.getReturnStmtOnAllocFailure())
150 cgm.errorNYI("handle coroutine return alloc failure");
151
154 return mlir::success();
155}
static void createCoroData(CIRGenFunction &cgf, CIRGenFunction::CGCoroInfo &curCoro, cir::CallOp coroId)
__device__ __2f16 b
__device__ __2f16 float __ockl_bool s
mlir::Value getPointer() const
Definition Address.h:82
cir::CallOp emitCoroIDBuiltinCall(mlir::Location loc, mlir::Value nullPtr)
cir::AllocaOp createTempAlloca(mlir::Type ty, mlir::Location loc, const Twine &name="tmp", mlir::Value arraySize=nullptr, bool insertIntoFnEntryBlock=false)
This creates an alloca and inserts it into the entry block if ArraySize is nullptr,...
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
mlir::Operation * curFn
The current function or global initializer that is generated code for.
mlir::Type convertTypeForMem(QualType t)
cir::CallOp emitCoroAllocBuiltinCall(mlir::Location loc)
clang::ASTContext & getContext() const
mlir::LogicalResult emitCoroutineBody(const CoroutineBodyStmt &s)
cir::CallOp emitCoroBeginBuiltinCall(mlir::Location loc, mlir::Value coroframeAddr)
Represents the body of a coroutine.
Definition StmtCXX.h:320
Exposes information about the current target.
Definition TargetInfo.h:226
unsigned getNewAlign() const
Return the largest alignment for which a suitably-sized allocation with 'operator new(size_t)' is gua...
Definition TargetInfo.h:761
unsigned getCharWidth() const
Definition TargetInfo.h:517
Defines the clang::TargetInfo interface.
The JSON file list parser is used to communicate input to InstallAPI.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
U cast(CodeGen::Address addr)
Definition Address.h:327
static bool emitBodyAndFallthrough()
static bool generateDebugInfo()
std::unique_ptr< CGCoroData > data
cir::PointerType voidPtrTy
void* in address space 0