Path: blob/main/contrib/llvm-project/clang/lib/CIR/CodeGen/CIRGenFunction.h
213799 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Internal per-function state used for AST-to-ClangIR code gen9//10//===----------------------------------------------------------------------===//1112#ifndef CLANG_LIB_CIR_CODEGEN_CIRGENFUNCTION_H13#define CLANG_LIB_CIR_CODEGEN_CIRGENFUNCTION_H1415#include "CIRGenBuilder.h"16#include "CIRGenCall.h"17#include "CIRGenModule.h"18#include "CIRGenTypeCache.h"19#include "CIRGenValue.h"2021#include "Address.h"2223#include "clang/AST/ASTContext.h"24#include "clang/AST/CharUnits.h"25#include "clang/AST/Decl.h"26#include "clang/AST/Stmt.h"27#include "clang/AST/Type.h"28#include "clang/CIR/Dialect/IR/CIRDialect.h"29#include "clang/CIR/MissingFeatures.h"30#include "clang/CIR/TypeEvaluationKind.h"3132namespace {33class ScalarExprEmitter;34} // namespace3536namespace mlir {37namespace acc {38class LoopOp;39} // namespace acc40} // namespace mlir4142namespace clang::CIRGen {4344class CIRGenFunction : public CIRGenTypeCache {45public:46CIRGenModule &cgm;4748private:49friend class ::ScalarExprEmitter;50/// The builder is a helper class to create IR inside a function. The51/// builder is stateful, in particular it keeps an "insertion point": this52/// is where the next operations will be introduced.53CIRGenBuilderTy &builder;5455public:56/// The GlobalDecl for the current function being compiled or the global57/// variable currently being initialized.58clang::GlobalDecl curGD;5960/// The compiler-generated variable that holds the return value.61std::optional<mlir::Value> fnRetAlloca;6263/// CXXThisDecl - When generating code for a C++ member function,64/// this will hold the implicit 'this' declaration.65ImplicitParamDecl *cxxabiThisDecl = nullptr;66mlir::Value cxxabiThisValue = nullptr;67mlir::Value cxxThisValue = nullptr;68clang::CharUnits cxxThisAlignment;6970/// The value of 'this' to sue when evaluating CXXDefaultInitExprs within this71/// expression.72Address cxxDefaultInitExprThis = Address::invalid();7374// Holds the Decl for the current outermost non-closure context75const clang::Decl *curFuncDecl = nullptr;7677/// The function for which code is currently being generated.78cir::FuncOp curFn;7980using DeclMapTy = llvm::DenseMap<const clang::Decl *, Address>;81/// This keeps track of the CIR allocas or globals for local C82/// declarations.83DeclMapTy localDeclMap;8485/// The type of the condition for the emitting switch statement.86llvm::SmallVector<mlir::Type, 2> condTypeStack;8788clang::ASTContext &getContext() const { return cgm.getASTContext(); }8990CIRGenBuilderTy &getBuilder() { return builder; }9192CIRGenModule &getCIRGenModule() { return cgm; }93const CIRGenModule &getCIRGenModule() const { return cgm; }9495mlir::Block *getCurFunctionEntryBlock() { return &curFn.getRegion().front(); }9697/// Sanitizers enabled for this function.98clang::SanitizerSet sanOpts;99100/// Whether or not a Microsoft-style asm block has been processed within101/// this fuction. These can potentially set the return value.102bool sawAsmBlock = false;103104mlir::Type convertTypeForMem(QualType t);105106mlir::Type convertType(clang::QualType t);107mlir::Type convertType(const TypeDecl *t) {108return convertType(getContext().getTypeDeclType(t));109}110111/// Return the cir::TypeEvaluationKind of QualType \c type.112static cir::TypeEvaluationKind getEvaluationKind(clang::QualType type);113114static bool hasScalarEvaluationKind(clang::QualType type) {115return getEvaluationKind(type) == cir::TEK_Scalar;116}117118static bool hasAggregateEvaluationKind(clang::QualType type) {119return getEvaluationKind(type) == cir::TEK_Aggregate;120}121122CIRGenFunction(CIRGenModule &cgm, CIRGenBuilderTy &builder,123bool suppressNewContext = false);124~CIRGenFunction();125126CIRGenTypes &getTypes() const { return cgm.getTypes(); }127128const TargetInfo &getTarget() const { return cgm.getTarget(); }129mlir::MLIRContext &getMLIRContext() { return cgm.getMLIRContext(); }130131// ---------------------132// Opaque value handling133// ---------------------134135/// Keeps track of the current set of opaque value expressions.136llvm::DenseMap<const OpaqueValueExpr *, LValue> opaqueLValues;137llvm::DenseMap<const OpaqueValueExpr *, RValue> opaqueRValues;138139public:140/// A non-RAII class containing all the information about a bound141/// opaque value. OpaqueValueMapping, below, is a RAII wrapper for142/// this which makes individual mappings very simple; using this143/// class directly is useful when you have a variable number of144/// opaque values or don't want the RAII functionality for some145/// reason.146class OpaqueValueMappingData {147const OpaqueValueExpr *opaqueValue;148bool boundLValue;149150OpaqueValueMappingData(const OpaqueValueExpr *ov, bool boundLValue)151: opaqueValue(ov), boundLValue(boundLValue) {}152153public:154OpaqueValueMappingData() : opaqueValue(nullptr) {}155156static bool shouldBindAsLValue(const Expr *expr) {157// gl-values should be bound as l-values for obvious reasons.158// Records should be bound as l-values because IR generation159// always keeps them in memory. Expressions of function type160// act exactly like l-values but are formally required to be161// r-values in C.162return expr->isGLValue() || expr->getType()->isFunctionType() ||163hasAggregateEvaluationKind(expr->getType());164}165166static OpaqueValueMappingData167bind(CIRGenFunction &cgf, const OpaqueValueExpr *ov, const Expr *e) {168if (shouldBindAsLValue(ov))169return bind(cgf, ov, cgf.emitLValue(e));170return bind(cgf, ov, cgf.emitAnyExpr(e));171}172173static OpaqueValueMappingData174bind(CIRGenFunction &cgf, const OpaqueValueExpr *ov, const LValue &lv) {175assert(shouldBindAsLValue(ov));176cgf.opaqueLValues.insert(std::make_pair(ov, lv));177return OpaqueValueMappingData(ov, true);178}179180static OpaqueValueMappingData181bind(CIRGenFunction &cgf, const OpaqueValueExpr *ov, const RValue &rv) {182assert(!shouldBindAsLValue(ov));183cgf.opaqueRValues.insert(std::make_pair(ov, rv));184185OpaqueValueMappingData data(ov, false);186187// Work around an extremely aggressive peephole optimization in188// EmitScalarConversion which assumes that all other uses of a189// value are extant.190assert(!cir::MissingFeatures::peepholeProtection() && "NYI");191return data;192}193194bool isValid() const { return opaqueValue != nullptr; }195void clear() { opaqueValue = nullptr; }196197void unbind(CIRGenFunction &cgf) {198assert(opaqueValue && "no data to unbind!");199200if (boundLValue) {201cgf.opaqueLValues.erase(opaqueValue);202} else {203cgf.opaqueRValues.erase(opaqueValue);204assert(!cir::MissingFeatures::peepholeProtection() && "NYI");205}206}207};208209/// An RAII object to set (and then clear) a mapping for an OpaqueValueExpr.210class OpaqueValueMapping {211CIRGenFunction &cgf;212OpaqueValueMappingData data;213214public:215static bool shouldBindAsLValue(const Expr *expr) {216return OpaqueValueMappingData::shouldBindAsLValue(expr);217}218219/// Build the opaque value mapping for the given conditional220/// operator if it's the GNU ?: extension. This is a common221/// enough pattern that the convenience operator is really222/// helpful.223///224OpaqueValueMapping(CIRGenFunction &cgf,225const AbstractConditionalOperator *op)226: cgf(cgf) {227if (mlir::isa<ConditionalOperator>(op))228// Leave Data empty.229return;230231const BinaryConditionalOperator *e =232mlir::cast<BinaryConditionalOperator>(op);233data = OpaqueValueMappingData::bind(cgf, e->getOpaqueValue(),234e->getCommon());235}236237/// Build the opaque value mapping for an OpaqueValueExpr whose source238/// expression is set to the expression the OVE represents.239OpaqueValueMapping(CIRGenFunction &cgf, const OpaqueValueExpr *ov)240: cgf(cgf) {241if (ov) {242assert(ov->getSourceExpr() && "wrong form of OpaqueValueMapping used "243"for OVE with no source expression");244data = OpaqueValueMappingData::bind(cgf, ov, ov->getSourceExpr());245}246}247248OpaqueValueMapping(CIRGenFunction &cgf, const OpaqueValueExpr *opaqueValue,249LValue lvalue)250: cgf(cgf),251data(OpaqueValueMappingData::bind(cgf, opaqueValue, lvalue)) {}252253OpaqueValueMapping(CIRGenFunction &cgf, const OpaqueValueExpr *opaqueValue,254RValue rvalue)255: cgf(cgf),256data(OpaqueValueMappingData::bind(cgf, opaqueValue, rvalue)) {}257258void pop() {259data.unbind(cgf);260data.clear();261}262263~OpaqueValueMapping() {264if (data.isValid())265data.unbind(cgf);266}267};268269private:270/// Declare a variable in the current scope, return success if the variable271/// wasn't declared yet.272void declare(mlir::Value addrVal, const clang::Decl *var, clang::QualType ty,273mlir::Location loc, clang::CharUnits alignment,274bool isParam = false);275276public:277mlir::Value createDummyValue(mlir::Location loc, clang::QualType qt);278279void emitNullInitialization(mlir::Location loc, Address destPtr, QualType ty);280281private:282// Track current variable initialization (if there's one)283const clang::VarDecl *currVarDecl = nullptr;284class VarDeclContext {285CIRGenFunction &p;286const clang::VarDecl *oldVal = nullptr;287288public:289VarDeclContext(CIRGenFunction &p, const VarDecl *value) : p(p) {290if (p.currVarDecl)291oldVal = p.currVarDecl;292p.currVarDecl = value;293}294295/// Can be used to restore the state early, before the dtor296/// is run.297void restore() { p.currVarDecl = oldVal; }298~VarDeclContext() { restore(); }299};300301public:302/// Use to track source locations across nested visitor traversals.303/// Always use a `SourceLocRAIIObject` to change currSrcLoc.304std::optional<mlir::Location> currSrcLoc;305class SourceLocRAIIObject {306CIRGenFunction &cgf;307std::optional<mlir::Location> oldLoc;308309public:310SourceLocRAIIObject(CIRGenFunction &cgf, mlir::Location value) : cgf(cgf) {311if (cgf.currSrcLoc)312oldLoc = cgf.currSrcLoc;313cgf.currSrcLoc = value;314}315316/// Can be used to restore the state early, before the dtor317/// is run.318void restore() { cgf.currSrcLoc = oldLoc; }319~SourceLocRAIIObject() { restore(); }320};321322/// Hold counters for incrementally naming temporaries323unsigned counterAggTmp = 0;324std::string getCounterAggTmpAsString();325326/// Helpers to convert Clang's SourceLocation to a MLIR Location.327mlir::Location getLoc(clang::SourceLocation srcLoc);328mlir::Location getLoc(clang::SourceRange srcLoc);329mlir::Location getLoc(mlir::Location lhs, mlir::Location rhs);330331const clang::LangOptions &getLangOpts() const { return cgm.getLangOpts(); }332333// Wrapper for function prototype sources. Wraps either a FunctionProtoType or334// an ObjCMethodDecl.335struct PrototypeWrapper {336llvm::PointerUnion<const clang::FunctionProtoType *,337const clang::ObjCMethodDecl *>338p;339340PrototypeWrapper(const clang::FunctionProtoType *ft) : p(ft) {}341PrototypeWrapper(const clang::ObjCMethodDecl *md) : p(md) {}342};343344bool isLValueSuitableForInlineAtomic(LValue lv);345346/// An abstract representation of regular/ObjC call/message targets.347class AbstractCallee {348/// The function declaration of the callee.349[[maybe_unused]] const clang::Decl *calleeDecl;350351public:352AbstractCallee() : calleeDecl(nullptr) {}353AbstractCallee(const clang::FunctionDecl *fd) : calleeDecl(fd) {}354355bool hasFunctionDecl() const {356return llvm::isa_and_nonnull<clang::FunctionDecl>(calleeDecl);357}358359unsigned getNumParams() const {360if (const auto *fd = llvm::dyn_cast<clang::FunctionDecl>(calleeDecl))361return fd->getNumParams();362return llvm::cast<clang::ObjCMethodDecl>(calleeDecl)->param_size();363}364365const clang::ParmVarDecl *getParamDecl(unsigned I) const {366if (const auto *fd = llvm::dyn_cast<clang::FunctionDecl>(calleeDecl))367return fd->getParamDecl(I);368return *(llvm::cast<clang::ObjCMethodDecl>(calleeDecl)->param_begin() +369I);370}371};372373void finishFunction(SourceLocation endLoc);374375/// Determine whether the given initializer is trivial in the sense376/// that it requires no code to be generated.377bool isTrivialInitializer(const Expr *init);378379/// If the specified expression does not fold to a constant, or if it does but380/// contains a label, return false. If it constant folds return true and set381/// the boolean result in Result.382bool constantFoldsToBool(const clang::Expr *cond, bool &resultBool,383bool allowLabels = false);384bool constantFoldsToSimpleInteger(const clang::Expr *cond,385llvm::APSInt &resultInt,386bool allowLabels = false);387388/// Return true if the statement contains a label in it. If389/// this statement is not executed normally, it not containing a label means390/// that we can just remove the code.391bool containsLabel(const clang::Stmt *s, bool ignoreCaseStmts = false);392393class ConstantEmission {394// Cannot use mlir::TypedAttr directly here because of bit availability.395llvm::PointerIntPair<mlir::Attribute, 1, bool> valueAndIsReference;396ConstantEmission(mlir::TypedAttr c, bool isReference)397: valueAndIsReference(c, isReference) {}398399public:400ConstantEmission() {}401static ConstantEmission forReference(mlir::TypedAttr c) {402return ConstantEmission(c, true);403}404static ConstantEmission forValue(mlir::TypedAttr c) {405return ConstantEmission(c, false);406}407408explicit operator bool() const {409return valueAndIsReference.getOpaqueValue() != nullptr;410}411412bool isReference() const { return valueAndIsReference.getInt(); }413LValue getReferenceLValue(CIRGenFunction &cgf, Expr *refExpr) const {414assert(isReference());415cgf.cgm.errorNYI(refExpr->getSourceRange(),416"ConstantEmission::getReferenceLValue");417return {};418}419420mlir::TypedAttr getValue() const {421assert(!isReference());422return mlir::cast<mlir::TypedAttr>(valueAndIsReference.getPointer());423}424};425426ConstantEmission tryEmitAsConstant(DeclRefExpr *refExpr);427428struct AutoVarEmission {429const clang::VarDecl *Variable;430/// The address of the alloca for languages with explicit address space431/// (e.g. OpenCL) or alloca casted to generic pointer for address space432/// agnostic languages (e.g. C++). Invalid if the variable was emitted433/// as a global constant.434Address Addr;435436/// True if the variable is of aggregate type and has a constant437/// initializer.438bool IsConstantAggregate = false;439440/// True if the variable is a __block variable that is captured by an441/// escaping block.442bool IsEscapingByRef = false;443444mlir::Value NRVOFlag{};445446struct Invalid {};447AutoVarEmission(Invalid) : Variable(nullptr), Addr(Address::invalid()) {}448449AutoVarEmission(const clang::VarDecl &variable)450: Variable(&variable), Addr(Address::invalid()) {}451452static AutoVarEmission invalid() { return AutoVarEmission(Invalid()); }453454bool wasEmittedAsGlobal() const { return !Addr.isValid(); }455456/// Returns the raw, allocated address, which is not necessarily457/// the address of the object itself. It is casted to default458/// address space for address space agnostic languages.459Address getAllocatedAddress() const { return Addr; }460461/// Returns the address of the object within this declaration.462/// Note that this does not chase the forwarding pointer for463/// __block decls.464Address getObjectAddress(CIRGenFunction &cgf) const {465if (!IsEscapingByRef)466return Addr;467468assert(!cir::MissingFeatures::opAllocaEscapeByReference());469return Address::invalid();470}471};472473/// Perform the usual unary conversions on the specified expression and474/// compare the result against zero, returning an Int1Ty value.475mlir::Value evaluateExprAsBool(const clang::Expr *e);476477cir::GlobalOp addInitializerToStaticVarDecl(const VarDecl &d,478cir::GlobalOp gv,479cir::GetGlobalOp gvAddr);480481/// Set the address of a local variable.482void setAddrOfLocalVar(const clang::VarDecl *vd, Address addr) {483assert(!localDeclMap.count(vd) && "Decl already exists in LocalDeclMap!");484localDeclMap.insert({vd, addr});485// TODO: Add symbol table support486}487488bool shouldNullCheckClassCastValue(const CastExpr *ce);489490RValue convertTempToRValue(Address addr, clang::QualType type,491clang::SourceLocation loc);492493static bool494isConstructorDelegationValid(const clang::CXXConstructorDecl *ctor);495496/// A scope within which we are constructing the fields of an object which497/// might use a CXXDefaultInitExpr. This stashes away a 'this' value to use if498/// we need to evaluate the CXXDefaultInitExpr within the evaluation.499class FieldConstructionScope {500public:501FieldConstructionScope(CIRGenFunction &cgf, Address thisAddr)502: cgf(cgf), oldCXXDefaultInitExprThis(cgf.cxxDefaultInitExprThis) {503cgf.cxxDefaultInitExprThis = thisAddr;504}505~FieldConstructionScope() {506cgf.cxxDefaultInitExprThis = oldCXXDefaultInitExprThis;507}508509private:510CIRGenFunction &cgf;511Address oldCXXDefaultInitExprThis;512};513514LValue makeNaturalAlignPointeeAddrLValue(mlir::Value v, clang::QualType t);515LValue makeNaturalAlignAddrLValue(mlir::Value val, QualType ty);516517/// Construct an address with the natural alignment of T. If a pointer to T518/// is expected to be signed, the pointer passed to this function must have519/// been signed, and the returned Address will have the pointer authentication520/// information needed to authenticate the signed pointer.521Address makeNaturalAddressForPointer(mlir::Value ptr, QualType t,522CharUnits alignment,523bool forPointeeType = false,524LValueBaseInfo *baseInfo = nullptr) {525if (alignment.isZero())526alignment = cgm.getNaturalTypeAlignment(t, baseInfo);527return Address(ptr, convertTypeForMem(t), alignment);528}529530Address getAddressOfBaseClass(531Address value, const CXXRecordDecl *derived,532llvm::iterator_range<CastExpr::path_const_iterator> path,533bool nullCheckValue, SourceLocation loc);534535LValue makeAddrLValue(Address addr, QualType ty,536AlignmentSource source = AlignmentSource::Type) {537return makeAddrLValue(addr, ty, LValueBaseInfo(source));538}539540LValue makeAddrLValue(Address addr, QualType ty, LValueBaseInfo baseInfo) {541return LValue::makeAddr(addr, ty, baseInfo);542}543544/// Return the address of a local variable.545Address getAddrOfLocalVar(const clang::VarDecl *vd) {546auto it = localDeclMap.find(vd);547assert(it != localDeclMap.end() &&548"Invalid argument to getAddrOfLocalVar(), no decl!");549return it->second;550}551552Address getAddrOfBitFieldStorage(LValue base, const clang::FieldDecl *field,553mlir::Type fieldType, unsigned index);554555/// Load the value for 'this'. This function is only valid while generating556/// code for an C++ member function.557/// FIXME(cir): this should return a mlir::Value!558mlir::Value loadCXXThis() {559assert(cxxThisValue && "no 'this' value for this function");560return cxxThisValue;561}562Address loadCXXThisAddress();563564/// Convert the given pointer to a complete class to the given direct base.565Address getAddressOfDirectBaseInCompleteClass(mlir::Location loc,566Address value,567const CXXRecordDecl *derived,568const CXXRecordDecl *base,569bool baseIsVirtual);570571/// Determine whether a base class initialization may overlap some other572/// object.573AggValueSlot::Overlap_t getOverlapForBaseInit(const CXXRecordDecl *rd,574const CXXRecordDecl *baseRD,575bool isVirtual);576577/// Get an appropriate 'undef' rvalue for the given type.578/// TODO: What's the equivalent for MLIR? Currently we're only using this for579/// void types so it just returns RValue::get(nullptr) but it'll need580/// addressed later.581RValue getUndefRValue(clang::QualType ty);582583cir::FuncOp generateCode(clang::GlobalDecl gd, cir::FuncOp fn,584cir::FuncType funcType);585586clang::QualType buildFunctionArgList(clang::GlobalDecl gd,587FunctionArgList &args);588589/// Emit code for the start of a function.590/// \param loc The location to be associated with the function.591/// \param startLoc The location of the function body.592void startFunction(clang::GlobalDecl gd, clang::QualType returnType,593cir::FuncOp fn, cir::FuncType funcType,594FunctionArgList args, clang::SourceLocation loc,595clang::SourceLocation startLoc);596597/// Represents a scope, including function bodies, compound statements, and598/// the substatements of if/while/do/for/switch/try statements. This class599/// handles any automatic cleanup, along with the return value.600struct LexicalScope {601private:602// TODO(CIR): This will live in the base class RunCleanupScope once that603// class is upstreamed.604CIRGenFunction &cgf;605606// Points to the scope entry block. This is useful, for instance, for607// helping to insert allocas before finalizing any recursive CodeGen from608// switches.609mlir::Block *entryBlock;610611LexicalScope *parentScope = nullptr;612613// Only Regular is used at the moment. Support for other kinds will be614// added as the relevant statements/expressions are upstreamed.615enum Kind {616Regular, // cir.if, cir.scope, if_regions617Ternary, // cir.ternary618Switch, // cir.switch619Try, // cir.try620GlobalInit // cir.global initialization code621};622Kind scopeKind = Kind::Regular;623624// The scope return value.625mlir::Value retVal = nullptr;626627mlir::Location beginLoc;628mlir::Location endLoc;629630public:631unsigned depth = 0;632633LexicalScope(CIRGenFunction &cgf, mlir::Location loc, mlir::Block *eb)634: cgf(cgf), entryBlock(eb), parentScope(cgf.curLexScope), beginLoc(loc),635endLoc(loc) {636637assert(entryBlock && "LexicalScope requires an entry block");638cgf.curLexScope = this;639if (parentScope)640++depth;641642if (const auto fusedLoc = mlir::dyn_cast<mlir::FusedLoc>(loc)) {643assert(fusedLoc.getLocations().size() == 2 && "too many locations");644beginLoc = fusedLoc.getLocations()[0];645endLoc = fusedLoc.getLocations()[1];646}647}648649void setRetVal(mlir::Value v) { retVal = v; }650651void cleanup();652void restore() { cgf.curLexScope = parentScope; }653654~LexicalScope() {655assert(!cir::MissingFeatures::generateDebugInfo());656cleanup();657restore();658}659660// ---661// Kind662// ---663bool isGlobalInit() { return scopeKind == Kind::GlobalInit; }664bool isRegular() { return scopeKind == Kind::Regular; }665bool isSwitch() { return scopeKind == Kind::Switch; }666bool isTernary() { return scopeKind == Kind::Ternary; }667bool isTry() { return scopeKind == Kind::Try; }668669void setAsGlobalInit() { scopeKind = Kind::GlobalInit; }670void setAsSwitch() { scopeKind = Kind::Switch; }671void setAsTernary() { scopeKind = Kind::Ternary; }672673// ---674// Return handling.675// ---676677private:678// `returnBlock`, `returnLoc`, and all the functions that deal with them679// will change and become more complicated when `switch` statements are680// upstreamed. `case` statements within the `switch` are in the same scope681// but have their own regions. Therefore the LexicalScope will need to682// keep track of multiple return blocks.683mlir::Block *returnBlock = nullptr;684std::optional<mlir::Location> returnLoc;685686// See the comment on `getOrCreateRetBlock`.687mlir::Block *createRetBlock(CIRGenFunction &cgf, mlir::Location loc) {688assert(returnBlock == nullptr && "only one return block per scope");689// Create the cleanup block but don't hook it up just yet.690mlir::OpBuilder::InsertionGuard guard(cgf.builder);691returnBlock =692cgf.builder.createBlock(cgf.builder.getBlock()->getParent());693updateRetLoc(returnBlock, loc);694return returnBlock;695}696697cir::ReturnOp emitReturn(mlir::Location loc);698void emitImplicitReturn();699700public:701mlir::Block *getRetBlock() { return returnBlock; }702mlir::Location getRetLoc(mlir::Block *b) { return *returnLoc; }703void updateRetLoc(mlir::Block *b, mlir::Location loc) { returnLoc = loc; }704705// Create the return block for this scope, or return the existing one.706// This get-or-create logic is necessary to handle multiple return707// statements within the same scope, which can happen if some of them are708// dead code or if there is a `goto` into the middle of the scope.709mlir::Block *getOrCreateRetBlock(CIRGenFunction &cgf, mlir::Location loc) {710if (returnBlock == nullptr) {711returnBlock = createRetBlock(cgf, loc);712return returnBlock;713}714updateRetLoc(returnBlock, loc);715return returnBlock;716}717718mlir::Block *getEntryBlock() { return entryBlock; }719};720721LexicalScope *curLexScope = nullptr;722723/// ----------------------724/// CIR emit functions725/// ----------------------726private:727void emitAndUpdateRetAlloca(clang::QualType type, mlir::Location loc,728clang::CharUnits alignment);729730CIRGenCallee emitDirectCallee(const GlobalDecl &gd);731732public:733Address emitAddrOfFieldStorage(Address base, const FieldDecl *field,734llvm::StringRef fieldName,735unsigned fieldIndex);736737mlir::Value emitAlloca(llvm::StringRef name, mlir::Type ty,738mlir::Location loc, clang::CharUnits alignment,739bool insertIntoFnEntryBlock,740mlir::Value arraySize = nullptr);741mlir::Value emitAlloca(llvm::StringRef name, mlir::Type ty,742mlir::Location loc, clang::CharUnits alignment,743mlir::OpBuilder::InsertPoint ip,744mlir::Value arraySize = nullptr);745746void emitAggregateStore(mlir::Value value, Address dest);747748void emitAggExpr(const clang::Expr *e, AggValueSlot slot);749750LValue emitAggExprToLValue(const Expr *e);751752/// Emit code to compute the specified expression which can have any type. The753/// result is returned as an RValue struct. If this is an aggregate754/// expression, the aggloc/agglocvolatile arguments indicate where the result755/// should be returned.756RValue emitAnyExpr(const clang::Expr *e,757AggValueSlot aggSlot = AggValueSlot::ignored());758759/// Similarly to emitAnyExpr(), however, the result will always be accessible760/// even if no aggregate location is provided.761RValue emitAnyExprToTemp(const clang::Expr *e);762763LValue emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e);764765Address emitArrayToPointerDecay(const Expr *array);766767AutoVarEmission emitAutoVarAlloca(const clang::VarDecl &d);768769/// Emit code and set up symbol table for a variable declaration with auto,770/// register, or no storage class specifier. These turn into simple stack771/// objects, globals depending on target.772void emitAutoVarDecl(const clang::VarDecl &d);773774void emitAutoVarCleanups(const AutoVarEmission &emission);775void emitAutoVarInit(const AutoVarEmission &emission);776777void emitBaseInitializer(mlir::Location loc, const CXXRecordDecl *classDecl,778CXXCtorInitializer *baseInit);779780LValue emitBinaryOperatorLValue(const BinaryOperator *e);781782mlir::LogicalResult emitBreakStmt(const clang::BreakStmt &s);783784RValue emitBuiltinExpr(const clang::GlobalDecl &gd, unsigned builtinID,785const clang::CallExpr *e, ReturnValueSlot returnValue);786787RValue emitCall(const CIRGenFunctionInfo &funcInfo,788const CIRGenCallee &callee, ReturnValueSlot returnValue,789const CallArgList &args, cir::CIRCallOpInterface *callOp,790mlir::Location loc);791RValue emitCall(const CIRGenFunctionInfo &funcInfo,792const CIRGenCallee &callee, ReturnValueSlot returnValue,793const CallArgList &args,794cir::CIRCallOpInterface *callOrTryCall = nullptr) {795assert(currSrcLoc && "source location must have been set");796return emitCall(funcInfo, callee, returnValue, args, callOrTryCall,797*currSrcLoc);798}799800RValue emitCall(clang::QualType calleeTy, const CIRGenCallee &callee,801const clang::CallExpr *e, ReturnValueSlot returnValue);802void emitCallArg(CallArgList &args, const clang::Expr *e,803clang::QualType argType);804void emitCallArgs(805CallArgList &args, PrototypeWrapper prototype,806llvm::iterator_range<clang::CallExpr::const_arg_iterator> argRange,807AbstractCallee callee = AbstractCallee(), unsigned paramsToSkip = 0);808RValue emitCallExpr(const clang::CallExpr *e,809ReturnValueSlot returnValue = ReturnValueSlot());810LValue emitCallExprLValue(const clang::CallExpr *e);811CIRGenCallee emitCallee(const clang::Expr *e);812813template <typename T>814mlir::LogicalResult emitCaseDefaultCascade(const T *stmt, mlir::Type condType,815mlir::ArrayAttr value,816cir::CaseOpKind kind,817bool buildingTopLevelCase);818819mlir::LogicalResult emitCaseStmt(const clang::CaseStmt &s,820mlir::Type condType,821bool buildingTopLevelCase);822823LValue emitCastLValue(const CastExpr *e);824825/// Emits an argument for a call to a `__builtin_assume`. If the builtin826/// sanitizer is enabled, a runtime check is also emitted.827mlir::Value emitCheckedArgForAssume(const Expr *e);828829LValue emitCompoundAssignmentLValue(const clang::CompoundAssignOperator *e);830831void emitConstructorBody(FunctionArgList &args);832void emitDestructorBody(FunctionArgList &args);833834mlir::LogicalResult emitContinueStmt(const clang::ContinueStmt &s);835836void emitCXXConstructExpr(const clang::CXXConstructExpr *e,837AggValueSlot dest);838839void emitCXXConstructorCall(const clang::CXXConstructorDecl *d,840clang::CXXCtorType type, bool forVirtualBase,841bool delegating, AggValueSlot thisAVS,842const clang::CXXConstructExpr *e);843844void emitCXXConstructorCall(const clang::CXXConstructorDecl *d,845clang::CXXCtorType type, bool forVirtualBase,846bool delegating, Address thisAddr,847CallArgList &args, clang::SourceLocation loc);848849mlir::LogicalResult emitCXXForRangeStmt(const CXXForRangeStmt &s,850llvm::ArrayRef<const Attr *> attrs);851852RValue emitCXXMemberCallExpr(const clang::CXXMemberCallExpr *e,853ReturnValueSlot returnValue);854855RValue emitCXXMemberOrOperatorCall(856const clang::CXXMethodDecl *md, const CIRGenCallee &callee,857ReturnValueSlot returnValue, mlir::Value thisPtr,858mlir::Value implicitParam, clang::QualType implicitParamTy,859const clang::CallExpr *ce, CallArgList *rtlArgs);860861RValue emitCXXMemberOrOperatorMemberCallExpr(862const clang::CallExpr *ce, const clang::CXXMethodDecl *md,863ReturnValueSlot returnValue, bool hasQualifier,864clang::NestedNameSpecifier *qualifier, bool isArrow,865const clang::Expr *base);866867mlir::Value emitCXXNewExpr(const CXXNewExpr *e);868869RValue emitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *e,870const CXXMethodDecl *md,871ReturnValueSlot returnValue);872873void emitCtorPrologue(const clang::CXXConstructorDecl *ctor,874clang::CXXCtorType ctorType, FunctionArgList &args);875876// It's important not to confuse this and emitDelegateCXXConstructorCall.877// Delegating constructors are the C++11 feature. The constructor delegate878// optimization is used to reduce duplication in the base and complete879// constructors where they are substantially the same.880void emitDelegatingCXXConstructorCall(const CXXConstructorDecl *ctor,881const FunctionArgList &args);882883mlir::LogicalResult emitDoStmt(const clang::DoStmt &s);884885/// Emit an expression as an initializer for an object (variable, field, etc.)886/// at the given location. The expression is not necessarily the normal887/// initializer for the object, and the address is not necessarily888/// its normal location.889///890/// \param init the initializing expression891/// \param d the object to act as if we're initializing892/// \param lvalue the lvalue to initialize893/// \param capturedByInit true if \p d is a __block variable whose address is894/// potentially changed by the initializer895void emitExprAsInit(const clang::Expr *init, const clang::ValueDecl *d,896LValue lvalue, bool capturedByInit = false);897898mlir::LogicalResult emitFunctionBody(const clang::Stmt *body);899900void emitImplicitAssignmentOperatorBody(FunctionArgList &args);901902void emitInitializerForField(clang::FieldDecl *field, LValue lhs,903clang::Expr *init);904905mlir::Value emitPromotedComplexExpr(const Expr *e, QualType promotionType);906907mlir::Value emitPromotedScalarExpr(const Expr *e, QualType promotionType);908909/// Emit the computation of the specified expression of scalar type.910mlir::Value emitScalarExpr(const clang::Expr *e);911912mlir::Value emitScalarPrePostIncDec(const UnaryOperator *e, LValue lv,913bool isInc, bool isPre);914915/// Build a debug stoppoint if we are emitting debug info.916void emitStopPoint(const Stmt *s);917918// Build CIR for a statement. useCurrentScope should be true if no919// new scopes need be created when finding a compound statement.920mlir::LogicalResult emitStmt(const clang::Stmt *s, bool useCurrentScope,921llvm::ArrayRef<const Attr *> attrs = {});922923mlir::LogicalResult emitSimpleStmt(const clang::Stmt *s,924bool useCurrentScope);925926mlir::LogicalResult emitForStmt(const clang::ForStmt &s);927928/// Emit the computation of the specified expression of complex type,929/// returning the result.930mlir::Value emitComplexExpr(const Expr *e);931932LValue emitComplexAssignmentLValue(const BinaryOperator *e);933934void emitCompoundStmt(const clang::CompoundStmt &s);935936void emitCompoundStmtWithoutScope(const clang::CompoundStmt &s);937938void emitDecl(const clang::Decl &d);939mlir::LogicalResult emitDeclStmt(const clang::DeclStmt &s);940LValue emitDeclRefLValue(const clang::DeclRefExpr *e);941942mlir::LogicalResult emitDefaultStmt(const clang::DefaultStmt &s,943mlir::Type condType,944bool buildingTopLevelCase);945946void emitDelegateCXXConstructorCall(const clang::CXXConstructorDecl *ctor,947clang::CXXCtorType ctorType,948const FunctionArgList &args,949clang::SourceLocation loc);950951/// We are performing a delegate call; that is, the current function is952/// delegating to another one. Produce a r-value suitable for passing the953/// given parameter.954void emitDelegateCallArg(CallArgList &args, const clang::VarDecl *param,955clang::SourceLocation loc);956957/// Emit an `if` on a boolean condition to the specified blocks.958/// FIXME: Based on the condition, this might try to simplify the codegen of959/// the conditional based on the branch.960/// In the future, we may apply code generation simplifications here,961/// similar to those used in classic LLVM codegen962/// See `EmitBranchOnBoolExpr` for inspiration.963mlir::LogicalResult emitIfOnBoolExpr(const clang::Expr *cond,964const clang::Stmt *thenS,965const clang::Stmt *elseS);966cir::IfOp emitIfOnBoolExpr(const clang::Expr *cond,967BuilderCallbackRef thenBuilder,968mlir::Location thenLoc,969BuilderCallbackRef elseBuilder,970std::optional<mlir::Location> elseLoc = {});971972mlir::Value emitOpOnBoolExpr(mlir::Location loc, const clang::Expr *cond);973974mlir::LogicalResult emitIfStmt(const clang::IfStmt &s);975976/// Emit code to compute the specified expression,977/// ignoring the result.978void emitIgnoredExpr(const clang::Expr *e);979980RValue emitLoadOfBitfieldLValue(LValue lv, SourceLocation loc);981982/// Given an expression that represents a value lvalue, this method emits983/// the address of the lvalue, then loads the result as an rvalue,984/// returning the rvalue.985RValue emitLoadOfLValue(LValue lv, SourceLocation loc);986987Address emitLoadOfReference(LValue refLVal, mlir::Location loc,988LValueBaseInfo *pointeeBaseInfo);989LValue emitLoadOfReferenceLValue(Address refAddr, mlir::Location loc,990QualType refTy, AlignmentSource source);991992/// EmitLoadOfScalar - Load a scalar value from an address, taking993/// care to appropriately convert from the memory representation to994/// the LLVM value representation. The l-value must be a simple995/// l-value.996mlir::Value emitLoadOfScalar(LValue lvalue, SourceLocation loc);997998/// Emit code to compute a designator that specifies the location999/// of the expression.1000/// FIXME: document this function better.1001LValue emitLValue(const clang::Expr *e);1002LValue emitLValueForBitField(LValue base, const FieldDecl *field);1003LValue emitLValueForField(LValue base, const clang::FieldDecl *field);10041005/// Like emitLValueForField, excpet that if the Field is a reference, this1006/// will return the address of the reference and not the address of the value1007/// stored in the reference.1008LValue emitLValueForFieldInitialization(LValue base,1009const clang::FieldDecl *field,1010llvm::StringRef fieldName);10111012LValue emitMemberExpr(const MemberExpr *e);10131014/// Given an expression with a pointer type, emit the value and compute our1015/// best estimate of the alignment of the pointee.1016///1017/// One reasonable way to use this information is when there's a language1018/// guarantee that the pointer must be aligned to some stricter value, and1019/// we're simply trying to ensure that sufficiently obvious uses of under-1020/// aligned objects don't get miscompiled; for example, a placement new1021/// into the address of a local variable. In such a case, it's quite1022/// reasonable to just ignore the returned alignment when it isn't from an1023/// explicit source.1024Address emitPointerWithAlignment(const clang::Expr *expr,1025LValueBaseInfo *baseInfo);10261027/// Emits a reference binding to the passed in expression.1028RValue emitReferenceBindingToExpr(const Expr *e);10291030mlir::LogicalResult emitReturnStmt(const clang::ReturnStmt &s);10311032mlir::Value emitScalarConstant(const ConstantEmission &constant, Expr *e);10331034/// Emit a conversion from the specified type to the specified destination1035/// type, both of which are CIR scalar types.1036mlir::Value emitScalarConversion(mlir::Value src, clang::QualType srcType,1037clang::QualType dstType,1038clang::SourceLocation loc);10391040void emitScalarInit(const clang::Expr *init, mlir::Location loc,1041LValue lvalue, bool capturedByInit = false);10421043void emitStaticVarDecl(const VarDecl &d, cir::GlobalLinkageKind linkage);10441045void emitStoreOfComplex(mlir::Location loc, mlir::Value v, LValue dest,1046bool isInit);10471048void emitStoreOfScalar(mlir::Value value, Address addr, bool isVolatile,1049clang::QualType ty, bool isInit = false,1050bool isNontemporal = false);1051void emitStoreOfScalar(mlir::Value value, LValue lvalue, bool isInit);10521053/// Store the specified rvalue into the specified1054/// lvalue, where both are guaranteed to the have the same type, and that type1055/// is 'Ty'.1056void emitStoreThroughLValue(RValue src, LValue dst, bool isInit = false);10571058mlir::Value emitStoreThroughBitfieldLValue(RValue src, LValue dstresult);10591060LValue emitStringLiteralLValue(const StringLiteral *e);10611062mlir::LogicalResult emitSwitchBody(const clang::Stmt *s);1063mlir::LogicalResult emitSwitchCase(const clang::SwitchCase &s,1064bool buildingTopLevelCase);1065mlir::LogicalResult emitSwitchStmt(const clang::SwitchStmt &s);10661067/// Given a value and its clang type, returns the value casted to its memory1068/// representation.1069/// Note: CIR defers most of the special casting to the final lowering passes1070/// to conserve the high level information.1071mlir::Value emitToMemory(mlir::Value value, clang::QualType ty);10721073LValue emitUnaryOpLValue(const clang::UnaryOperator *e);10741075/// This method handles emission of any variable declaration1076/// inside a function, including static vars etc.1077void emitVarDecl(const clang::VarDecl &d);10781079mlir::LogicalResult emitWhileStmt(const clang::WhileStmt &s);10801081/// Given an assignment `*lhs = rhs`, emit a test that checks if \p rhs is1082/// nonnull, if 1\p LHS is marked _Nonnull.1083void emitNullabilityCheck(LValue lhs, mlir::Value rhs,1084clang::SourceLocation loc);10851086/// An object to manage conditionally-evaluated expressions.1087class ConditionalEvaluation {1088CIRGenFunction &cgf;1089mlir::OpBuilder::InsertPoint insertPt;10901091public:1092ConditionalEvaluation(CIRGenFunction &cgf)1093: cgf(cgf), insertPt(cgf.builder.saveInsertionPoint()) {}1094ConditionalEvaluation(CIRGenFunction &cgf, mlir::OpBuilder::InsertPoint ip)1095: cgf(cgf), insertPt(ip) {}10961097void beginEvaluation() {1098assert(cgf.outermostConditional != this);1099if (!cgf.outermostConditional)1100cgf.outermostConditional = this;1101}11021103void endEvaluation() {1104assert(cgf.outermostConditional != nullptr);1105if (cgf.outermostConditional == this)1106cgf.outermostConditional = nullptr;1107}11081109/// Returns the insertion point which will be executed prior to each1110/// evaluation of the conditional code. In LLVM OG, this method1111/// is called getStartingBlock.1112mlir::OpBuilder::InsertPoint getInsertPoint() const { return insertPt; }1113};11141115struct ConditionalInfo {1116std::optional<LValue> lhs{}, rhs{};1117mlir::Value result{};1118};11191120// Return true if we're currently emitting one branch or the other of a1121// conditional expression.1122bool isInConditionalBranch() const { return outermostConditional != nullptr; }11231124void setBeforeOutermostConditional(mlir::Value value, Address addr) {1125assert(isInConditionalBranch());1126{1127mlir::OpBuilder::InsertionGuard guard(builder);1128builder.restoreInsertionPoint(outermostConditional->getInsertPoint());1129builder.createStore(1130value.getLoc(), value, addr,1131mlir::IntegerAttr::get(1132mlir::IntegerType::get(value.getContext(), 64),1133(uint64_t)addr.getAlignment().getAsAlign().value()));1134}1135}11361137// Points to the outermost active conditional control. This is used so that1138// we know if a temporary should be destroyed conditionally.1139ConditionalEvaluation *outermostConditional = nullptr;11401141template <typename FuncTy>1142ConditionalInfo emitConditionalBlocks(const AbstractConditionalOperator *e,1143const FuncTy &branchGenFunc);11441145mlir::Value emitTernaryOnBoolExpr(const clang::Expr *cond, mlir::Location loc,1146const clang::Stmt *thenS,1147const clang::Stmt *elseS);11481149/// ----------------------1150/// CIR build helpers1151/// -----------------1152public:1153cir::AllocaOp createTempAlloca(mlir::Type ty, mlir::Location loc,1154const Twine &name = "tmp",1155mlir::Value arraySize = nullptr,1156bool insertIntoFnEntryBlock = false);1157cir::AllocaOp createTempAlloca(mlir::Type ty, mlir::Location loc,1158const Twine &name = "tmp",1159mlir::OpBuilder::InsertPoint ip = {},1160mlir::Value arraySize = nullptr);1161Address createTempAlloca(mlir::Type ty, CharUnits align, mlir::Location loc,1162const Twine &name = "tmp",1163mlir::Value arraySize = nullptr,1164Address *alloca = nullptr,1165mlir::OpBuilder::InsertPoint ip = {});1166Address createTempAllocaWithoutCast(mlir::Type ty, CharUnits align,1167mlir::Location loc,1168const Twine &name = "tmp",1169mlir::Value arraySize = nullptr,1170mlir::OpBuilder::InsertPoint ip = {});11711172/// Create a temporary memory object of the given type, with1173/// appropriate alignmen and cast it to the default address space. Returns1174/// the original alloca instruction by \p Alloca if it is not nullptr.1175Address createMemTemp(QualType t, mlir::Location loc,1176const Twine &name = "tmp", Address *alloca = nullptr,1177mlir::OpBuilder::InsertPoint ip = {});1178Address createMemTemp(QualType t, CharUnits align, mlir::Location loc,1179const Twine &name = "tmp", Address *alloca = nullptr,1180mlir::OpBuilder::InsertPoint ip = {});11811182//===--------------------------------------------------------------------===//1183// OpenACC Emission1184//===--------------------------------------------------------------------===//1185private:1186template <typename Op>1187Op emitOpenACCOp(mlir::Location start, OpenACCDirectiveKind dirKind,1188SourceLocation dirLoc,1189llvm::ArrayRef<const OpenACCClause *> clauses);1190// Function to do the basic implementation of an operation with an Associated1191// Statement. Models AssociatedStmtConstruct.1192template <typename Op, typename TermOp>1193mlir::LogicalResult emitOpenACCOpAssociatedStmt(1194mlir::Location start, mlir::Location end, OpenACCDirectiveKind dirKind,1195SourceLocation dirLoc, llvm::ArrayRef<const OpenACCClause *> clauses,1196const Stmt *associatedStmt);11971198template <typename Op, typename TermOp>1199mlir::LogicalResult emitOpenACCOpCombinedConstruct(1200mlir::Location start, mlir::Location end, OpenACCDirectiveKind dirKind,1201SourceLocation dirLoc, llvm::ArrayRef<const OpenACCClause *> clauses,1202const Stmt *loopStmt);12031204template <typename Op>1205void emitOpenACCClauses(Op &op, OpenACCDirectiveKind dirKind,1206SourceLocation dirLoc,1207ArrayRef<const OpenACCClause *> clauses);1208// The second template argument doesn't need to be a template, since it should1209// always be an mlir::acc::LoopOp, but as this is a template anyway, we make1210// it a template argument as this way we can avoid including the OpenACC MLIR1211// headers here. We will count on linker failures/explicit instantiation to1212// ensure we don't mess this up, but it is only called from 1 place, and1213// instantiated 3x.1214template <typename ComputeOp, typename LoopOp>1215void emitOpenACCClauses(ComputeOp &op, LoopOp &loopOp,1216OpenACCDirectiveKind dirKind, SourceLocation dirLoc,1217ArrayRef<const OpenACCClause *> clauses);12181219// The OpenACC LoopOp requires that we have auto, seq, or independent on all1220// LoopOp operations for the 'none' device type case. This function checks if1221// the LoopOp has one, else it updates it to have one.1222void updateLoopOpParallelism(mlir::acc::LoopOp &op, bool isOrphan,1223OpenACCDirectiveKind dk);12241225// The OpenACC 'cache' construct actually applies to the 'loop' if present. So1226// keep track of the 'loop' so that we can add the cache vars to it correctly.1227mlir::acc::LoopOp *activeLoopOp = nullptr;12281229struct ActiveOpenACCLoopRAII {1230CIRGenFunction &cgf;1231mlir::acc::LoopOp *oldLoopOp;12321233ActiveOpenACCLoopRAII(CIRGenFunction &cgf, mlir::acc::LoopOp *newOp)1234: cgf(cgf), oldLoopOp(cgf.activeLoopOp) {1235cgf.activeLoopOp = newOp;1236}1237~ActiveOpenACCLoopRAII() { cgf.activeLoopOp = oldLoopOp; }1238};12391240public:1241// Helper type used to store the list of important information for a 'data'1242// clause variable, or a 'cache' variable reference.1243struct OpenACCDataOperandInfo {1244mlir::Location beginLoc;1245mlir::Value varValue;1246std::string name;1247llvm::SmallVector<mlir::Value> bounds;1248};1249// Gets the collection of info required to lower and OpenACC clause or cache1250// construct variable reference.1251OpenACCDataOperandInfo getOpenACCDataOperandInfo(const Expr *e);1252// Helper function to emit the integer expressions as required by an OpenACC1253// clause/construct.1254mlir::Value emitOpenACCIntExpr(const Expr *intExpr);1255// Helper function to emit an integer constant as an mlir int type, used for1256// constants in OpenACC constructs/clauses.1257mlir::Value createOpenACCConstantInt(mlir::Location loc, unsigned width,1258int64_t value);12591260mlir::LogicalResult1261emitOpenACCComputeConstruct(const OpenACCComputeConstruct &s);1262mlir::LogicalResult emitOpenACCLoopConstruct(const OpenACCLoopConstruct &s);1263mlir::LogicalResult1264emitOpenACCCombinedConstruct(const OpenACCCombinedConstruct &s);1265mlir::LogicalResult emitOpenACCDataConstruct(const OpenACCDataConstruct &s);1266mlir::LogicalResult1267emitOpenACCEnterDataConstruct(const OpenACCEnterDataConstruct &s);1268mlir::LogicalResult1269emitOpenACCExitDataConstruct(const OpenACCExitDataConstruct &s);1270mlir::LogicalResult1271emitOpenACCHostDataConstruct(const OpenACCHostDataConstruct &s);1272mlir::LogicalResult emitOpenACCWaitConstruct(const OpenACCWaitConstruct &s);1273mlir::LogicalResult emitOpenACCInitConstruct(const OpenACCInitConstruct &s);1274mlir::LogicalResult1275emitOpenACCShutdownConstruct(const OpenACCShutdownConstruct &s);1276mlir::LogicalResult emitOpenACCSetConstruct(const OpenACCSetConstruct &s);1277mlir::LogicalResult1278emitOpenACCUpdateConstruct(const OpenACCUpdateConstruct &s);1279mlir::LogicalResult1280emitOpenACCAtomicConstruct(const OpenACCAtomicConstruct &s);1281mlir::LogicalResult emitOpenACCCacheConstruct(const OpenACCCacheConstruct &s);12821283void emitOpenACCDeclare(const OpenACCDeclareDecl &d);1284void emitOpenACCRoutine(const OpenACCRoutineDecl &d);12851286/// Create a temporary memory object for the given aggregate type.1287AggValueSlot createAggTemp(QualType ty, mlir::Location loc,1288const Twine &name = "tmp",1289Address *alloca = nullptr) {1290assert(!cir::MissingFeatures::aggValueSlot());1291return AggValueSlot::forAddr(1292createMemTemp(ty, loc, name, alloca), ty.getQualifiers(),1293AggValueSlot::IsNotDestructed, AggValueSlot::IsNotAliased,1294AggValueSlot::DoesNotOverlap);1295}12961297private:1298QualType getVarArgType(const Expr *arg);1299};13001301} // namespace clang::CIRGen13021303#endif130413051306