brintos

brintos / llvm-project-archived public Read only

0
0
Text · 83.9 KiB · b6926bb Raw
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