brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.0 KiB · 71568ec Raw
250 lines · cpp
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// This contains code dealing with C++ code generation.10//11//===----------------------------------------------------------------------===//12 13#include "CIRGenCXXABI.h"14#include "CIRGenFunction.h"15#include "CIRGenModule.h"16 17#include "clang/AST/GlobalDecl.h"18#include "clang/CIR/MissingFeatures.h"19#include "llvm/Support/SaveAndRestore.h"20 21using namespace clang;22using namespace clang::CIRGen;23 24static void emitDeclInit(CIRGenFunction &cgf, const VarDecl *varDecl,25                         cir::GlobalOp globalOp) {26  assert((varDecl->hasGlobalStorage() ||27          (varDecl->hasLocalStorage() &&28           cgf.getContext().getLangOpts().OpenCLCPlusPlus)) &&29         "VarDecl must have global or local (in the case of OpenCL) storage!");30  assert(!varDecl->getType()->isReferenceType() &&31         "Should not call emitDeclInit on a reference!");32 33  CIRGenBuilderTy &builder = cgf.getBuilder();34 35  // Set up the ctor region.36  mlir::OpBuilder::InsertionGuard guard(builder);37  mlir::Block *block = builder.createBlock(&globalOp.getCtorRegion());38  CIRGenFunction::LexicalScope lexScope{cgf, globalOp.getLoc(),39                                        builder.getInsertionBlock()};40  lexScope.setAsGlobalInit();41  builder.setInsertionPointToStart(block);42 43  Address declAddr(cgf.cgm.getAddrOfGlobalVar(varDecl),44                   cgf.cgm.getASTContext().getDeclAlign(varDecl));45 46  QualType type = varDecl->getType();47  LValue lv = cgf.makeAddrLValue(declAddr, type);48 49  const Expr *init = varDecl->getInit();50  switch (CIRGenFunction::getEvaluationKind(type)) {51  case cir::TEK_Scalar:52    assert(!cir::MissingFeatures::objCGC());53    cgf.emitScalarInit(init, cgf.getLoc(varDecl->getLocation()), lv, false);54    break;55  case cir::TEK_Complex:56    cgf.emitComplexExprIntoLValue(init, lv, /*isInit=*/true);57    break;58  case cir::TEK_Aggregate:59    assert(!cir::MissingFeatures::aggValueSlotGC());60    cgf.emitAggExpr(init,61                    AggValueSlot::forLValue(lv, AggValueSlot::IsDestructed,62                                            AggValueSlot::IsNotAliased,63                                            AggValueSlot::DoesNotOverlap));64    break;65  }66 67  // Finish the ctor region.68  builder.setInsertionPointToEnd(block);69  cir::YieldOp::create(builder, globalOp.getLoc());70}71 72static void emitDeclDestroy(CIRGenFunction &cgf, const VarDecl *vd,73                            cir::GlobalOp addr) {74  // Honor __attribute__((no_destroy)) and bail instead of attempting75  // to emit a reference to a possibly nonexistent destructor, which76  // in turn can cause a crash. This will result in a global constructor77  // that isn't balanced out by a destructor call as intended by the78  // attribute. This also checks for -fno-c++-static-destructors and79  // bails even if the attribute is not present.80  QualType::DestructionKind dtorKind = vd->needsDestruction(cgf.getContext());81 82  // FIXME:  __attribute__((cleanup)) ?83 84  switch (dtorKind) {85  case QualType::DK_none:86    return;87 88  case QualType::DK_cxx_destructor:89    break;90 91  case QualType::DK_objc_strong_lifetime:92  case QualType::DK_objc_weak_lifetime:93  case QualType::DK_nontrivial_c_struct:94    // We don't care about releasing objects during process teardown.95    assert(!vd->getTLSKind() && "should have rejected this");96    return;97  }98 99  // If not constant storage we'll emit this regardless of NeedsDtor value.100  CIRGenBuilderTy &builder = cgf.getBuilder();101 102  // Prepare the dtor region.103  mlir::OpBuilder::InsertionGuard guard(builder);104  mlir::Block *block = builder.createBlock(&addr.getDtorRegion());105  CIRGenFunction::LexicalScope lexScope{cgf, addr.getLoc(),106                                        builder.getInsertionBlock()};107  lexScope.setAsGlobalInit();108  builder.setInsertionPointToStart(block);109 110  CIRGenModule &cgm = cgf.cgm;111  QualType type = vd->getType();112 113  // Special-case non-array C++ destructors, if they have the right signature.114  // Under some ABIs, destructors return this instead of void, and cannot be115  // passed directly to __cxa_atexit if the target does not allow this116  // mismatch.117  const CXXRecordDecl *record = type->getAsCXXRecordDecl();118  bool canRegisterDestructor =119      record && (!cgm.getCXXABI().hasThisReturn(120                     GlobalDecl(record->getDestructor(), Dtor_Complete)) ||121                 cgm.getCXXABI().canCallMismatchedFunctionType());122 123  // If __cxa_atexit is disabled via a flag, a different helper function is124  // generated elsewhere which uses atexit instead, and it takes the destructor125  // directly.126  cir::FuncOp fnOp;127  if (record && (canRegisterDestructor || cgm.getCodeGenOpts().CXAAtExit)) {128    if (vd->getTLSKind())129      cgm.errorNYI(vd->getSourceRange(), "TLS destructor");130    assert(!record->hasTrivialDestructor());131    assert(!cir::MissingFeatures::openCL());132    CXXDestructorDecl *dtor = record->getDestructor();133    // In LLVM OG codegen this is done in registerGlobalDtor, but CIRGen134    // relies on LoweringPrepare for further decoupling, so build the135    // call right here.136    auto gd = GlobalDecl(dtor, Dtor_Complete);137    fnOp = cgm.getAddrAndTypeOfCXXStructor(gd).second;138    builder.createCallOp(cgf.getLoc(vd->getSourceRange()),139                         mlir::FlatSymbolRefAttr::get(fnOp.getSymNameAttr()),140                         mlir::ValueRange{cgm.getAddrOfGlobalVar(vd)});141    assert(fnOp && "expected cir.func");142    // TODO(cir): This doesn't do anything but check for unhandled conditions.143    // What it is meant to do should really be happening in LoweringPrepare.144    cgm.getCXXABI().registerGlobalDtor(vd, fnOp, nullptr);145  } else {146    // Otherwise, a custom destroyed is needed. Classic codegen creates a helper147    // function here and emits the destroy into the helper function, which is148    // called from __cxa_atexit.149    // In CIR, we just emit the destroy into the dtor region. It will be moved150    // into a separate function during the LoweringPrepare pass.151    // FIXME(cir): We should create a new operation here to explicitly get the152    // address of the global into whose dtor region we are emiiting the destroy.153    // The same applies to code above where it is calling getAddrOfGlobalVar.154    mlir::Value globalVal = builder.createGetGlobal(addr);155    CharUnits alignment = cgf.getContext().getDeclAlign(vd);156    Address globalAddr{globalVal, cgf.convertTypeForMem(type), alignment};157    cgf.emitDestroy(globalAddr, type, cgf.getDestroyer(dtorKind));158  }159 160  builder.setInsertionPointToEnd(block);161  if (block->empty()) {162    block->erase();163    // Don't confuse lexical cleanup.164    builder.clearInsertionPoint();165  } else {166    cir::YieldOp::create(builder, addr.getLoc());167  }168}169 170cir::FuncOp CIRGenModule::codegenCXXStructor(GlobalDecl gd) {171  const CIRGenFunctionInfo &fnInfo =172      getTypes().arrangeCXXStructorDeclaration(gd);173  cir::FuncType funcType = getTypes().getFunctionType(fnInfo);174  cir::FuncOp fn = getAddrOfCXXStructor(gd, &fnInfo, /*FnType=*/nullptr,175                                        /*DontDefer=*/true, ForDefinition);176  setFunctionLinkage(gd, fn);177  CIRGenFunction cgf{*this, builder};178  curCGF = &cgf;179  {180    mlir::OpBuilder::InsertionGuard guard(builder);181    cgf.generateCode(gd, fn, funcType);182  }183  curCGF = nullptr;184 185  setNonAliasAttributes(gd, fn);186  setCIRFunctionAttributesForDefinition(mlir::cast<FunctionDecl>(gd.getDecl()),187                                        fn);188  return fn;189}190 191// Global variables requiring non-trivial initialization are handled192// differently in CIR than in classic codegen. Classic codegen emits193// a global init function (__cxx_global_var_init) and inserts194// initialization for each global there. In CIR, we attach a ctor195// region to the global variable and insert the initialization code196// into the ctor region. This will be moved into the197// __cxx_global_var_init function during the LoweringPrepare pass.198void CIRGenModule::emitCXXGlobalVarDeclInit(const VarDecl *varDecl,199                                            cir::GlobalOp addr,200                                            bool performInit) {201  QualType ty = varDecl->getType();202 203  // TODO: handle address space204  // The address space of a static local variable (addr) may be different205  // from the address space of the "this" argument of the constructor. In that206  // case, we need an addrspacecast before calling the constructor.207  //208  // struct StructWithCtor {209  //   __device__ StructWithCtor() {...}210  // };211  // __device__ void foo() {212  //   __shared__ StructWithCtor s;213  //   ...214  // }215  //216  // For example, in the above CUDA code, the static local variable s has a217  // "shared" address space qualifier, but the constructor of StructWithCtor218  // expects "this" in the "generic" address space.219  assert(!cir::MissingFeatures::addressSpace());220 221  // Create a CIRGenFunction to emit the initializer. While this isn't a true222  // function, the handling works the same way.223  CIRGenFunction cgf{*this, builder, true};224  llvm::SaveAndRestore<CIRGenFunction *> savedCGF(curCGF, &cgf);225  curCGF->curFn = addr;226 227  CIRGenFunction::SourceLocRAIIObject fnLoc{cgf,228                                            getLoc(varDecl->getLocation())};229 230  assert(!cir::MissingFeatures::astVarDeclInterface());231 232  if (!ty->isReferenceType()) {233    assert(!cir::MissingFeatures::openMP());234 235    bool needsDtor = varDecl->needsDestruction(getASTContext()) ==236                     QualType::DK_cxx_destructor;237    // PerformInit, constant store invariant / destroy handled below.238    if (performInit)239      emitDeclInit(cgf, varDecl, addr);240 241    if (varDecl->getType().isConstantStorage(getASTContext(), true, !needsDtor))242      errorNYI(varDecl->getSourceRange(), "global with constant storage");243    else244      emitDeclDestroy(cgf, varDecl, addr);245    return;246  }247 248  errorNYI(varDecl->getSourceRange(), "global with reference type");249}250