2105 lines · c
1//===----------------------------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// Internal per-function state used for AST-to-ClangIR code gen10//11//===----------------------------------------------------------------------===//12 13#ifndef CLANG_LIB_CIR_CODEGEN_CIRGENFUNCTION_H14#define CLANG_LIB_CIR_CODEGEN_CIRGENFUNCTION_H15 16#include "CIRGenBuilder.h"17#include "CIRGenCall.h"18#include "CIRGenModule.h"19#include "CIRGenTypeCache.h"20#include "CIRGenValue.h"21#include "EHScopeStack.h"22 23#include "Address.h"24 25#include "clang/AST/ASTContext.h"26#include "clang/AST/BaseSubobject.h"27#include "clang/AST/CharUnits.h"28#include "clang/AST/CurrentSourceLocExprScope.h"29#include "clang/AST/Decl.h"30#include "clang/AST/ExprCXX.h"31#include "clang/AST/Stmt.h"32#include "clang/AST/Type.h"33#include "clang/Basic/OperatorKinds.h"34#include "clang/CIR/Dialect/IR/CIRDialect.h"35#include "clang/CIR/MissingFeatures.h"36#include "clang/CIR/TypeEvaluationKind.h"37#include "llvm/ADT/ScopedHashTable.h"38 39namespace {40class ScalarExprEmitter;41} // namespace42 43namespace mlir {44namespace acc {45class LoopOp;46} // namespace acc47} // namespace mlir48 49namespace clang::CIRGen {50 51struct CGCoroData;52 53class CIRGenFunction : public CIRGenTypeCache {54public:55 CIRGenModule &cgm;56 57private:58 friend class ::ScalarExprEmitter;59 /// The builder is a helper class to create IR inside a function. The60 /// builder is stateful, in particular it keeps an "insertion point": this61 /// is where the next operations will be introduced.62 CIRGenBuilderTy &builder;63 64 /// A jump destination is an abstract label, branching to which may65 /// require a jump out through normal cleanups.66 struct JumpDest {67 JumpDest() = default;68 JumpDest(mlir::Block *block, EHScopeStack::stable_iterator depth = {},69 unsigned index = 0)70 : block(block) {}71 72 bool isValid() const { return block != nullptr; }73 mlir::Block *getBlock() const { return block; }74 EHScopeStack::stable_iterator getScopeDepth() const { return scopeDepth; }75 unsigned getDestIndex() const { return index; }76 77 // This should be used cautiously.78 void setScopeDepth(EHScopeStack::stable_iterator depth) {79 scopeDepth = depth;80 }81 82 private:83 mlir::Block *block = nullptr;84 EHScopeStack::stable_iterator scopeDepth;85 unsigned index;86 };87 88public:89 /// The GlobalDecl for the current function being compiled or the global90 /// variable currently being initialized.91 clang::GlobalDecl curGD;92 93 /// Unified return block.94 /// In CIR this is a function because each scope might have95 /// its associated return block.96 JumpDest returnBlock(mlir::Block *retBlock) {97 return getJumpDestInCurrentScope(retBlock);98 }99 100 unsigned nextCleanupDestIndex = 1;101 102 /// The compiler-generated variable that holds the return value.103 std::optional<mlir::Value> fnRetAlloca;104 105 // Holds coroutine data if the current function is a coroutine. We use a106 // wrapper to manage its lifetime, so that we don't have to define CGCoroData107 // in this header.108 struct CGCoroInfo {109 std::unique_ptr<CGCoroData> data;110 CGCoroInfo();111 ~CGCoroInfo();112 };113 CGCoroInfo curCoro;114 115 bool isCoroutine() const { return curCoro.data != nullptr; }116 117 /// The temporary alloca to hold the return value. This is118 /// invalid iff the function has no return value.119 Address returnValue = Address::invalid();120 121 /// Tracks function scope overall cleanup handling.122 EHScopeStack ehStack;123 124 GlobalDecl curSEHParent;125 126 llvm::DenseMap<const clang::ValueDecl *, clang::FieldDecl *>127 lambdaCaptureFields;128 clang::FieldDecl *lambdaThisCaptureField = nullptr;129 130 /// CXXThisDecl - When generating code for a C++ member function,131 /// this will hold the implicit 'this' declaration.132 ImplicitParamDecl *cxxabiThisDecl = nullptr;133 mlir::Value cxxabiThisValue = nullptr;134 mlir::Value cxxThisValue = nullptr;135 clang::CharUnits cxxThisAlignment;136 137 /// When generating code for a constructor or destructor, this will hold the138 /// implicit argument (e.g. VTT).139 ImplicitParamDecl *cxxStructorImplicitParamDecl{};140 mlir::Value cxxStructorImplicitParamValue{};141 142 /// The value of 'this' to sue when evaluating CXXDefaultInitExprs within this143 /// expression.144 Address cxxDefaultInitExprThis = Address::invalid();145 146 // Holds the Decl for the current outermost non-closure context147 const clang::Decl *curFuncDecl = nullptr;148 /// This is the inner-most code context, which includes blocks.149 const clang::Decl *curCodeDecl = nullptr;150 151 /// The current function or global initializer that is generated code for.152 /// This is usually a cir::FuncOp, but it can also be a cir::GlobalOp for153 /// global initializers.154 mlir::Operation *curFn = nullptr;155 156 /// Save Parameter Decl for coroutine.157 llvm::SmallVector<const ParmVarDecl *> fnArgs;158 159 using DeclMapTy = llvm::DenseMap<const clang::Decl *, Address>;160 /// This keeps track of the CIR allocas or globals for local C161 /// declarations.162 DeclMapTy localDeclMap;163 164 /// The type of the condition for the emitting switch statement.165 llvm::SmallVector<mlir::Type, 2> condTypeStack;166 167 clang::ASTContext &getContext() const { return cgm.getASTContext(); }168 169 CIRGenBuilderTy &getBuilder() { return builder; }170 171 CIRGenModule &getCIRGenModule() { return cgm; }172 const CIRGenModule &getCIRGenModule() const { return cgm; }173 174 mlir::Block *getCurFunctionEntryBlock() {175 // We currently assume this isn't called for a global initializer.176 auto fn = mlir::cast<cir::FuncOp>(curFn);177 return &fn.getRegion().front();178 }179 180 /// Sanitizers enabled for this function.181 clang::SanitizerSet sanOpts;182 183 /// The symbol table maps a variable name to a value in the current scope.184 /// Entering a function creates a new scope, and the function arguments are185 /// added to the mapping. When the processing of a function is terminated,186 /// the scope is destroyed and the mappings created in this scope are187 /// dropped.188 using SymTableTy = llvm::ScopedHashTable<const clang::Decl *, mlir::Value>;189 SymTableTy symbolTable;190 191 /// Whether a cir.stacksave operation has been added. Used to avoid192 /// inserting cir.stacksave for multiple VLAs in the same scope.193 bool didCallStackSave = false;194 195 /// Whether or not a Microsoft-style asm block has been processed within196 /// this fuction. These can potentially set the return value.197 bool sawAsmBlock = false;198 199 mlir::Type convertTypeForMem(QualType t);200 201 mlir::Type convertType(clang::QualType t);202 mlir::Type convertType(const TypeDecl *t) {203 return convertType(getContext().getTypeDeclType(t));204 }205 206 /// Return the cir::TypeEvaluationKind of QualType \c type.207 static cir::TypeEvaluationKind getEvaluationKind(clang::QualType type);208 209 static bool hasScalarEvaluationKind(clang::QualType type) {210 return getEvaluationKind(type) == cir::TEK_Scalar;211 }212 213 static bool hasAggregateEvaluationKind(clang::QualType type) {214 return getEvaluationKind(type) == cir::TEK_Aggregate;215 }216 217 CIRGenFunction(CIRGenModule &cgm, CIRGenBuilderTy &builder,218 bool suppressNewContext = false);219 ~CIRGenFunction();220 221 CIRGenTypes &getTypes() const { return cgm.getTypes(); }222 223 const TargetInfo &getTarget() const { return cgm.getTarget(); }224 mlir::MLIRContext &getMLIRContext() { return cgm.getMLIRContext(); }225 226 const TargetCIRGenInfo &getTargetHooks() const {227 return cgm.getTargetCIRGenInfo();228 }229 230 // ---------------------231 // Opaque value handling232 // ---------------------233 234 /// Keeps track of the current set of opaque value expressions.235 llvm::DenseMap<const OpaqueValueExpr *, LValue> opaqueLValues;236 llvm::DenseMap<const OpaqueValueExpr *, RValue> opaqueRValues;237 238 // This keeps track of the associated size for each VLA type.239 // We track this by the size expression rather than the type itself because240 // in certain situations, like a const qualifier applied to an VLA typedef,241 // multiple VLA types can share the same size expression.242 // FIXME: Maybe this could be a stack of maps that is pushed/popped as we243 // enter/leave scopes.244 llvm::DenseMap<const Expr *, mlir::Value> vlaSizeMap;245 246public:247 /// A non-RAII class containing all the information about a bound248 /// opaque value. OpaqueValueMapping, below, is a RAII wrapper for249 /// this which makes individual mappings very simple; using this250 /// class directly is useful when you have a variable number of251 /// opaque values or don't want the RAII functionality for some252 /// reason.253 class OpaqueValueMappingData {254 const OpaqueValueExpr *opaqueValue;255 bool boundLValue;256 257 OpaqueValueMappingData(const OpaqueValueExpr *ov, bool boundLValue)258 : opaqueValue(ov), boundLValue(boundLValue) {}259 260 public:261 OpaqueValueMappingData() : opaqueValue(nullptr) {}262 263 static bool shouldBindAsLValue(const Expr *expr) {264 // gl-values should be bound as l-values for obvious reasons.265 // Records should be bound as l-values because IR generation266 // always keeps them in memory. Expressions of function type267 // act exactly like l-values but are formally required to be268 // r-values in C.269 return expr->isGLValue() || expr->getType()->isFunctionType() ||270 hasAggregateEvaluationKind(expr->getType());271 }272 273 static OpaqueValueMappingData274 bind(CIRGenFunction &cgf, const OpaqueValueExpr *ov, const Expr *e) {275 if (shouldBindAsLValue(ov))276 return bind(cgf, ov, cgf.emitLValue(e));277 return bind(cgf, ov, cgf.emitAnyExpr(e));278 }279 280 static OpaqueValueMappingData281 bind(CIRGenFunction &cgf, const OpaqueValueExpr *ov, const LValue &lv) {282 assert(shouldBindAsLValue(ov));283 cgf.opaqueLValues.insert(std::make_pair(ov, lv));284 return OpaqueValueMappingData(ov, true);285 }286 287 static OpaqueValueMappingData288 bind(CIRGenFunction &cgf, const OpaqueValueExpr *ov, const RValue &rv) {289 assert(!shouldBindAsLValue(ov));290 cgf.opaqueRValues.insert(std::make_pair(ov, rv));291 292 OpaqueValueMappingData data(ov, false);293 294 // Work around an extremely aggressive peephole optimization in295 // EmitScalarConversion which assumes that all other uses of a296 // value are extant.297 assert(!cir::MissingFeatures::peepholeProtection() && "NYI");298 return data;299 }300 301 bool isValid() const { return opaqueValue != nullptr; }302 void clear() { opaqueValue = nullptr; }303 304 void unbind(CIRGenFunction &cgf) {305 assert(opaqueValue && "no data to unbind!");306 307 if (boundLValue) {308 cgf.opaqueLValues.erase(opaqueValue);309 } else {310 cgf.opaqueRValues.erase(opaqueValue);311 assert(!cir::MissingFeatures::peepholeProtection() && "NYI");312 }313 }314 };315 316 /// An RAII object to set (and then clear) a mapping for an OpaqueValueExpr.317 class OpaqueValueMapping {318 CIRGenFunction &cgf;319 OpaqueValueMappingData data;320 321 public:322 static bool shouldBindAsLValue(const Expr *expr) {323 return OpaqueValueMappingData::shouldBindAsLValue(expr);324 }325 326 /// Build the opaque value mapping for the given conditional327 /// operator if it's the GNU ?: extension. This is a common328 /// enough pattern that the convenience operator is really329 /// helpful.330 ///331 OpaqueValueMapping(CIRGenFunction &cgf,332 const AbstractConditionalOperator *op)333 : cgf(cgf) {334 if (mlir::isa<ConditionalOperator>(op))335 // Leave Data empty.336 return;337 338 const BinaryConditionalOperator *e =339 mlir::cast<BinaryConditionalOperator>(op);340 data = OpaqueValueMappingData::bind(cgf, e->getOpaqueValue(),341 e->getCommon());342 }343 344 /// Build the opaque value mapping for an OpaqueValueExpr whose source345 /// expression is set to the expression the OVE represents.346 OpaqueValueMapping(CIRGenFunction &cgf, const OpaqueValueExpr *ov)347 : cgf(cgf) {348 if (ov) {349 assert(ov->getSourceExpr() && "wrong form of OpaqueValueMapping used "350 "for OVE with no source expression");351 data = OpaqueValueMappingData::bind(cgf, ov, ov->getSourceExpr());352 }353 }354 355 OpaqueValueMapping(CIRGenFunction &cgf, const OpaqueValueExpr *opaqueValue,356 LValue lvalue)357 : cgf(cgf),358 data(OpaqueValueMappingData::bind(cgf, opaqueValue, lvalue)) {}359 360 OpaqueValueMapping(CIRGenFunction &cgf, const OpaqueValueExpr *opaqueValue,361 RValue rvalue)362 : cgf(cgf),363 data(OpaqueValueMappingData::bind(cgf, opaqueValue, rvalue)) {}364 365 void pop() {366 data.unbind(cgf);367 data.clear();368 }369 370 ~OpaqueValueMapping() {371 if (data.isValid())372 data.unbind(cgf);373 }374 };375 376private:377 /// Declare a variable in the current scope, return success if the variable378 /// wasn't declared yet.379 void declare(mlir::Value addrVal, const clang::Decl *var, clang::QualType ty,380 mlir::Location loc, clang::CharUnits alignment,381 bool isParam = false);382 383public:384 mlir::Value createDummyValue(mlir::Location loc, clang::QualType qt);385 386 void emitNullInitialization(mlir::Location loc, Address destPtr, QualType ty);387 388private:389 // Track current variable initialization (if there's one)390 const clang::VarDecl *currVarDecl = nullptr;391 class VarDeclContext {392 CIRGenFunction &p;393 const clang::VarDecl *oldVal = nullptr;394 395 public:396 VarDeclContext(CIRGenFunction &p, const VarDecl *value) : p(p) {397 if (p.currVarDecl)398 oldVal = p.currVarDecl;399 p.currVarDecl = value;400 }401 402 /// Can be used to restore the state early, before the dtor403 /// is run.404 void restore() { p.currVarDecl = oldVal; }405 ~VarDeclContext() { restore(); }406 };407 408public:409 /// Use to track source locations across nested visitor traversals.410 /// Always use a `SourceLocRAIIObject` to change currSrcLoc.411 std::optional<mlir::Location> currSrcLoc;412 class SourceLocRAIIObject {413 CIRGenFunction &cgf;414 std::optional<mlir::Location> oldLoc;415 416 public:417 SourceLocRAIIObject(CIRGenFunction &cgf, mlir::Location value) : cgf(cgf) {418 if (cgf.currSrcLoc)419 oldLoc = cgf.currSrcLoc;420 cgf.currSrcLoc = value;421 }422 423 /// Can be used to restore the state early, before the dtor424 /// is run.425 void restore() { cgf.currSrcLoc = oldLoc; }426 ~SourceLocRAIIObject() { restore(); }427 };428 429 using SymTableScopeTy =430 llvm::ScopedHashTableScope<const clang::Decl *, mlir::Value>;431 432 /// Hold counters for incrementally naming temporaries433 unsigned counterRefTmp = 0;434 unsigned counterAggTmp = 0;435 std::string getCounterRefTmpAsString();436 std::string getCounterAggTmpAsString();437 438 /// Helpers to convert Clang's SourceLocation to a MLIR Location.439 mlir::Location getLoc(clang::SourceLocation srcLoc);440 mlir::Location getLoc(clang::SourceRange srcLoc);441 mlir::Location getLoc(mlir::Location lhs, mlir::Location rhs);442 443 const clang::LangOptions &getLangOpts() const { return cgm.getLangOpts(); }444 445 /// True if an insertion point is defined. If not, this indicates that the446 /// current code being emitted is unreachable.447 /// FIXME(cir): we need to inspect this and perhaps use a cleaner mechanism448 /// since we don't yet force null insertion point to designate behavior (like449 /// LLVM's codegen does) and we probably shouldn't.450 bool haveInsertPoint() const {451 return builder.getInsertionBlock() != nullptr;452 }453 454 // Wrapper for function prototype sources. Wraps either a FunctionProtoType or455 // an ObjCMethodDecl.456 struct PrototypeWrapper {457 llvm::PointerUnion<const clang::FunctionProtoType *,458 const clang::ObjCMethodDecl *>459 p;460 461 PrototypeWrapper(const clang::FunctionProtoType *ft) : p(ft) {}462 PrototypeWrapper(const clang::ObjCMethodDecl *md) : p(md) {}463 };464 465 bool isLValueSuitableForInlineAtomic(LValue lv);466 467 /// An abstract representation of regular/ObjC call/message targets.468 class AbstractCallee {469 /// The function declaration of the callee.470 [[maybe_unused]] const clang::Decl *calleeDecl;471 472 public:473 AbstractCallee() : calleeDecl(nullptr) {}474 AbstractCallee(const clang::FunctionDecl *fd) : calleeDecl(fd) {}475 476 bool hasFunctionDecl() const {477 return llvm::isa_and_nonnull<clang::FunctionDecl>(calleeDecl);478 }479 480 unsigned getNumParams() const {481 if (const auto *fd = llvm::dyn_cast<clang::FunctionDecl>(calleeDecl))482 return fd->getNumParams();483 return llvm::cast<clang::ObjCMethodDecl>(calleeDecl)->param_size();484 }485 486 const clang::ParmVarDecl *getParamDecl(unsigned I) const {487 if (const auto *fd = llvm::dyn_cast<clang::FunctionDecl>(calleeDecl))488 return fd->getParamDecl(I);489 return *(llvm::cast<clang::ObjCMethodDecl>(calleeDecl)->param_begin() +490 I);491 }492 };493 494 struct VlaSizePair {495 mlir::Value numElts;496 QualType type;497 498 VlaSizePair(mlir::Value num, QualType ty) : numElts(num), type(ty) {}499 };500 501 /// Return the number of elements for a single dimension502 /// for the given array type.503 VlaSizePair getVLAElements1D(const VariableArrayType *vla);504 505 /// Returns an MLIR::Value+QualType pair that corresponds to the size,506 /// in non-variably-sized elements, of a variable length array type,507 /// plus that largest non-variably-sized element type. Assumes that508 /// the type has already been emitted with emitVariablyModifiedType.509 VlaSizePair getVLASize(const VariableArrayType *type);510 VlaSizePair getVLASize(QualType type);511 512 Address getAsNaturalAddressOf(Address addr, QualType pointeeTy);513 514 mlir::Value getAsNaturalPointerTo(Address addr, QualType pointeeType) {515 return getAsNaturalAddressOf(addr, pointeeType).getBasePointer();516 }517 518 void finishFunction(SourceLocation endLoc);519 520 /// Determine whether the given initializer is trivial in the sense521 /// that it requires no code to be generated.522 bool isTrivialInitializer(const Expr *init);523 524 /// If the specified expression does not fold to a constant, or if it does but525 /// contains a label, return false. If it constant folds return true and set526 /// the boolean result in Result.527 bool constantFoldsToBool(const clang::Expr *cond, bool &resultBool,528 bool allowLabels = false);529 bool constantFoldsToSimpleInteger(const clang::Expr *cond,530 llvm::APSInt &resultInt,531 bool allowLabels = false);532 533 /// Return true if the statement contains a label in it. If534 /// this statement is not executed normally, it not containing a label means535 /// that we can just remove the code.536 bool containsLabel(const clang::Stmt *s, bool ignoreCaseStmts = false);537 538 Address emitExtVectorElementLValue(LValue lv, mlir::Location loc);539 540 class ConstantEmission {541 // Cannot use mlir::TypedAttr directly here because of bit availability.542 llvm::PointerIntPair<mlir::Attribute, 1, bool> valueAndIsReference;543 ConstantEmission(mlir::TypedAttr c, bool isReference)544 : valueAndIsReference(c, isReference) {}545 546 public:547 ConstantEmission() {}548 static ConstantEmission forReference(mlir::TypedAttr c) {549 return ConstantEmission(c, true);550 }551 static ConstantEmission forValue(mlir::TypedAttr c) {552 return ConstantEmission(c, false);553 }554 555 explicit operator bool() const {556 return valueAndIsReference.getOpaqueValue() != nullptr;557 }558 559 bool isReference() const { return valueAndIsReference.getInt(); }560 LValue getReferenceLValue(CIRGenFunction &cgf, Expr *refExpr) const {561 assert(isReference());562 cgf.cgm.errorNYI(refExpr->getSourceRange(),563 "ConstantEmission::getReferenceLValue");564 return {};565 }566 567 mlir::TypedAttr getValue() const {568 assert(!isReference());569 return mlir::cast<mlir::TypedAttr>(valueAndIsReference.getPointer());570 }571 };572 573 ConstantEmission tryEmitAsConstant(const DeclRefExpr *refExpr);574 ConstantEmission tryEmitAsConstant(const MemberExpr *me);575 576 struct AutoVarEmission {577 const clang::VarDecl *variable;578 /// The address of the alloca for languages with explicit address space579 /// (e.g. OpenCL) or alloca casted to generic pointer for address space580 /// agnostic languages (e.g. C++). Invalid if the variable was emitted581 /// as a global constant.582 Address addr;583 584 /// True if the variable is of aggregate type and has a constant585 /// initializer.586 bool isConstantAggregate = false;587 588 /// True if the variable is a __block variable that is captured by an589 /// escaping block.590 bool isEscapingByRef = false;591 592 /// True if the variable was emitted as an offload recipe, and thus doesn't593 /// have the same sort of alloca initialization.594 bool emittedAsOffload = false;595 596 mlir::Value nrvoFlag{};597 598 struct Invalid {};599 AutoVarEmission(Invalid) : variable(nullptr), addr(Address::invalid()) {}600 601 AutoVarEmission(const clang::VarDecl &variable)602 : variable(&variable), addr(Address::invalid()) {}603 604 static AutoVarEmission invalid() { return AutoVarEmission(Invalid()); }605 606 bool wasEmittedAsGlobal() const { return !addr.isValid(); }607 608 bool wasEmittedAsOffloadClause() const { return emittedAsOffload; }609 610 /// Returns the raw, allocated address, which is not necessarily611 /// the address of the object itself. It is casted to default612 /// address space for address space agnostic languages.613 Address getAllocatedAddress() const { return addr; }614 615 // Changes the stored address for the emission. This function should only616 // be used in extreme cases, and isn't required to model normal AST617 // initialization/variables.618 void setAllocatedAddress(Address a) { addr = a; }619 620 /// Returns the address of the object within this declaration.621 /// Note that this does not chase the forwarding pointer for622 /// __block decls.623 Address getObjectAddress(CIRGenFunction &cgf) const {624 if (!isEscapingByRef)625 return addr;626 627 assert(!cir::MissingFeatures::opAllocaEscapeByReference());628 return Address::invalid();629 }630 };631 632 /// The given basic block lies in the current EH scope, but may be a633 /// target of a potentially scope-crossing jump; get a stable handle634 /// to which we can perform this jump later.635 /// CIRGen: this mostly tracks state for figuring out the proper scope636 /// information, no actual branches are emitted.637 JumpDest getJumpDestInCurrentScope(mlir::Block *target) {638 return JumpDest(target, ehStack.getInnermostNormalCleanup(),639 nextCleanupDestIndex++);640 }641 642 /// Perform the usual unary conversions on the specified expression and643 /// compare the result against zero, returning an Int1Ty value.644 mlir::Value evaluateExprAsBool(const clang::Expr *e);645 646 cir::GlobalOp addInitializerToStaticVarDecl(const VarDecl &d,647 cir::GlobalOp gv,648 cir::GetGlobalOp gvAddr);649 650 /// Enter the cleanups necessary to complete the given phase of destruction651 /// for a destructor. The end result should call destructors on members and652 /// base classes in reverse order of their construction.653 void enterDtorCleanups(const CXXDestructorDecl *dtor, CXXDtorType type);654 655 /// Determines whether an EH cleanup is required to destroy a type656 /// with the given destruction kind.657 /// TODO(cir): could be shared with Clang LLVM codegen658 bool needsEHCleanup(QualType::DestructionKind kind) {659 switch (kind) {660 case QualType::DK_none:661 return false;662 case QualType::DK_cxx_destructor:663 case QualType::DK_objc_weak_lifetime:664 case QualType::DK_nontrivial_c_struct:665 return getLangOpts().Exceptions;666 case QualType::DK_objc_strong_lifetime:667 return getLangOpts().Exceptions &&668 cgm.getCodeGenOpts().ObjCAutoRefCountExceptions;669 }670 llvm_unreachable("bad destruction kind");671 }672 673 CleanupKind getCleanupKind(QualType::DestructionKind kind) {674 return needsEHCleanup(kind) ? NormalAndEHCleanup : NormalCleanup;675 }676 677 void pushStackRestore(CleanupKind kind, Address spMem);678 679 /// Set the address of a local variable.680 void setAddrOfLocalVar(const clang::VarDecl *vd, Address addr) {681 assert(!localDeclMap.count(vd) && "Decl already exists in LocalDeclMap!");682 localDeclMap.insert({vd, addr});683 684 // Add to the symbol table if not there already.685 if (symbolTable.count(vd))686 return;687 symbolTable.insert(vd, addr.getPointer());688 }689 690 // Replaces the address of the local variable, if it exists. Else does the691 // same thing as setAddrOfLocalVar.692 void replaceAddrOfLocalVar(const clang::VarDecl *vd, Address addr) {693 localDeclMap.insert_or_assign(vd, addr);694 }695 696 // A class to allow reverting changes to a var-decl's registration to the697 // localDeclMap. This is used in cases where things are being inserted into698 // the variable list but don't follow normal lookup/search rules, like in699 // OpenACC recipe generation.700 class DeclMapRevertingRAII {701 CIRGenFunction &cgf;702 const VarDecl *vd;703 bool shouldDelete = false;704 Address oldAddr = Address::invalid();705 706 public:707 DeclMapRevertingRAII(CIRGenFunction &cgf, const VarDecl *vd)708 : cgf(cgf), vd(vd) {709 auto mapItr = cgf.localDeclMap.find(vd);710 711 if (mapItr != cgf.localDeclMap.end())712 oldAddr = mapItr->second;713 else714 shouldDelete = true;715 }716 717 ~DeclMapRevertingRAII() {718 if (shouldDelete)719 cgf.localDeclMap.erase(vd);720 else721 cgf.localDeclMap.insert_or_assign(vd, oldAddr);722 }723 };724 725 bool shouldNullCheckClassCastValue(const CastExpr *ce);726 727 RValue convertTempToRValue(Address addr, clang::QualType type,728 clang::SourceLocation loc);729 730 static bool731 isConstructorDelegationValid(const clang::CXXConstructorDecl *ctor);732 733 struct VPtr {734 clang::BaseSubobject base;735 const clang::CXXRecordDecl *nearestVBase;736 clang::CharUnits offsetFromNearestVBase;737 const clang::CXXRecordDecl *vtableClass;738 };739 740 using VisitedVirtualBasesSetTy =741 llvm::SmallPtrSet<const clang::CXXRecordDecl *, 4>;742 743 using VPtrsVector = llvm::SmallVector<VPtr, 4>;744 VPtrsVector getVTablePointers(const clang::CXXRecordDecl *vtableClass);745 void getVTablePointers(clang::BaseSubobject base,746 const clang::CXXRecordDecl *nearestVBase,747 clang::CharUnits offsetFromNearestVBase,748 bool baseIsNonVirtualPrimaryBase,749 const clang::CXXRecordDecl *vtableClass,750 VisitedVirtualBasesSetTy &vbases, VPtrsVector &vptrs);751 /// Return the Value of the vtable pointer member pointed to by thisAddr.752 mlir::Value getVTablePtr(mlir::Location loc, Address thisAddr,753 const clang::CXXRecordDecl *vtableClass);754 755 /// Returns whether we should perform a type checked load when loading a756 /// virtual function for virtual calls to members of RD. This is generally757 /// true when both vcall CFI and whole-program-vtables are enabled.758 bool shouldEmitVTableTypeCheckedLoad(const CXXRecordDecl *rd);759 760 /// Source location information about the default argument or member761 /// initializer expression we're evaluating, if any.762 clang::CurrentSourceLocExprScope curSourceLocExprScope;763 using SourceLocExprScopeGuard =764 clang::CurrentSourceLocExprScope::SourceLocExprScopeGuard;765 766 /// A scope within which we are constructing the fields of an object which767 /// might use a CXXDefaultInitExpr. This stashes away a 'this' value to use if768 /// we need to evaluate the CXXDefaultInitExpr within the evaluation.769 class FieldConstructionScope {770 public:771 FieldConstructionScope(CIRGenFunction &cgf, Address thisAddr)772 : cgf(cgf), oldCXXDefaultInitExprThis(cgf.cxxDefaultInitExprThis) {773 cgf.cxxDefaultInitExprThis = thisAddr;774 }775 ~FieldConstructionScope() {776 cgf.cxxDefaultInitExprThis = oldCXXDefaultInitExprThis;777 }778 779 private:780 CIRGenFunction &cgf;781 Address oldCXXDefaultInitExprThis;782 };783 784 /// The scope of a CXXDefaultInitExpr. Within this scope, the value of 'this'785 /// is overridden to be the object under construction.786 class CXXDefaultInitExprScope {787 public:788 CXXDefaultInitExprScope(CIRGenFunction &cgf, const CXXDefaultInitExpr *e)789 : cgf{cgf}, oldCXXThisValue(cgf.cxxThisValue),790 oldCXXThisAlignment(cgf.cxxThisAlignment),791 sourceLocScope(e, cgf.curSourceLocExprScope) {792 cgf.cxxThisValue = cgf.cxxDefaultInitExprThis.getPointer();793 cgf.cxxThisAlignment = cgf.cxxDefaultInitExprThis.getAlignment();794 }795 ~CXXDefaultInitExprScope() {796 cgf.cxxThisValue = oldCXXThisValue;797 cgf.cxxThisAlignment = oldCXXThisAlignment;798 }799 800 public:801 CIRGenFunction &cgf;802 mlir::Value oldCXXThisValue;803 clang::CharUnits oldCXXThisAlignment;804 SourceLocExprScopeGuard sourceLocScope;805 };806 807 struct CXXDefaultArgExprScope : SourceLocExprScopeGuard {808 CXXDefaultArgExprScope(CIRGenFunction &cfg, const CXXDefaultArgExpr *e)809 : SourceLocExprScopeGuard(e, cfg.curSourceLocExprScope) {}810 };811 812 LValue makeNaturalAlignPointeeAddrLValue(mlir::Value v, clang::QualType t);813 LValue makeNaturalAlignAddrLValue(mlir::Value val, QualType ty);814 815 /// Construct an address with the natural alignment of T. If a pointer to T816 /// is expected to be signed, the pointer passed to this function must have817 /// been signed, and the returned Address will have the pointer authentication818 /// information needed to authenticate the signed pointer.819 Address makeNaturalAddressForPointer(mlir::Value ptr, QualType t,820 CharUnits alignment,821 bool forPointeeType = false,822 LValueBaseInfo *baseInfo = nullptr) {823 if (alignment.isZero())824 alignment = cgm.getNaturalTypeAlignment(t, baseInfo);825 return Address(ptr, convertTypeForMem(t), alignment);826 }827 828 Address getAddressOfBaseClass(829 Address value, const CXXRecordDecl *derived,830 llvm::iterator_range<CastExpr::path_const_iterator> path,831 bool nullCheckValue, SourceLocation loc);832 833 Address getAddressOfDerivedClass(834 mlir::Location loc, Address baseAddr, const CXXRecordDecl *derived,835 llvm::iterator_range<CastExpr::path_const_iterator> path,836 bool nullCheckValue);837 838 /// Return the VTT parameter that should be passed to a base839 /// constructor/destructor with virtual bases.840 /// FIXME: VTTs are Itanium ABI-specific, so the definition should move841 /// to ItaniumCXXABI.cpp together with all the references to VTT.842 mlir::Value getVTTParameter(GlobalDecl gd, bool forVirtualBase,843 bool delegating);844 845 LValue makeAddrLValue(Address addr, QualType ty,846 AlignmentSource source = AlignmentSource::Type) {847 return makeAddrLValue(addr, ty, LValueBaseInfo(source));848 }849 850 LValue makeAddrLValue(Address addr, QualType ty, LValueBaseInfo baseInfo) {851 return LValue::makeAddr(addr, ty, baseInfo);852 }853 854 void initializeVTablePointers(mlir::Location loc,855 const clang::CXXRecordDecl *rd);856 void initializeVTablePointer(mlir::Location loc, const VPtr &vptr);857 858 AggValueSlot::Overlap_t getOverlapForFieldInit(const FieldDecl *fd);859 860 /// Return the address of a local variable.861 Address getAddrOfLocalVar(const clang::VarDecl *vd) {862 auto it = localDeclMap.find(vd);863 assert(it != localDeclMap.end() &&864 "Invalid argument to getAddrOfLocalVar(), no decl!");865 return it->second;866 }867 868 Address getAddrOfBitFieldStorage(LValue base, const clang::FieldDecl *field,869 mlir::Type fieldType, unsigned index);870 871 /// Given an opaque value expression, return its LValue mapping if it exists,872 /// otherwise create one.873 LValue getOrCreateOpaqueLValueMapping(const OpaqueValueExpr *e);874 875 /// Given an opaque value expression, return its RValue mapping if it exists,876 /// otherwise create one.877 RValue getOrCreateOpaqueRValueMapping(const OpaqueValueExpr *e);878 879 /// Load the value for 'this'. This function is only valid while generating880 /// code for an C++ member function.881 /// FIXME(cir): this should return a mlir::Value!882 mlir::Value loadCXXThis() {883 assert(cxxThisValue && "no 'this' value for this function");884 return cxxThisValue;885 }886 Address loadCXXThisAddress();887 888 /// Load the VTT parameter to base constructors/destructors have virtual889 /// bases. FIXME: Every place that calls LoadCXXVTT is something that needs to890 /// be abstracted properly.891 mlir::Value loadCXXVTT() {892 assert(cxxStructorImplicitParamValue && "no VTT value for this function");893 return cxxStructorImplicitParamValue;894 }895 896 /// Convert the given pointer to a complete class to the given direct base.897 Address getAddressOfDirectBaseInCompleteClass(mlir::Location loc,898 Address value,899 const CXXRecordDecl *derived,900 const CXXRecordDecl *base,901 bool baseIsVirtual);902 903 /// Determine whether a return value slot may overlap some other object.904 AggValueSlot::Overlap_t getOverlapForReturnValue() {905 // FIXME: Assuming no overlap here breaks guaranteed copy elision for base906 // class subobjects. These cases may need to be revisited depending on the907 // resolution of the relevant core issue.908 return AggValueSlot::DoesNotOverlap;909 }910 911 /// Determine whether a base class initialization may overlap some other912 /// object.913 AggValueSlot::Overlap_t getOverlapForBaseInit(const CXXRecordDecl *rd,914 const CXXRecordDecl *baseRD,915 bool isVirtual);916 917 /// Get an appropriate 'undef' rvalue for the given type.918 /// TODO: What's the equivalent for MLIR? Currently we're only using this for919 /// void types so it just returns RValue::get(nullptr) but it'll need920 /// addressed later.921 RValue getUndefRValue(clang::QualType ty);922 923 cir::FuncOp generateCode(clang::GlobalDecl gd, cir::FuncOp fn,924 cir::FuncType funcType);925 926 clang::QualType buildFunctionArgList(clang::GlobalDecl gd,927 FunctionArgList &args);928 929 /// Emit code for the start of a function.930 /// \param loc The location to be associated with the function.931 /// \param startLoc The location of the function body.932 void startFunction(clang::GlobalDecl gd, clang::QualType returnType,933 cir::FuncOp fn, cir::FuncType funcType,934 FunctionArgList args, clang::SourceLocation loc,935 clang::SourceLocation startLoc);936 937 /// returns true if aggregate type has a volatile member.938 bool hasVolatileMember(QualType t) {939 if (const auto *rd = t->getAsRecordDecl())940 return rd->hasVolatileMember();941 return false;942 }943 944 void populateEHCatchRegions(EHScopeStack::stable_iterator scope,945 cir::TryOp tryOp);946 947 /// The cleanup depth enclosing all the cleanups associated with the948 /// parameters.949 EHScopeStack::stable_iterator prologueCleanupDepth;950 951 bool isCatchOrCleanupRequired();952 void populateCatchHandlersIfRequired(cir::TryOp tryOp);953 954 /// Takes the old cleanup stack size and emits the cleanup blocks955 /// that have been added.956 void popCleanupBlocks(EHScopeStack::stable_iterator oldCleanupStackDepth);957 void popCleanupBlock();958 959 /// Push a cleanup to be run at the end of the current full-expression. Safe960 /// against the possibility that we're currently inside a961 /// conditionally-evaluated expression.962 template <class T, class... As>963 void pushFullExprCleanup(CleanupKind kind, As... a) {964 // If we're not in a conditional branch, or if none of the965 // arguments requires saving, then use the unconditional cleanup.966 if (!isInConditionalBranch())967 return ehStack.pushCleanup<T>(kind, a...);968 969 cgm.errorNYI("pushFullExprCleanup in conditional branch");970 }971 972 /// Enters a new scope for capturing cleanups, all of which973 /// will be executed once the scope is exited.974 class RunCleanupsScope {975 EHScopeStack::stable_iterator cleanupStackDepth, oldCleanupStackDepth;976 977 protected:978 bool performCleanup;979 bool oldDidCallStackSave;980 981 private:982 RunCleanupsScope(const RunCleanupsScope &) = delete;983 void operator=(const RunCleanupsScope &) = delete;984 985 protected:986 CIRGenFunction &cgf;987 988 public:989 /// Enter a new cleanup scope.990 explicit RunCleanupsScope(CIRGenFunction &cgf)991 : performCleanup(true), cgf(cgf) {992 cleanupStackDepth = cgf.ehStack.stable_begin();993 oldDidCallStackSave = cgf.didCallStackSave;994 cgf.didCallStackSave = false;995 oldCleanupStackDepth = cgf.currentCleanupStackDepth;996 cgf.currentCleanupStackDepth = cleanupStackDepth;997 }998 999 /// Exit this cleanup scope, emitting any accumulated cleanups.1000 ~RunCleanupsScope() {1001 if (performCleanup)1002 forceCleanup();1003 }1004 1005 /// Force the emission of cleanups now, instead of waiting1006 /// until this object is destroyed.1007 void forceCleanup() {1008 assert(performCleanup && "Already forced cleanup");1009 {1010 mlir::OpBuilder::InsertionGuard guard(cgf.getBuilder());1011 cgf.didCallStackSave = oldDidCallStackSave;1012 cgf.popCleanupBlocks(cleanupStackDepth);1013 performCleanup = false;1014 cgf.currentCleanupStackDepth = oldCleanupStackDepth;1015 }1016 }1017 };1018 1019 // Cleanup stack depth of the RunCleanupsScope that was pushed most recently.1020 EHScopeStack::stable_iterator currentCleanupStackDepth = ehStack.stable_end();1021 1022public:1023 /// Represents a scope, including function bodies, compound statements, and1024 /// the substatements of if/while/do/for/switch/try statements. This class1025 /// handles any automatic cleanup, along with the return value.1026 struct LexicalScope : public RunCleanupsScope {1027 private:1028 // Block containing cleanup code for things initialized in this1029 // lexical context (scope).1030 mlir::Block *cleanupBlock = nullptr;1031 1032 // Points to the scope entry block. This is useful, for instance, for1033 // helping to insert allocas before finalizing any recursive CodeGen from1034 // switches.1035 mlir::Block *entryBlock;1036 1037 LexicalScope *parentScope = nullptr;1038 1039 // Holds the actual value for ScopeKind::Try1040 cir::TryOp tryOp = nullptr;1041 1042 // Only Regular is used at the moment. Support for other kinds will be1043 // added as the relevant statements/expressions are upstreamed.1044 enum Kind {1045 Regular, // cir.if, cir.scope, if_regions1046 Ternary, // cir.ternary1047 Switch, // cir.switch1048 Try, // cir.try1049 GlobalInit // cir.global initialization code1050 };1051 Kind scopeKind = Kind::Regular;1052 1053 // The scope return value.1054 mlir::Value retVal = nullptr;1055 1056 mlir::Location beginLoc;1057 mlir::Location endLoc;1058 1059 public:1060 unsigned depth = 0;1061 1062 LexicalScope(CIRGenFunction &cgf, mlir::Location loc, mlir::Block *eb)1063 : RunCleanupsScope(cgf), entryBlock(eb), parentScope(cgf.curLexScope),1064 beginLoc(loc), endLoc(loc) {1065 1066 assert(entryBlock && "LexicalScope requires an entry block");1067 cgf.curLexScope = this;1068 if (parentScope)1069 ++depth;1070 1071 if (const auto fusedLoc = mlir::dyn_cast<mlir::FusedLoc>(loc)) {1072 assert(fusedLoc.getLocations().size() == 2 && "too many locations");1073 beginLoc = fusedLoc.getLocations()[0];1074 endLoc = fusedLoc.getLocations()[1];1075 }1076 }1077 1078 void setRetVal(mlir::Value v) { retVal = v; }1079 1080 void cleanup();1081 void restore() { cgf.curLexScope = parentScope; }1082 1083 ~LexicalScope() {1084 assert(!cir::MissingFeatures::generateDebugInfo());1085 cleanup();1086 restore();1087 }1088 1089 // ---1090 // Kind1091 // ---1092 bool isGlobalInit() { return scopeKind == Kind::GlobalInit; }1093 bool isRegular() { return scopeKind == Kind::Regular; }1094 bool isSwitch() { return scopeKind == Kind::Switch; }1095 bool isTernary() { return scopeKind == Kind::Ternary; }1096 bool isTry() { return scopeKind == Kind::Try; }1097 cir::TryOp getClosestTryParent();1098 void setAsGlobalInit() { scopeKind = Kind::GlobalInit; }1099 void setAsSwitch() { scopeKind = Kind::Switch; }1100 void setAsTernary() { scopeKind = Kind::Ternary; }1101 void setAsTry(cir::TryOp op) {1102 scopeKind = Kind::Try;1103 tryOp = op;1104 }1105 1106 // Lazy create cleanup block or return what's available.1107 mlir::Block *getOrCreateCleanupBlock(mlir::OpBuilder &builder) {1108 if (cleanupBlock)1109 return cleanupBlock;1110 cleanupBlock = createCleanupBlock(builder);1111 return cleanupBlock;1112 }1113 1114 cir::TryOp getTry() {1115 assert(isTry());1116 return tryOp;1117 }1118 1119 mlir::Block *getCleanupBlock(mlir::OpBuilder &builder) {1120 return cleanupBlock;1121 }1122 1123 mlir::Block *createCleanupBlock(mlir::OpBuilder &builder) {1124 // Create the cleanup block but dont hook it up around just yet.1125 mlir::OpBuilder::InsertionGuard guard(builder);1126 mlir::Region *r = builder.getBlock() ? builder.getBlock()->getParent()1127 : &cgf.curFn->getRegion(0);1128 cleanupBlock = builder.createBlock(r);1129 return cleanupBlock;1130 }1131 1132 // ---1133 // Return handling.1134 // ---1135 1136 private:1137 // On switches we need one return block per region, since cases don't1138 // have their own scopes but are distinct regions nonetheless.1139 1140 // TODO: This implementation should change once we have support for early1141 // exits in MLIR structured control flow (llvm-project#161575)1142 llvm::SmallVector<mlir::Block *> retBlocks;1143 llvm::DenseMap<mlir::Block *, mlir::Location> retLocs;1144 llvm::DenseMap<cir::CaseOp, unsigned> retBlockInCaseIndex;1145 std::optional<unsigned> normalRetBlockIndex;1146 1147 // There's usually only one ret block per scope, but this needs to be1148 // get or create because of potential unreachable return statements, note1149 // that for those, all source location maps to the first one found.1150 mlir::Block *createRetBlock(CIRGenFunction &cgf, mlir::Location loc) {1151 assert((isa_and_nonnull<cir::CaseOp>(1152 cgf.builder.getBlock()->getParentOp()) ||1153 retBlocks.size() == 0) &&1154 "only switches can hold more than one ret block");1155 1156 // Create the return block but don't hook it up just yet.1157 mlir::OpBuilder::InsertionGuard guard(cgf.builder);1158 auto *b = cgf.builder.createBlock(cgf.builder.getBlock()->getParent());1159 retBlocks.push_back(b);1160 updateRetLoc(b, loc);1161 return b;1162 }1163 1164 cir::ReturnOp emitReturn(mlir::Location loc);1165 void emitImplicitReturn();1166 1167 public:1168 llvm::ArrayRef<mlir::Block *> getRetBlocks() { return retBlocks; }1169 mlir::Location getRetLoc(mlir::Block *b) { return retLocs.at(b); }1170 void updateRetLoc(mlir::Block *b, mlir::Location loc) {1171 retLocs.insert_or_assign(b, loc);1172 }1173 1174 mlir::Block *getOrCreateRetBlock(CIRGenFunction &cgf, mlir::Location loc) {1175 // Check if we're inside a case region1176 if (auto caseOp = mlir::dyn_cast_if_present<cir::CaseOp>(1177 cgf.builder.getBlock()->getParentOp())) {1178 auto iter = retBlockInCaseIndex.find(caseOp);1179 if (iter != retBlockInCaseIndex.end()) {1180 // Reuse existing return block1181 mlir::Block *ret = retBlocks[iter->second];1182 updateRetLoc(ret, loc);1183 return ret;1184 }1185 // Create new return block1186 mlir::Block *ret = createRetBlock(cgf, loc);1187 retBlockInCaseIndex[caseOp] = retBlocks.size() - 1;1188 return ret;1189 }1190 1191 if (normalRetBlockIndex) {1192 mlir::Block *ret = retBlocks[*normalRetBlockIndex];1193 updateRetLoc(ret, loc);1194 return ret;1195 }1196 1197 mlir::Block *ret = createRetBlock(cgf, loc);1198 normalRetBlockIndex = retBlocks.size() - 1;1199 return ret;1200 }1201 1202 mlir::Block *getEntryBlock() { return entryBlock; }1203 };1204 1205 LexicalScope *curLexScope = nullptr;1206 1207 typedef void Destroyer(CIRGenFunction &cgf, Address addr, QualType ty);1208 1209 static Destroyer destroyCXXObject;1210 1211 void pushDestroy(QualType::DestructionKind dtorKind, Address addr,1212 QualType type);1213 1214 void pushDestroy(CleanupKind kind, Address addr, QualType type,1215 Destroyer *destroyer);1216 1217 Destroyer *getDestroyer(clang::QualType::DestructionKind kind);1218 1219 /// ----------------------1220 /// CIR emit functions1221 /// ----------------------1222public:1223 mlir::Value emitAlignmentAssumption(mlir::Value ptrValue, QualType ty,1224 SourceLocation loc,1225 SourceLocation assumptionLoc,1226 int64_t alignment,1227 mlir::Value offsetValue = nullptr);1228 1229 mlir::Value emitAlignmentAssumption(mlir::Value ptrValue, const Expr *expr,1230 SourceLocation assumptionLoc,1231 int64_t alignment,1232 mlir::Value offsetValue = nullptr);1233 1234private:1235 void emitAndUpdateRetAlloca(clang::QualType type, mlir::Location loc,1236 clang::CharUnits alignment);1237 1238 CIRGenCallee emitDirectCallee(const GlobalDecl &gd);1239 1240public:1241 Address emitAddrOfFieldStorage(Address base, const FieldDecl *field,1242 llvm::StringRef fieldName,1243 unsigned fieldIndex);1244 1245 mlir::Value emitAlloca(llvm::StringRef name, mlir::Type ty,1246 mlir::Location loc, clang::CharUnits alignment,1247 bool insertIntoFnEntryBlock,1248 mlir::Value arraySize = nullptr);1249 mlir::Value emitAlloca(llvm::StringRef name, mlir::Type ty,1250 mlir::Location loc, clang::CharUnits alignment,1251 mlir::OpBuilder::InsertPoint ip,1252 mlir::Value arraySize = nullptr);1253 1254 void emitAggregateStore(mlir::Value value, Address dest);1255 1256 void emitAggExpr(const clang::Expr *e, AggValueSlot slot);1257 1258 LValue emitAggExprToLValue(const Expr *e);1259 1260 /// Emit an aggregate copy.1261 ///1262 /// \param isVolatile \c true iff either the source or the destination is1263 /// volatile.1264 /// \param MayOverlap Whether the tail padding of the destination might be1265 /// occupied by some other object. More efficient code can often be1266 /// generated if not.1267 void emitAggregateCopy(LValue dest, LValue src, QualType eltTy,1268 AggValueSlot::Overlap_t mayOverlap,1269 bool isVolatile = false);1270 1271 /// Emit code to compute the specified expression which can have any type. The1272 /// result is returned as an RValue struct. If this is an aggregate1273 /// expression, the aggloc/agglocvolatile arguments indicate where the result1274 /// should be returned.1275 RValue emitAnyExpr(const clang::Expr *e,1276 AggValueSlot aggSlot = AggValueSlot::ignored(),1277 bool ignoreResult = false);1278 1279 /// Emits the code necessary to evaluate an arbitrary expression into the1280 /// given memory location.1281 void emitAnyExprToMem(const Expr *e, Address location, Qualifiers quals,1282 bool isInitializer);1283 1284 /// Similarly to emitAnyExpr(), however, the result will always be accessible1285 /// even if no aggregate location is provided.1286 RValue emitAnyExprToTemp(const clang::Expr *e);1287 1288 void emitAnyExprToExn(const Expr *e, Address addr);1289 1290 void emitArrayDestroy(mlir::Value begin, mlir::Value numElements,1291 QualType elementType, CharUnits elementAlign,1292 Destroyer *destroyer);1293 1294 mlir::Value emitArrayLength(const clang::ArrayType *arrayType,1295 QualType &baseType, Address &addr);1296 LValue emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e);1297 1298 LValue emitExtVectorElementExpr(const ExtVectorElementExpr *e);1299 1300 Address emitArrayToPointerDecay(const Expr *e,1301 LValueBaseInfo *baseInfo = nullptr);1302 1303 mlir::LogicalResult emitAsmStmt(const clang::AsmStmt &s);1304 1305 RValue emitAtomicExpr(AtomicExpr *e);1306 void emitAtomicInit(Expr *init, LValue dest);1307 void emitAtomicStore(RValue rvalue, LValue dest, bool isInit);1308 void emitAtomicStore(RValue rvalue, LValue dest, cir::MemOrder order,1309 bool isVolatile, bool isInit);1310 1311 AutoVarEmission emitAutoVarAlloca(const clang::VarDecl &d,1312 mlir::OpBuilder::InsertPoint ip = {});1313 1314 /// Emit code and set up symbol table for a variable declaration with auto,1315 /// register, or no storage class specifier. These turn into simple stack1316 /// objects, globals depending on target.1317 void emitAutoVarDecl(const clang::VarDecl &d);1318 1319 void emitAutoVarCleanups(const AutoVarEmission &emission);1320 /// Emit the initializer for an allocated variable. If this call is not1321 /// associated with the call to emitAutoVarAlloca (as the address of the1322 /// emission is not directly an alloca), the allocatedSeparately parameter can1323 /// be used to suppress the assertions. However, this should only be used in1324 /// extreme cases, as it doesn't properly reflect the language/AST.1325 void emitAutoVarInit(const AutoVarEmission &emission);1326 void emitAutoVarTypeCleanup(const AutoVarEmission &emission,1327 clang::QualType::DestructionKind dtorKind);1328 1329 void maybeEmitDeferredVarDeclInit(const VarDecl *vd);1330 1331 void emitBaseInitializer(mlir::Location loc, const CXXRecordDecl *classDecl,1332 CXXCtorInitializer *baseInit);1333 1334 LValue emitBinaryOperatorLValue(const BinaryOperator *e);1335 1336 cir::BrOp emitBranchThroughCleanup(mlir::Location loc, JumpDest dest);1337 1338 mlir::LogicalResult emitBreakStmt(const clang::BreakStmt &s);1339 1340 RValue emitBuiltinExpr(const clang::GlobalDecl &gd, unsigned builtinID,1341 const clang::CallExpr *e, ReturnValueSlot returnValue);1342 1343 /// Returns a Value corresponding to the size of the given expression by1344 /// emitting a `cir.objsize` operation.1345 ///1346 /// \param e The expression whose object size to compute1347 /// \param type Determines the semantics of the object size computation.1348 /// The type parameter is a 2-bit value where:1349 /// bit 0 (type & 1): 0 = whole object, 1 = closest subobject1350 /// bit 1 (type & 2): 0 = maximum size, 2 = minimum size1351 /// \param resType The result type for the size value1352 /// \param emittedE Optional pre-emitted pointer value. If non-null, we'll1353 /// call `cir.objsize` on this value rather than emitting e.1354 /// \param isDynamic If true, allows runtime evaluation via dynamic mode1355 mlir::Value emitBuiltinObjectSize(const clang::Expr *e, unsigned type,1356 cir::IntType resType, mlir::Value emittedE,1357 bool isDynamic);1358 1359 mlir::Value evaluateOrEmitBuiltinObjectSize(const clang::Expr *e,1360 unsigned type,1361 cir::IntType resType,1362 mlir::Value emittedE,1363 bool isDynamic);1364 1365 int64_t getAccessedFieldNo(unsigned idx, mlir::ArrayAttr elts);1366 1367 RValue emitCall(const CIRGenFunctionInfo &funcInfo,1368 const CIRGenCallee &callee, ReturnValueSlot returnValue,1369 const CallArgList &args, cir::CIRCallOpInterface *callOp,1370 mlir::Location loc);1371 RValue emitCall(const CIRGenFunctionInfo &funcInfo,1372 const CIRGenCallee &callee, ReturnValueSlot returnValue,1373 const CallArgList &args,1374 cir::CIRCallOpInterface *callOrTryCall = nullptr) {1375 assert(currSrcLoc && "source location must have been set");1376 return emitCall(funcInfo, callee, returnValue, args, callOrTryCall,1377 *currSrcLoc);1378 }1379 1380 RValue emitCall(clang::QualType calleeTy, const CIRGenCallee &callee,1381 const clang::CallExpr *e, ReturnValueSlot returnValue);1382 void emitCallArg(CallArgList &args, const clang::Expr *e,1383 clang::QualType argType);1384 void emitCallArgs(1385 CallArgList &args, PrototypeWrapper prototype,1386 llvm::iterator_range<clang::CallExpr::const_arg_iterator> argRange,1387 AbstractCallee callee = AbstractCallee(), unsigned paramsToSkip = 0);1388 RValue emitCallExpr(const clang::CallExpr *e,1389 ReturnValueSlot returnValue = ReturnValueSlot());1390 LValue emitCallExprLValue(const clang::CallExpr *e);1391 CIRGenCallee emitCallee(const clang::Expr *e);1392 1393 template <typename T>1394 mlir::LogicalResult emitCaseDefaultCascade(const T *stmt, mlir::Type condType,1395 mlir::ArrayAttr value,1396 cir::CaseOpKind kind,1397 bool buildingTopLevelCase);1398 1399 mlir::LogicalResult emitCaseStmt(const clang::CaseStmt &s,1400 mlir::Type condType,1401 bool buildingTopLevelCase);1402 1403 LValue emitCastLValue(const CastExpr *e);1404 1405 /// Emits an argument for a call to a `__builtin_assume`. If the builtin1406 /// sanitizer is enabled, a runtime check is also emitted.1407 mlir::Value emitCheckedArgForAssume(const Expr *e);1408 1409 /// Emit a conversion from the specified complex type to the specified1410 /// destination type, where the destination type is an LLVM scalar type.1411 mlir::Value emitComplexToScalarConversion(mlir::Value src, QualType srcTy,1412 QualType dstTy, SourceLocation loc);1413 1414 LValue emitCompoundAssignmentLValue(const clang::CompoundAssignOperator *e);1415 LValue emitCompoundLiteralLValue(const CompoundLiteralExpr *e);1416 1417 void emitConstructorBody(FunctionArgList &args);1418 1419 mlir::LogicalResult emitCoroutineBody(const CoroutineBodyStmt &s);1420 cir::CallOp emitCoroEndBuiltinCall(mlir::Location loc, mlir::Value nullPtr);1421 cir::CallOp emitCoroIDBuiltinCall(mlir::Location loc, mlir::Value nullPtr);1422 cir::CallOp emitCoroAllocBuiltinCall(mlir::Location loc);1423 cir::CallOp emitCoroBeginBuiltinCall(mlir::Location loc,1424 mlir::Value coroframeAddr);1425 RValue emitCoroutineFrame();1426 1427 void emitDestroy(Address addr, QualType type, Destroyer *destroyer);1428 1429 void emitDestructorBody(FunctionArgList &args);1430 1431 mlir::LogicalResult emitContinueStmt(const clang::ContinueStmt &s);1432 1433 void emitCXXConstructExpr(const clang::CXXConstructExpr *e,1434 AggValueSlot dest);1435 1436 void emitCXXAggrConstructorCall(const CXXConstructorDecl *ctor,1437 const clang::ArrayType *arrayType,1438 Address arrayBegin, const CXXConstructExpr *e,1439 bool newPointerIsChecked,1440 bool zeroInitialize = false);1441 void emitCXXAggrConstructorCall(const CXXConstructorDecl *ctor,1442 mlir::Value numElements, Address arrayBase,1443 const CXXConstructExpr *e,1444 bool newPointerIsChecked,1445 bool zeroInitialize);1446 void emitCXXConstructorCall(const clang::CXXConstructorDecl *d,1447 clang::CXXCtorType type, bool forVirtualBase,1448 bool delegating, AggValueSlot thisAVS,1449 const clang::CXXConstructExpr *e);1450 1451 void emitCXXConstructorCall(const clang::CXXConstructorDecl *d,1452 clang::CXXCtorType type, bool forVirtualBase,1453 bool delegating, Address thisAddr,1454 CallArgList &args, clang::SourceLocation loc);1455 1456 void emitCXXDeleteExpr(const CXXDeleteExpr *e);1457 1458 void emitCXXDestructorCall(const CXXDestructorDecl *dd, CXXDtorType type,1459 bool forVirtualBase, bool delegating,1460 Address thisAddr, QualType thisTy);1461 1462 RValue emitCXXDestructorCall(GlobalDecl dtor, const CIRGenCallee &callee,1463 mlir::Value thisVal, QualType thisTy,1464 mlir::Value implicitParam,1465 QualType implicitParamTy, const CallExpr *e);1466 1467 mlir::LogicalResult emitCXXForRangeStmt(const CXXForRangeStmt &s,1468 llvm::ArrayRef<const Attr *> attrs);1469 1470 RValue emitCXXMemberCallExpr(const clang::CXXMemberCallExpr *e,1471 ReturnValueSlot returnValue);1472 1473 RValue emitCXXMemberOrOperatorCall(1474 const clang::CXXMethodDecl *md, const CIRGenCallee &callee,1475 ReturnValueSlot returnValue, mlir::Value thisPtr,1476 mlir::Value implicitParam, clang::QualType implicitParamTy,1477 const clang::CallExpr *ce, CallArgList *rtlArgs);1478 1479 RValue emitCXXMemberOrOperatorMemberCallExpr(1480 const clang::CallExpr *ce, const clang::CXXMethodDecl *md,1481 ReturnValueSlot returnValue, bool hasQualifier,1482 clang::NestedNameSpecifier qualifier, bool isArrow,1483 const clang::Expr *base);1484 1485 mlir::Value emitCXXNewExpr(const CXXNewExpr *e);1486 1487 void emitNewArrayInitializer(const CXXNewExpr *e, QualType elementType,1488 mlir::Type elementTy, Address beginPtr,1489 mlir::Value numElements,1490 mlir::Value allocSizeWithoutCookie);1491 1492 RValue emitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *e,1493 const CXXMethodDecl *md,1494 ReturnValueSlot returnValue);1495 1496 RValue emitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *expr);1497 1498 RValue emitNewOrDeleteBuiltinCall(const FunctionProtoType *type,1499 const CallExpr *callExpr,1500 OverloadedOperatorKind op);1501 1502 void emitCXXTemporary(const CXXTemporary *temporary, QualType tempType,1503 Address ptr);1504 1505 void emitCXXThrowExpr(const CXXThrowExpr *e);1506 1507 mlir::LogicalResult emitCXXTryStmt(const clang::CXXTryStmt &s);1508 1509 mlir::LogicalResult emitCXXTryStmtUnderScope(const clang::CXXTryStmt &s);1510 1511 void enterCXXTryStmt(const CXXTryStmt &s, cir::TryOp tryOp,1512 bool isFnTryBlock = false);1513 1514 void exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock = false);1515 1516 void emitCtorPrologue(const clang::CXXConstructorDecl *ctor,1517 clang::CXXCtorType ctorType, FunctionArgList &args);1518 1519 // It's important not to confuse this and emitDelegateCXXConstructorCall.1520 // Delegating constructors are the C++11 feature. The constructor delegate1521 // optimization is used to reduce duplication in the base and complete1522 // constructors where they are substantially the same.1523 void emitDelegatingCXXConstructorCall(const CXXConstructorDecl *ctor,1524 const FunctionArgList &args);1525 1526 void emitDeleteCall(const FunctionDecl *deleteFD, mlir::Value ptr,1527 QualType deleteTy);1528 1529 mlir::LogicalResult emitDoStmt(const clang::DoStmt &s);1530 1531 mlir::Value emitDynamicCast(Address thisAddr, const CXXDynamicCastExpr *dce);1532 1533 /// Emit an expression as an initializer for an object (variable, field, etc.)1534 /// at the given location. The expression is not necessarily the normal1535 /// initializer for the object, and the address is not necessarily1536 /// its normal location.1537 ///1538 /// \param init the initializing expression1539 /// \param d the object to act as if we're initializing1540 /// \param lvalue the lvalue to initialize1541 /// \param capturedByInit true if \p d is a __block variable whose address is1542 /// potentially changed by the initializer1543 void emitExprAsInit(const clang::Expr *init, const clang::ValueDecl *d,1544 LValue lvalue, bool capturedByInit = false);1545 1546 mlir::LogicalResult emitFunctionBody(const clang::Stmt *body);1547 1548 mlir::LogicalResult emitGotoStmt(const clang::GotoStmt &s);1549 1550 void emitImplicitAssignmentOperatorBody(FunctionArgList &args);1551 1552 void emitInitializerForField(clang::FieldDecl *field, LValue lhs,1553 clang::Expr *init);1554 1555 LValue emitPredefinedLValue(const PredefinedExpr *e);1556 1557 mlir::Value emitPromotedComplexExpr(const Expr *e, QualType promotionType);1558 1559 mlir::Value emitPromotedScalarExpr(const Expr *e, QualType promotionType);1560 1561 mlir::Value emitPromotedValue(mlir::Value result, QualType promotionType);1562 1563 void emitReturnOfRValue(mlir::Location loc, RValue rv, QualType ty);1564 1565 mlir::Value emitRuntimeCall(mlir::Location loc, cir::FuncOp callee,1566 llvm::ArrayRef<mlir::Value> args = {});1567 1568 /// Emit the computation of the specified expression of scalar type.1569 mlir::Value emitScalarExpr(const clang::Expr *e,1570 bool ignoreResultAssign = false);1571 1572 mlir::Value emitScalarPrePostIncDec(const UnaryOperator *e, LValue lv,1573 cir::UnaryOpKind kind, bool isPre);1574 1575 /// Build a debug stoppoint if we are emitting debug info.1576 void emitStopPoint(const Stmt *s);1577 1578 // Build CIR for a statement. useCurrentScope should be true if no1579 // new scopes need be created when finding a compound statement.1580 mlir::LogicalResult emitStmt(const clang::Stmt *s, bool useCurrentScope,1581 llvm::ArrayRef<const Attr *> attrs = {});1582 1583 mlir::LogicalResult emitSimpleStmt(const clang::Stmt *s,1584 bool useCurrentScope);1585 1586 mlir::LogicalResult emitForStmt(const clang::ForStmt &s);1587 1588 void emitForwardingCallToLambda(const CXXMethodDecl *lambdaCallOperator,1589 CallArgList &callArgs);1590 1591 RValue emitCoawaitExpr(const CoawaitExpr &e,1592 AggValueSlot aggSlot = AggValueSlot::ignored(),1593 bool ignoreResult = false);1594 /// Emit the computation of the specified expression of complex type,1595 /// returning the result.1596 mlir::Value emitComplexExpr(const Expr *e);1597 1598 void emitComplexExprIntoLValue(const Expr *e, LValue dest, bool isInit);1599 1600 mlir::Value emitComplexPrePostIncDec(const UnaryOperator *e, LValue lv,1601 cir::UnaryOpKind op, bool isPre);1602 1603 LValue emitComplexAssignmentLValue(const BinaryOperator *e);1604 LValue emitComplexCompoundAssignmentLValue(const CompoundAssignOperator *e);1605 LValue emitScalarCompoundAssignWithComplex(const CompoundAssignOperator *e,1606 mlir::Value &result);1607 1608 mlir::LogicalResult1609 emitCompoundStmt(const clang::CompoundStmt &s, Address *lastValue = nullptr,1610 AggValueSlot slot = AggValueSlot::ignored());1611 1612 mlir::LogicalResult1613 emitCompoundStmtWithoutScope(const clang::CompoundStmt &s,1614 Address *lastValue = nullptr,1615 AggValueSlot slot = AggValueSlot::ignored());1616 1617 void emitDecl(const clang::Decl &d, bool evaluateConditionDecl = false);1618 mlir::LogicalResult emitDeclStmt(const clang::DeclStmt &s);1619 LValue emitDeclRefLValue(const clang::DeclRefExpr *e);1620 1621 mlir::LogicalResult emitDefaultStmt(const clang::DefaultStmt &s,1622 mlir::Type condType,1623 bool buildingTopLevelCase);1624 1625 void emitDelegateCXXConstructorCall(const clang::CXXConstructorDecl *ctor,1626 clang::CXXCtorType ctorType,1627 const FunctionArgList &args,1628 clang::SourceLocation loc);1629 1630 /// We are performing a delegate call; that is, the current function is1631 /// delegating to another one. Produce a r-value suitable for passing the1632 /// given parameter.1633 void emitDelegateCallArg(CallArgList &args, const clang::VarDecl *param,1634 clang::SourceLocation loc);1635 1636 /// Emit an `if` on a boolean condition to the specified blocks.1637 /// FIXME: Based on the condition, this might try to simplify the codegen of1638 /// the conditional based on the branch.1639 /// In the future, we may apply code generation simplifications here,1640 /// similar to those used in classic LLVM codegen1641 /// See `EmitBranchOnBoolExpr` for inspiration.1642 mlir::LogicalResult emitIfOnBoolExpr(const clang::Expr *cond,1643 const clang::Stmt *thenS,1644 const clang::Stmt *elseS);1645 cir::IfOp emitIfOnBoolExpr(const clang::Expr *cond,1646 BuilderCallbackRef thenBuilder,1647 mlir::Location thenLoc,1648 BuilderCallbackRef elseBuilder,1649 std::optional<mlir::Location> elseLoc = {});1650 1651 mlir::Value emitOpOnBoolExpr(mlir::Location loc, const clang::Expr *cond);1652 1653 mlir::LogicalResult emitLabel(const clang::LabelDecl &d);1654 mlir::LogicalResult emitLabelStmt(const clang::LabelStmt &s);1655 1656 void emitLambdaDelegatingInvokeBody(const CXXMethodDecl *md);1657 void emitLambdaStaticInvokeBody(const CXXMethodDecl *md);1658 1659 void populateCatchHandlers(cir::TryOp tryOp);1660 1661 mlir::LogicalResult emitIfStmt(const clang::IfStmt &s);1662 1663 /// Emit code to compute the specified expression,1664 /// ignoring the result.1665 void emitIgnoredExpr(const clang::Expr *e);1666 1667 RValue emitLoadOfBitfieldLValue(LValue lv, SourceLocation loc);1668 1669 /// Load a complex number from the specified l-value.1670 mlir::Value emitLoadOfComplex(LValue src, SourceLocation loc);1671 1672 RValue emitLoadOfExtVectorElementLValue(LValue lv);1673 1674 /// Given an expression that represents a value lvalue, this method emits1675 /// the address of the lvalue, then loads the result as an rvalue,1676 /// returning the rvalue.1677 RValue emitLoadOfLValue(LValue lv, SourceLocation loc);1678 1679 Address emitLoadOfReference(LValue refLVal, mlir::Location loc,1680 LValueBaseInfo *pointeeBaseInfo);1681 LValue emitLoadOfReferenceLValue(Address refAddr, mlir::Location loc,1682 QualType refTy, AlignmentSource source);1683 1684 /// EmitLoadOfScalar - Load a scalar value from an address, taking1685 /// care to appropriately convert from the memory representation to1686 /// the LLVM value representation. The l-value must be a simple1687 /// l-value.1688 mlir::Value emitLoadOfScalar(LValue lvalue, SourceLocation loc);1689 mlir::Value emitLoadOfScalar(Address addr, bool isVolatile, QualType ty,1690 SourceLocation loc, LValueBaseInfo baseInfo);1691 1692 /// Emit code to compute a designator that specifies the location1693 /// of the expression.1694 /// FIXME: document this function better.1695 LValue emitLValue(const clang::Expr *e);1696 LValue emitLValueForBitField(LValue base, const FieldDecl *field);1697 LValue emitLValueForField(LValue base, const clang::FieldDecl *field);1698 1699 LValue emitLValueForLambdaField(const FieldDecl *field);1700 LValue emitLValueForLambdaField(const FieldDecl *field,1701 mlir::Value thisValue);1702 1703 /// Like emitLValueForField, excpet that if the Field is a reference, this1704 /// will return the address of the reference and not the address of the value1705 /// stored in the reference.1706 LValue emitLValueForFieldInitialization(LValue base,1707 const clang::FieldDecl *field,1708 llvm::StringRef fieldName);1709 1710 LValue emitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *e);1711 1712 LValue emitMemberExpr(const MemberExpr *e);1713 1714 LValue emitOpaqueValueLValue(const OpaqueValueExpr *e);1715 1716 LValue emitConditionalOperatorLValue(const AbstractConditionalOperator *expr);1717 1718 /// Given an expression with a pointer type, emit the value and compute our1719 /// best estimate of the alignment of the pointee.1720 ///1721 /// One reasonable way to use this information is when there's a language1722 /// guarantee that the pointer must be aligned to some stricter value, and1723 /// we're simply trying to ensure that sufficiently obvious uses of under-1724 /// aligned objects don't get miscompiled; for example, a placement new1725 /// into the address of a local variable. In such a case, it's quite1726 /// reasonable to just ignore the returned alignment when it isn't from an1727 /// explicit source.1728 Address emitPointerWithAlignment(const clang::Expr *expr,1729 LValueBaseInfo *baseInfo = nullptr);1730 1731 /// Emits a reference binding to the passed in expression.1732 RValue emitReferenceBindingToExpr(const Expr *e);1733 1734 mlir::LogicalResult emitReturnStmt(const clang::ReturnStmt &s);1735 1736 RValue emitRotate(const CallExpr *e, bool isRotateLeft);1737 1738 mlir::Value emitScalarConstant(const ConstantEmission &constant, Expr *e);1739 1740 /// Emit a conversion from the specified type to the specified destination1741 /// type, both of which are CIR scalar types.1742 mlir::Value emitScalarConversion(mlir::Value src, clang::QualType srcType,1743 clang::QualType dstType,1744 clang::SourceLocation loc);1745 1746 void emitScalarInit(const clang::Expr *init, mlir::Location loc,1747 LValue lvalue, bool capturedByInit = false);1748 1749 mlir::Value emitScalarOrConstFoldImmArg(unsigned iceArguments, unsigned idx,1750 const Expr *argExpr);1751 1752 void emitStaticVarDecl(const VarDecl &d, cir::GlobalLinkageKind linkage);1753 1754 void emitStoreOfComplex(mlir::Location loc, mlir::Value v, LValue dest,1755 bool isInit);1756 1757 void emitStoreOfScalar(mlir::Value value, Address addr, bool isVolatile,1758 clang::QualType ty, LValueBaseInfo baseInfo,1759 bool isInit = false, bool isNontemporal = false);1760 void emitStoreOfScalar(mlir::Value value, LValue lvalue, bool isInit);1761 1762 /// Store the specified rvalue into the specified1763 /// lvalue, where both are guaranteed to the have the same type, and that type1764 /// is 'Ty'.1765 void emitStoreThroughLValue(RValue src, LValue dst, bool isInit = false);1766 1767 mlir::Value emitStoreThroughBitfieldLValue(RValue src, LValue dstresult);1768 1769 LValue emitStringLiteralLValue(const StringLiteral *e,1770 llvm::StringRef name = ".str");1771 1772 mlir::LogicalResult emitSwitchBody(const clang::Stmt *s);1773 mlir::LogicalResult emitSwitchCase(const clang::SwitchCase &s,1774 bool buildingTopLevelCase);1775 mlir::LogicalResult emitSwitchStmt(const clang::SwitchStmt &s);1776 1777 mlir::Value emitTargetBuiltinExpr(unsigned builtinID,1778 const clang::CallExpr *e,1779 ReturnValueSlot &returnValue);1780 1781 /// Given a value and its clang type, returns the value casted to its memory1782 /// representation.1783 /// Note: CIR defers most of the special casting to the final lowering passes1784 /// to conserve the high level information.1785 mlir::Value emitToMemory(mlir::Value value, clang::QualType ty);1786 1787 /// Emit a trap instruction, which is used to abort the program in an abnormal1788 /// way, usually for debugging purposes.1789 /// \p createNewBlock indicates whether to create a new block for the IR1790 /// builder. Since the `cir.trap` operation is a terminator, operations that1791 /// follow a trap cannot be emitted after `cir.trap` in the same block. To1792 /// ensure these operations get emitted successfully, you need to create a new1793 /// dummy block and set the insertion point there before continuing from the1794 /// trap operation.1795 void emitTrap(mlir::Location loc, bool createNewBlock);1796 1797 LValue emitUnaryOpLValue(const clang::UnaryOperator *e);1798 1799 mlir::Value emitUnPromotedValue(mlir::Value result, QualType unPromotionType);1800 1801 /// Emit a reached-unreachable diagnostic if \p loc is valid and runtime1802 /// checking is enabled. Otherwise, just emit an unreachable instruction.1803 /// \p createNewBlock indicates whether to create a new block for the IR1804 /// builder. Since the `cir.unreachable` operation is a terminator, operations1805 /// that follow an unreachable point cannot be emitted after `cir.unreachable`1806 /// in the same block. To ensure these operations get emitted successfully,1807 /// you need to create a dummy block and set the insertion point there before1808 /// continuing from the unreachable point.1809 void emitUnreachable(clang::SourceLocation loc, bool createNewBlock);1810 1811 /// This method handles emission of any variable declaration1812 /// inside a function, including static vars etc.1813 void emitVarDecl(const clang::VarDecl &d);1814 1815 void emitVariablyModifiedType(QualType ty);1816 1817 mlir::LogicalResult emitWhileStmt(const clang::WhileStmt &s);1818 1819 mlir::Value emitX86BuiltinExpr(unsigned builtinID, const CallExpr *e);1820 1821 /// Given an assignment `*lhs = rhs`, emit a test that checks if \p rhs is1822 /// nonnull, if 1\p LHS is marked _Nonnull.1823 void emitNullabilityCheck(LValue lhs, mlir::Value rhs,1824 clang::SourceLocation loc);1825 1826 /// An object to manage conditionally-evaluated expressions.1827 class ConditionalEvaluation {1828 CIRGenFunction &cgf;1829 mlir::OpBuilder::InsertPoint insertPt;1830 1831 public:1832 ConditionalEvaluation(CIRGenFunction &cgf)1833 : cgf(cgf), insertPt(cgf.builder.saveInsertionPoint()) {}1834 ConditionalEvaluation(CIRGenFunction &cgf, mlir::OpBuilder::InsertPoint ip)1835 : cgf(cgf), insertPt(ip) {}1836 1837 void beginEvaluation() {1838 assert(cgf.outermostConditional != this);1839 if (!cgf.outermostConditional)1840 cgf.outermostConditional = this;1841 }1842 1843 void endEvaluation() {1844 assert(cgf.outermostConditional != nullptr);1845 if (cgf.outermostConditional == this)1846 cgf.outermostConditional = nullptr;1847 }1848 1849 /// Returns the insertion point which will be executed prior to each1850 /// evaluation of the conditional code. In LLVM OG, this method1851 /// is called getStartingBlock.1852 mlir::OpBuilder::InsertPoint getInsertPoint() const { return insertPt; }1853 };1854 1855 struct ConditionalInfo {1856 std::optional<LValue> lhs{}, rhs{};1857 mlir::Value result{};1858 };1859 1860 // Return true if we're currently emitting one branch or the other of a1861 // conditional expression.1862 bool isInConditionalBranch() const { return outermostConditional != nullptr; }1863 1864 void setBeforeOutermostConditional(mlir::Value value, Address addr) {1865 assert(isInConditionalBranch());1866 {1867 mlir::OpBuilder::InsertionGuard guard(builder);1868 builder.restoreInsertionPoint(outermostConditional->getInsertPoint());1869 builder.createStore(1870 value.getLoc(), value, addr, /*isVolatile=*/false,1871 mlir::IntegerAttr::get(1872 mlir::IntegerType::get(value.getContext(), 64),1873 (uint64_t)addr.getAlignment().getAsAlign().value()));1874 }1875 }1876 1877 // Points to the outermost active conditional control. This is used so that1878 // we know if a temporary should be destroyed conditionally.1879 ConditionalEvaluation *outermostConditional = nullptr;1880 1881 /// An RAII object to record that we're evaluating a statement1882 /// expression.1883 class StmtExprEvaluation {1884 CIRGenFunction &cgf;1885 1886 /// We have to save the outermost conditional: cleanups in a1887 /// statement expression aren't conditional just because the1888 /// StmtExpr is.1889 ConditionalEvaluation *savedOutermostConditional;1890 1891 public:1892 StmtExprEvaluation(CIRGenFunction &cgf)1893 : cgf(cgf), savedOutermostConditional(cgf.outermostConditional) {1894 cgf.outermostConditional = nullptr;1895 }1896 1897 ~StmtExprEvaluation() {1898 cgf.outermostConditional = savedOutermostConditional;1899 }1900 };1901 1902 template <typename FuncTy>1903 ConditionalInfo emitConditionalBlocks(const AbstractConditionalOperator *e,1904 const FuncTy &branchGenFunc);1905 1906 mlir::Value emitTernaryOnBoolExpr(const clang::Expr *cond, mlir::Location loc,1907 const clang::Stmt *thenS,1908 const clang::Stmt *elseS);1909 1910 /// Build a "reference" to a va_list; this is either the address or the value1911 /// of the expression, depending on how va_list is defined.1912 Address emitVAListRef(const Expr *e);1913 1914 /// Emits the start of a CIR variable-argument operation (`cir.va_start`)1915 ///1916 /// \param vaList A reference to the \c va_list as emitted by either1917 /// \c emitVAListRef or \c emitMSVAListRef.1918 ///1919 /// \param count The number of arguments in \c vaList1920 void emitVAStart(mlir::Value vaList, mlir::Value count);1921 1922 /// Emits the end of a CIR variable-argument operation (`cir.va_start`)1923 ///1924 /// \param vaList A reference to the \c va_list as emitted by either1925 /// \c emitVAListRef or \c emitMSVAListRef.1926 void emitVAEnd(mlir::Value vaList);1927 1928 /// Generate code to get an argument from the passed in pointer1929 /// and update it accordingly.1930 ///1931 /// \param ve The \c VAArgExpr for which to generate code.1932 ///1933 /// \param vaListAddr Receives a reference to the \c va_list as emitted by1934 /// either \c emitVAListRef or \c emitMSVAListRef.1935 ///1936 /// \returns SSA value with the argument.1937 mlir::Value emitVAArg(VAArgExpr *ve);1938 1939 /// ----------------------1940 /// CIR build helpers1941 /// -----------------1942public:1943 cir::AllocaOp createTempAlloca(mlir::Type ty, mlir::Location loc,1944 const Twine &name = "tmp",1945 mlir::Value arraySize = nullptr,1946 bool insertIntoFnEntryBlock = false);1947 cir::AllocaOp createTempAlloca(mlir::Type ty, mlir::Location loc,1948 const Twine &name = "tmp",1949 mlir::OpBuilder::InsertPoint ip = {},1950 mlir::Value arraySize = nullptr);1951 Address createTempAlloca(mlir::Type ty, CharUnits align, mlir::Location loc,1952 const Twine &name = "tmp",1953 mlir::Value arraySize = nullptr,1954 Address *alloca = nullptr,1955 mlir::OpBuilder::InsertPoint ip = {});1956 Address createTempAllocaWithoutCast(mlir::Type ty, CharUnits align,1957 mlir::Location loc,1958 const Twine &name = "tmp",1959 mlir::Value arraySize = nullptr,1960 mlir::OpBuilder::InsertPoint ip = {});1961 1962 /// Create a temporary memory object of the given type, with1963 /// appropriate alignmen and cast it to the default address space. Returns1964 /// the original alloca instruction by \p Alloca if it is not nullptr.1965 Address createMemTemp(QualType t, mlir::Location loc,1966 const Twine &name = "tmp", Address *alloca = nullptr,1967 mlir::OpBuilder::InsertPoint ip = {});1968 Address createMemTemp(QualType t, CharUnits align, mlir::Location loc,1969 const Twine &name = "tmp", Address *alloca = nullptr,1970 mlir::OpBuilder::InsertPoint ip = {});1971 1972 //===--------------------------------------------------------------------===//1973 // OpenACC Emission1974 //===--------------------------------------------------------------------===//1975private:1976 template <typename Op>1977 Op emitOpenACCOp(mlir::Location start, OpenACCDirectiveKind dirKind,1978 llvm::ArrayRef<const OpenACCClause *> clauses);1979 // Function to do the basic implementation of an operation with an Associated1980 // Statement. Models AssociatedStmtConstruct.1981 template <typename Op, typename TermOp>1982 mlir::LogicalResult1983 emitOpenACCOpAssociatedStmt(mlir::Location start, mlir::Location end,1984 OpenACCDirectiveKind dirKind,1985 llvm::ArrayRef<const OpenACCClause *> clauses,1986 const Stmt *associatedStmt);1987 1988 template <typename Op, typename TermOp>1989 mlir::LogicalResult emitOpenACCOpCombinedConstruct(1990 mlir::Location start, mlir::Location end, OpenACCDirectiveKind dirKind,1991 llvm::ArrayRef<const OpenACCClause *> clauses, const Stmt *loopStmt);1992 1993 template <typename Op>1994 void emitOpenACCClauses(Op &op, OpenACCDirectiveKind dirKind,1995 ArrayRef<const OpenACCClause *> clauses);1996 // The second template argument doesn't need to be a template, since it should1997 // always be an mlir::acc::LoopOp, but as this is a template anyway, we make1998 // it a template argument as this way we can avoid including the OpenACC MLIR1999 // headers here. We will count on linker failures/explicit instantiation to2000 // ensure we don't mess this up, but it is only called from 1 place, and2001 // instantiated 3x.2002 template <typename ComputeOp, typename LoopOp>2003 void emitOpenACCClauses(ComputeOp &op, LoopOp &loopOp,2004 OpenACCDirectiveKind dirKind,2005 ArrayRef<const OpenACCClause *> clauses);2006 2007 // The OpenACC LoopOp requires that we have auto, seq, or independent on all2008 // LoopOp operations for the 'none' device type case. This function checks if2009 // the LoopOp has one, else it updates it to have one.2010 void updateLoopOpParallelism(mlir::acc::LoopOp &op, bool isOrphan,2011 OpenACCDirectiveKind dk);2012 2013 // The OpenACC 'cache' construct actually applies to the 'loop' if present. So2014 // keep track of the 'loop' so that we can add the cache vars to it correctly.2015 mlir::acc::LoopOp *activeLoopOp = nullptr;2016 2017 struct ActiveOpenACCLoopRAII {2018 CIRGenFunction &cgf;2019 mlir::acc::LoopOp *oldLoopOp;2020 2021 ActiveOpenACCLoopRAII(CIRGenFunction &cgf, mlir::acc::LoopOp *newOp)2022 : cgf(cgf), oldLoopOp(cgf.activeLoopOp) {2023 cgf.activeLoopOp = newOp;2024 }2025 ~ActiveOpenACCLoopRAII() { cgf.activeLoopOp = oldLoopOp; }2026 };2027 2028 // Keep track of the last place we inserted a 'recipe' so that we can insert2029 // the next one in lexical order.2030 mlir::OpBuilder::InsertPoint lastRecipeLocation;2031 2032public:2033 // Helper type used to store the list of important information for a 'data'2034 // clause variable, or a 'cache' variable reference.2035 struct OpenACCDataOperandInfo {2036 mlir::Location beginLoc;2037 mlir::Value varValue;2038 std::string name;2039 // The type of the original variable reference: that is, after 'bounds' have2040 // removed pointers/array types/etc. So in the case of int arr[5], and a2041 // private(arr[1]), 'origType' is 'int', but 'baseType' is 'int[5]'.2042 QualType origType;2043 QualType baseType;2044 llvm::SmallVector<mlir::Value> bounds;2045 // The list of types that we found when going through the bounds, which we2046 // can use to properly set the alloca section.2047 llvm::SmallVector<QualType> boundTypes;2048 };2049 2050 // Gets the collection of info required to lower and OpenACC clause or cache2051 // construct variable reference.2052 OpenACCDataOperandInfo getOpenACCDataOperandInfo(const Expr *e);2053 // Helper function to emit the integer expressions as required by an OpenACC2054 // clause/construct.2055 mlir::Value emitOpenACCIntExpr(const Expr *intExpr);2056 // Helper function to emit an integer constant as an mlir int type, used for2057 // constants in OpenACC constructs/clauses.2058 mlir::Value createOpenACCConstantInt(mlir::Location loc, unsigned width,2059 int64_t value);2060 2061 mlir::LogicalResult2062 emitOpenACCComputeConstruct(const OpenACCComputeConstruct &s);2063 mlir::LogicalResult emitOpenACCLoopConstruct(const OpenACCLoopConstruct &s);2064 mlir::LogicalResult2065 emitOpenACCCombinedConstruct(const OpenACCCombinedConstruct &s);2066 mlir::LogicalResult emitOpenACCDataConstruct(const OpenACCDataConstruct &s);2067 mlir::LogicalResult2068 emitOpenACCEnterDataConstruct(const OpenACCEnterDataConstruct &s);2069 mlir::LogicalResult2070 emitOpenACCExitDataConstruct(const OpenACCExitDataConstruct &s);2071 mlir::LogicalResult2072 emitOpenACCHostDataConstruct(const OpenACCHostDataConstruct &s);2073 mlir::LogicalResult emitOpenACCWaitConstruct(const OpenACCWaitConstruct &s);2074 mlir::LogicalResult emitOpenACCInitConstruct(const OpenACCInitConstruct &s);2075 mlir::LogicalResult2076 emitOpenACCShutdownConstruct(const OpenACCShutdownConstruct &s);2077 mlir::LogicalResult emitOpenACCSetConstruct(const OpenACCSetConstruct &s);2078 mlir::LogicalResult2079 emitOpenACCUpdateConstruct(const OpenACCUpdateConstruct &s);2080 mlir::LogicalResult2081 emitOpenACCAtomicConstruct(const OpenACCAtomicConstruct &s);2082 mlir::LogicalResult emitOpenACCCacheConstruct(const OpenACCCacheConstruct &s);2083 2084 void emitOpenACCDeclare(const OpenACCDeclareDecl &d);2085 void emitOpenACCRoutine(const OpenACCRoutineDecl &d);2086 2087 /// Create a temporary memory object for the given aggregate type.2088 AggValueSlot createAggTemp(QualType ty, mlir::Location loc,2089 const Twine &name = "tmp",2090 Address *alloca = nullptr) {2091 assert(!cir::MissingFeatures::aggValueSlot());2092 return AggValueSlot::forAddr(2093 createMemTemp(ty, loc, name, alloca), ty.getQualifiers(),2094 AggValueSlot::IsNotDestructed, AggValueSlot::IsNotAliased,2095 AggValueSlot::DoesNotOverlap);2096 }2097 2098private:2099 QualType getVarArgType(const Expr *arg);2100};2101 2102} // namespace clang::CIRGen2103 2104#endif2105