[CIR] Add support for globals reference variables (#182608)
These are fairly simple, particularly if they don't need special cleanups (which is left unimplemented), but this provides init for a global reference variable.
This commit is contained in:
parent
a9e29e7ae3
commit
06c673ed49
@ -294,5 +294,34 @@ void CIRGenModule::emitCXXGlobalVarDeclInit(const VarDecl *varDecl,
|
||||
return;
|
||||
}
|
||||
|
||||
errorNYI(varDecl->getSourceRange(), "global with reference type");
|
||||
mlir::OpBuilder::InsertionGuard guard(builder);
|
||||
auto *block = builder.createBlock(&addr.getCtorRegion());
|
||||
CIRGenFunction::LexicalScope scope{*curCGF, addr.getLoc(),
|
||||
builder.getInsertionBlock()};
|
||||
scope.setAsGlobalInit();
|
||||
builder.setInsertionPointToStart(block);
|
||||
mlir::Value getGlobal = builder.createGetGlobal(addr);
|
||||
|
||||
Address declAddr(getGlobal, getASTContext().getDeclAlign(varDecl));
|
||||
assert(performInit && "cannot have a constant initializer which needs "
|
||||
"destruction for reference");
|
||||
RValue rv = cgf.emitReferenceBindingToExpr(varDecl->getInit());
|
||||
{
|
||||
mlir::OpBuilder::InsertionGuard guard(builder);
|
||||
mlir::Operation *rvalDefOp = rv.getValue().getDefiningOp();
|
||||
if (rvalDefOp && rvalDefOp->getBlock()) {
|
||||
mlir::Block *rvalSrcBlock = rvalDefOp->getBlock();
|
||||
|
||||
if (!rvalSrcBlock->empty() && isa<cir::YieldOp>(rvalSrcBlock->back())) {
|
||||
mlir::Operation &front = rvalSrcBlock->front();
|
||||
getGlobal.getDefiningOp()->moveBefore(&front);
|
||||
builder.setInsertionPoint(cast<cir::YieldOp>(rvalSrcBlock->back()));
|
||||
}
|
||||
}
|
||||
cgf.emitStoreOfScalar(rv.getValue(), declAddr, /*isVolatile=*/false, ty,
|
||||
LValueBaseInfo{});
|
||||
}
|
||||
|
||||
builder.setInsertionPointToEnd(block);
|
||||
cir::YieldOp::create(builder, addr->getLoc());
|
||||
}
|
||||
|
||||
@ -65,6 +65,8 @@ public:
|
||||
/// constant. If this succeeds, the emission must be finalized.
|
||||
mlir::Attribute tryEmitForInitializer(const VarDecl &d);
|
||||
|
||||
mlir::Attribute emitForInitializer(const APValue &value, QualType destType);
|
||||
|
||||
void finalize(cir::GlobalOp gv);
|
||||
|
||||
// All of the "abstract" emission methods below permit the emission to
|
||||
|
||||
@ -1657,10 +1657,13 @@ static Address createReferenceTemporary(CIRGenFunction &cgf,
|
||||
}
|
||||
case SD_Thread:
|
||||
case SD_Static: {
|
||||
cgf.cgm.errorNYI(
|
||||
m->getSourceRange(),
|
||||
"createReferenceTemporary: static/thread storage duration");
|
||||
return Address::invalid();
|
||||
auto addr =
|
||||
mlir::cast<cir::GlobalOp>(cgf.cgm.getAddrOfGlobalTemporary(m, inner));
|
||||
auto getGlobal = cgf.cgm.getBuilder().createGetGlobal(addr);
|
||||
assert(addr.getAlignment().has_value() &&
|
||||
"This should always have an alignment");
|
||||
return Address(getGlobal,
|
||||
clang::CharUnits::fromQuantity(addr.getAlignment().value()));
|
||||
}
|
||||
|
||||
case SD_Dynamic:
|
||||
|
||||
@ -1485,9 +1485,11 @@ ConstantLValueEmitter::VisitCXXTypeidExpr(const CXXTypeidExpr *e) {
|
||||
|
||||
ConstantLValue ConstantLValueEmitter::VisitMaterializeTemporaryExpr(
|
||||
const MaterializeTemporaryExpr *e) {
|
||||
cgm.errorNYI(e->getSourceRange(),
|
||||
"ConstantLValueEmitter: materialize temporary expr");
|
||||
return {};
|
||||
assert(e->getStorageDuration() == SD_Static);
|
||||
const Expr *inner = e->getSubExpr()->skipRValueSubobjectAdjustments();
|
||||
mlir::Operation *global = cgm.getAddrOfGlobalTemporary(e, inner);
|
||||
return ConstantLValue(
|
||||
cgm.getBuilder().getGlobalViewAttr(mlir::cast<cir::GlobalOp>(global)));
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -1499,6 +1501,14 @@ mlir::Attribute ConstantEmitter::tryEmitForInitializer(const VarDecl &d) {
|
||||
return markIfFailed(tryEmitPrivateForVarInit(d));
|
||||
}
|
||||
|
||||
mlir::Attribute ConstantEmitter::emitForInitializer(const APValue &value,
|
||||
QualType destType) {
|
||||
initializeNonAbstract();
|
||||
auto c = tryEmitPrivateForMemory(value, destType);
|
||||
assert(c && "couldn't emit constant value non-abstractly?");
|
||||
return c;
|
||||
}
|
||||
|
||||
void ConstantEmitter::finalize(cir::GlobalOp gv) {
|
||||
assert(initializedNonAbstract &&
|
||||
"finalizing emitter that was used for abstract emission?");
|
||||
|
||||
@ -2887,3 +2887,119 @@ cir::LabelOp
|
||||
CIRGenModule::lookupBlockAddressInfo(cir::BlockAddrInfoAttr blockInfo) {
|
||||
return blockAddressInfoToLabel.lookup(blockInfo);
|
||||
}
|
||||
|
||||
mlir::Operation *
|
||||
CIRGenModule::getAddrOfGlobalTemporary(const MaterializeTemporaryExpr *mte,
|
||||
const Expr *init) {
|
||||
assert((mte->getStorageDuration() == SD_Static ||
|
||||
mte->getStorageDuration() == SD_Thread) &&
|
||||
"not a global temporary");
|
||||
const auto *varDecl = cast<VarDecl>(mte->getExtendingDecl());
|
||||
|
||||
// If we're not materializing a subobject of the temporary, keep the
|
||||
// cv-qualifiers from the type of the MaterializeTemporaryExpr.
|
||||
QualType materializedType = init->getType();
|
||||
if (init == mte->getSubExpr())
|
||||
materializedType = mte->getType();
|
||||
|
||||
CharUnits align = getASTContext().getTypeAlignInChars(materializedType);
|
||||
|
||||
auto insertResult = materializedGlobalTemporaryMap.insert({mte, nullptr});
|
||||
if (!insertResult.second)
|
||||
errorNYI(mte->getSourceRange(), "duplicate materialized temporaries");
|
||||
|
||||
// FIXME: If an externally-visible declaration extends multiple temporaries,
|
||||
// we need to give each temporary the same name in every translation unit (and
|
||||
// we also need to make the temporaries externally-visible).
|
||||
llvm::SmallString<256> name;
|
||||
llvm::raw_svector_ostream out(name);
|
||||
getCXXABI().getMangleContext().mangleReferenceTemporary(
|
||||
varDecl, mte->getManglingNumber(), out);
|
||||
|
||||
APValue *value = nullptr;
|
||||
if (mte->getStorageDuration() == SD_Static && varDecl->evaluateValue()) {
|
||||
// If the initializer of the extending declaration is a constant
|
||||
// initializer, we should have a cached constant initializer for this
|
||||
// temporay. Note taht this m ight have a different value from the value
|
||||
// computed by evaluating the initializer if the surrounding constant
|
||||
// expression modifies the temporary.
|
||||
value = mte->getOrCreateValue(/*MayCreate=*/false);
|
||||
}
|
||||
|
||||
// Try evaluating it now, it might have a constant initializer
|
||||
Expr::EvalResult evalResult;
|
||||
if (!value && init->EvaluateAsRValue(evalResult, getASTContext()) &&
|
||||
!evalResult.hasSideEffects())
|
||||
value = &evalResult.Val;
|
||||
|
||||
assert(!cir::MissingFeatures::addressSpace());
|
||||
|
||||
std::optional<ConstantEmitter> emitter;
|
||||
mlir::Attribute initialValue = nullptr;
|
||||
bool isConstant = false;
|
||||
mlir::Type type;
|
||||
|
||||
if (value) {
|
||||
emitter.emplace(*this);
|
||||
initialValue = emitter->emitForInitializer(*value, materializedType);
|
||||
|
||||
isConstant = materializedType.isConstantStorage(
|
||||
getASTContext(), /*ExcludeCtor=*/value, /*ExcludeDtor=*/false);
|
||||
|
||||
type = mlir::cast<mlir::TypedAttr>(initialValue).getType();
|
||||
} else {
|
||||
// No initializer, the initialization will be provided when we initialize
|
||||
// the declaration which performed lifetime extension.
|
||||
type = getTypes().convertTypeForMem(materializedType);
|
||||
}
|
||||
|
||||
// Create a global variable for this lifetime-extended temporary.
|
||||
cir::GlobalLinkageKind linkage =
|
||||
getCIRLinkageVarDefinition(varDecl, /*isConstant=*/false);
|
||||
if (linkage == cir::GlobalLinkageKind::ExternalLinkage) {
|
||||
const VarDecl *initVD;
|
||||
if (varDecl->isStaticDataMember() && varDecl->getAnyInitializer(initVD) &&
|
||||
isa<CXXRecordDecl>(initVD->getLexicalDeclContext())) {
|
||||
// Temporaries defined inside a class get linkonce_odr linkage because the
|
||||
// calss can be defined in multiple translation units.
|
||||
errorNYI(mte->getSourceRange(), "static data member initialization");
|
||||
} else {
|
||||
// There is no need for this temporary to have external linkage if the
|
||||
// VarDecl has external linkage.
|
||||
linkage = cir::GlobalLinkageKind::InternalLinkage;
|
||||
}
|
||||
}
|
||||
mlir::Location loc = getLoc(mte->getSourceRange());
|
||||
cir::GlobalOp gv = createGlobalOp(*this, loc, name, type, isConstant);
|
||||
gv.setInitialValueAttr(initialValue);
|
||||
|
||||
if (emitter)
|
||||
emitter->finalize(gv);
|
||||
// Don't assign dllimport or dllexport to local linkage globals
|
||||
if (!gv.hasLocalLinkage()) {
|
||||
setGVProperties(gv, varDecl);
|
||||
assert(!cir::MissingFeatures::setDLLStorageClass());
|
||||
}
|
||||
|
||||
gv.setAlignment(align.getAsAlign().value());
|
||||
if (supportsCOMDAT() && gv.isWeakForLinker())
|
||||
errorNYI(mte->getSourceRange(),
|
||||
"Global temporary with comdat/weak linkage");
|
||||
if (varDecl->getTLSKind())
|
||||
errorNYI(mte->getSourceRange(),
|
||||
"Global temporary with thread local storage");
|
||||
mlir::Operation *cv = gv;
|
||||
|
||||
assert(!cir::MissingFeatures::addressSpace());
|
||||
|
||||
// Update the map with the new temporary. If we created a placeholder above,
|
||||
// replace it with the new global now.
|
||||
mlir::Operation *&entry = materializedGlobalTemporaryMap[mte];
|
||||
if (entry) {
|
||||
entry->replaceAllUsesWith(cv);
|
||||
entry->erase();
|
||||
}
|
||||
entry = cv;
|
||||
|
||||
return cv;
|
||||
}
|
||||
|
||||
@ -117,6 +117,9 @@ private:
|
||||
/// `noundef` on a return is possible.
|
||||
bool hasStrictReturn(QualType retTy, const Decl *targetDecl);
|
||||
|
||||
llvm::DenseMap<const Expr *, mlir::Operation *>
|
||||
materializedGlobalTemporaryMap;
|
||||
|
||||
public:
|
||||
mlir::ModuleOp getModule() const { return theModule; }
|
||||
CIRGenBuilderTy &getBuilder() { return builder; }
|
||||
@ -658,6 +661,11 @@ public:
|
||||
// Finalize CIR code generation.
|
||||
void release();
|
||||
|
||||
/// Returns a pointer to a global variable representing a temporary with
|
||||
/// static or thread storage duration.
|
||||
mlir::Operation *getAddrOfGlobalTemporary(const MaterializeTemporaryExpr *mte,
|
||||
const Expr *init);
|
||||
|
||||
/// -------
|
||||
/// Visibility and Linkage
|
||||
/// -------
|
||||
|
||||
149
clang/test/CIR/CodeGenCXX/global-refs.cpp
Normal file
149
clang/test/CIR/CodeGenCXX/global-refs.cpp
Normal file
@ -0,0 +1,149 @@
|
||||
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2> %t-before.cir
|
||||
// RUN: FileCheck %s --input-file=%t-before.cir --check-prefixes=CIR,CIR-BEFORE
|
||||
// RUN: FileCheck %s --input-file=%t.cir --check-prefixes=CIR,CIR-AFTER
|
||||
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o - | FileCheck %s --check-prefixes=LLVM
|
||||
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=LLVM
|
||||
|
||||
struct DefCtor{};
|
||||
struct WithCtor{
|
||||
WithCtor();
|
||||
WithCtor(int);
|
||||
};
|
||||
|
||||
struct WithCtorDtor{
|
||||
WithCtorDtor();
|
||||
WithCtorDtor(int);
|
||||
~WithCtorDtor();
|
||||
};
|
||||
|
||||
|
||||
int globalInt;
|
||||
// CIR: cir.global external @globalInt = #cir.int<0> : !s32i {alignment = 4 : i64}
|
||||
// LLVM: @globalInt = global i32 0, align 4
|
||||
|
||||
int &globalIntRef = globalInt;
|
||||
// CIR: cir.global constant external @globalIntRef = #cir.global_view<@globalInt> : !cir.ptr<!s32i> {alignment = 8 : i64}
|
||||
// LLVM: @globalIntRef = constant ptr @globalInt, align 8
|
||||
|
||||
const int &constGlobalIntRef = 5;
|
||||
// CIR: cir.global "private" external @_ZGR17constGlobalIntRef_ = #cir.int<5> : !s32i {alignment = 4 : i64}
|
||||
// CIR: cir.global constant external @constGlobalIntRef = #cir.global_view<@_ZGR17constGlobalIntRef_> : !cir.ptr<!s32i> {alignment = 8 : i64}
|
||||
// LLVM: @_ZGR17constGlobalIntRef_ = {{.*}}global i32 5, align 4
|
||||
// LLVM: @constGlobalIntRef = constant ptr @_ZGR17constGlobalIntRef_, align 8
|
||||
// CIR-BEFORE-LLP: FAIL
|
||||
|
||||
DefCtor defCtor{};
|
||||
// CIR: cir.global external @defCtor = #cir.undef : !rec_DefCtor {alignment = 1 : i64}
|
||||
// LLVM: @defCtor = global %struct.DefCtor undef, align 1
|
||||
|
||||
DefCtor &defCtorRef = defCtor;
|
||||
// CIR: cir.global constant external @defCtorRef = #cir.global_view<@defCtor> : !cir.ptr<!rec_DefCtor> {alignment = 8 : i64}
|
||||
// LLVM: @defCtorRef = constant ptr @defCtor, align 8
|
||||
|
||||
const DefCtor &constDefCtorRef{};
|
||||
// CIR: cir.global "private" constant external @_ZGR15constDefCtorRef_ = #cir.undef : !rec_DefCtor {alignment = 1 : i64}
|
||||
// CIR: cir.global constant external @constDefCtorRef = #cir.global_view<@_ZGR15constDefCtorRef_> : !cir.ptr<!rec_DefCtor> {alignment = 8 : i64}
|
||||
// LLVM: @_ZGR15constDefCtorRef_ = {{.*}}constant %struct.DefCtor undef, align 1
|
||||
// LLVM: @constDefCtorRef = constant ptr @_ZGR15constDefCtorRef_, align 8
|
||||
|
||||
WithCtor withCtor{};
|
||||
// CIR-BEFORE: cir.global external @withCtor = ctor : !rec_WithCtor {
|
||||
// CIR-BEFORE-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtor : !cir.ptr<!rec_WithCtor>
|
||||
// CIR-BEFORE-NEXT: cir.call @_ZN8WithCtorC1Ev(%[[GET_GLOB]]) : (!cir.ptr<!rec_WithCtor>) -> ()
|
||||
// CIR-BEFORE-NEXT: } {alignment = 1 : i64, ast = #cir.var.decl.ast}
|
||||
// CIR-AFTER: cir.global external @withCtor = #cir.zero : !rec_WithCtor {alignment = 1 : i64, ast = #cir.var.decl.ast}
|
||||
// CIR-AFTER-NEXT: cir.func internal private @__cxx_global_var_init{{.*}}() {
|
||||
// CIR-AFTER-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtor : !cir.ptr<!rec_WithCtor>
|
||||
// CIR-AFTER-NEXT: cir.call @_ZN8WithCtorC1Ev(%[[GET_GLOB]]) : (!cir.ptr<!rec_WithCtor>{{.*}}) -> ()
|
||||
// CIR-AFTER-NEXT: cir.return
|
||||
// CIR-AFTER-NEXT: }
|
||||
// LLVM: @withCtor = global %struct.WithCtor zeroinitializer, align 1
|
||||
|
||||
WithCtor &withCtorRef = withCtor;
|
||||
// CIR: cir.global constant external @withCtorRef = #cir.global_view<@withCtor> : !cir.ptr<!rec_WithCtor> {alignment = 8 : i64}
|
||||
// LLVM: @withCtorRef = constant ptr @withCtor, align 8
|
||||
|
||||
const WithCtor &constWithCtorRef{};
|
||||
// CIR-BEFORE: cir.global external @constWithCtorRef = ctor : !cir.ptr<!rec_WithCtor> {
|
||||
// CIR-BEFORE-NEXT: %[[GET_GLOB:.*]] = cir.get_global @constWithCtorRef : !cir.ptr<!cir.ptr<!rec_WithCtor>>
|
||||
// CIR-BEFORE-NEXT: %[[GET_GLOB_OBJ:.*]] = cir.get_global @_ZGR16constWithCtorRef_ : !cir.ptr<!rec_WithCtor>
|
||||
// CIR-BEFORE-NEXT: cir.call @_ZN8WithCtorC1Ev(%[[GET_GLOB_OBJ]]) : (!cir.ptr<!rec_WithCtor>) -> ()
|
||||
// CIR-BEFORE-NEXT: cir.store align(8) %[[GET_GLOB_OBJ]], %[[GET_GLOB]] : !cir.ptr<!rec_WithCtor>, !cir.ptr<!cir.ptr<!rec_WithCtor>>
|
||||
// CIR-BEFORE-NEXT: } {alignment = 8 : i64, ast = #cir.var.decl.ast}
|
||||
// CIR-AFTER: cir.global external @constWithCtorRef = #cir.ptr<null> : !cir.ptr<!rec_WithCtor> {alignment = 8 : i64, ast = #cir.var.decl.ast}
|
||||
// CIR-AFTER-NEXT: cir.func internal private @__cxx_global_var_init{{.*}}() {
|
||||
// CIR-AFTER-NEXT: %[[GET_GLOB:.*]] = cir.get_global @constWithCtorRef : !cir.ptr<!cir.ptr<!rec_WithCtor>>
|
||||
// CIR-AFTER-NEXT: %[[GET_GLOB_OBJ:.*]] = cir.get_global @_ZGR16constWithCtorRef_ : !cir.ptr<!rec_WithCtor>
|
||||
// CIR-AFTER-NEXT: cir.call @_ZN8WithCtorC1Ev(%[[GET_GLOB_OBJ]]) : (!cir.ptr<!rec_WithCtor>{{.*}}) -> ()
|
||||
// CIR-AFTER-NEXT: cir.store align(8) %[[GET_GLOB_OBJ]], %[[GET_GLOB]] : !cir.ptr<!rec_WithCtor>, !cir.ptr<!cir.ptr<!rec_WithCtor>>
|
||||
// CIR-AFTER-NEXT: cir.return
|
||||
// CIR-AFTER-NEXT: }
|
||||
// LLVM: @constWithCtorRef = global ptr null, align 8
|
||||
|
||||
const WithCtor &constWithCtorRef2{5};
|
||||
// CIR-BEFORE: cir.global external @constWithCtorRef2 = ctor : !cir.ptr<!rec_WithCtor> {
|
||||
// CIR-BEFORE-NEXT: %[[GET_GLOB:.*]] = cir.get_global @constWithCtorRef2 : !cir.ptr<!cir.ptr<!rec_WithCtor>>
|
||||
// CIR-BEFORE-NEXT: %[[GET_GLOB_OBJ:.*]] = cir.get_global @_ZGR17constWithCtorRef2_ : !cir.ptr<!rec_WithCtor>
|
||||
// CIR-BEFORE-NEXT: %[[FIVE:.*]] = cir.const #cir.int<5> : !s32i
|
||||
// CIR-BEFORE-NEXT: cir.call @_ZN8WithCtorC1Ei(%[[GET_GLOB_OBJ]], %[[FIVE]]) : (!cir.ptr<!rec_WithCtor>, !s32i) -> ()
|
||||
// CIR-BEFORE-NEXT: cir.store align(8) %[[GET_GLOB_OBJ]], %[[GET_GLOB]] : !cir.ptr<!rec_WithCtor>, !cir.ptr<!cir.ptr<!rec_WithCtor>>
|
||||
// CIR-BEFORE-NEXT: } {alignment = 8 : i64, ast = #cir.var.decl.ast}
|
||||
// CIR-AFTER: cir.global external @constWithCtorRef2 = #cir.ptr<null> : !cir.ptr<!rec_WithCtor> {alignment = 8 : i64, ast = #cir.var.decl.ast}
|
||||
// CIR-AFTER-NEXT: cir.func internal private @__cxx_global_var_init{{.*}}() {
|
||||
// CIR-AFTER-NEXT: %[[GET_GLOB:.*]] = cir.get_global @constWithCtorRef2 : !cir.ptr<!cir.ptr<!rec_WithCtor>>
|
||||
// CIR-AFTER-NEXT: %[[GET_GLOB_OBJ:.*]] = cir.get_global @_ZGR17constWithCtorRef2_ : !cir.ptr<!rec_WithCtor>
|
||||
// CIR-AFTER-NEXT: %[[FIVE:.*]] = cir.const #cir.int<5> : !s32i
|
||||
// CIR-AFTER-NEXT: cir.call @_ZN8WithCtorC1Ei(%[[GET_GLOB_OBJ]], %[[FIVE]]) : (!cir.ptr<!rec_WithCtor>{{.*}}, !s32i{{.*}}) -> ()
|
||||
// CIR-AFTER-NEXT: cir.store align(8) %[[GET_GLOB_OBJ]], %[[GET_GLOB]] : !cir.ptr<!rec_WithCtor>, !cir.ptr<!cir.ptr<!rec_WithCtor>>
|
||||
// CIR-AFTER-NEXT: cir.return
|
||||
// CIR-AFTER-NEXT: }
|
||||
// LLVM: @constWithCtorRef2 = global ptr null, align 8
|
||||
|
||||
WithCtorDtor withCtorDtor{};
|
||||
// CIR-BEFORE: cir.global external @withCtorDtor = ctor : !rec_WithCtorDtor {
|
||||
// CIR-BEFORE-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtorDtor : !cir.ptr<!rec_WithCtorDtor>
|
||||
// CIR-BEFORE-NEXT: cir.call @_ZN12WithCtorDtorC1Ev(%[[GET_GLOB]]) : (!cir.ptr<!rec_WithCtorDtor>) -> ()
|
||||
// CIR-BEFORE-NEXT: } dtor {
|
||||
// CIR-BEFORE-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtorDtor : !cir.ptr<!rec_WithCtorDtor>
|
||||
// CIR-BEFORE-NEXT: cir.call @_ZN12WithCtorDtorD1Ev(%[[GET_GLOB]]) : (!cir.ptr<!rec_WithCtorDtor>) -> ()
|
||||
// CIR-BEFORE-NEXT: } {alignment = 1 : i64, ast = #cir.var.decl.ast}
|
||||
// CIR-AFTER: cir.global external @withCtorDtor = #cir.zero : !rec_WithCtorDtor {alignment = 1 : i64, ast = #cir.var.decl.ast}
|
||||
// CIR-AFTER: cir.func internal private @__cxx_global_var_init{{.*}}() {
|
||||
// CIR-AFTER-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtorDtor : !cir.ptr<!rec_WithCtorDtor>
|
||||
// CIR-AFTER-NEXT: cir.call @_ZN12WithCtorDtorC1Ev(%[[GET_GLOB]]) : (!cir.ptr<!rec_WithCtorDtor>{{.*}}) -> ()
|
||||
// CIR-AFTER-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtorDtor : !cir.ptr<!rec_WithCtorDtor>
|
||||
// CIR-AFTER-NEXT: %[[GET_DTOR:.*]] = cir.get_global @_ZN12WithCtorDtorD1Ev : !cir.ptr<!cir.func<(!cir.ptr<!rec_WithCtorDtor>)>>
|
||||
// CIR-AFTER-NEXT: %[[VOID_FN_PTR:.*]] = cir.cast bitcast %[[GET_DTOR]] : !cir.ptr<!cir.func<(!cir.ptr<!rec_WithCtorDtor>)>> -> !cir.ptr<!cir.func<(!cir.ptr<!void>)>>
|
||||
// CIR-AFTER-NEXT: %[[GLOB_TO_VOID:.*]] = cir.cast bitcast %[[GET_GLOB]] : !cir.ptr<!rec_WithCtorDtor> -> !cir.ptr<!void>
|
||||
// CIR-AFTER-NEXT: %[[DSO_HANDLE:.*]] = cir.get_global @__dso_handle : !cir.ptr<i8>
|
||||
// CIR-AFTER-NEXT: cir.call @__cxa_atexit(%[[VOID_FN_PTR]], %[[GLOB_TO_VOID]], %[[DSO_HANDLE]]) : (!cir.ptr<!cir.func<(!cir.ptr<!void>)>>, !cir.ptr<!void>, !cir.ptr<i8>{{.*}}) -> ()
|
||||
// CIR-AFTER-NEXT: cir.return
|
||||
// CIR-AFTER-NEXT: }
|
||||
// LLVM: @withCtorDtor = global %struct.WithCtorDtor zeroinitializer, align 1
|
||||
|
||||
WithCtorDtor &withCtorDtorRef = withCtorDtor;
|
||||
// CIR: cir.global constant external @withCtorDtorRef = #cir.global_view<@withCtorDtor> : !cir.ptr<!rec_WithCtorDtor> {alignment = 8 : i64}
|
||||
// LLVM: @withCtorDtorRef = constant ptr @withCtorDtor, align 8
|
||||
|
||||
// LLVM: define internal void @__cxx_global_var_init{{.*}}()
|
||||
// LLVM: call void @_ZN8WithCtorC1Ev(ptr {{.*}}@withCtor)
|
||||
// LLVM-NEXT: ret void
|
||||
|
||||
// LLVM: define internal void @__cxx_global_var_init{{.*}}()
|
||||
// LLVM: call void @_ZN8WithCtorC1Ev(ptr {{.*}}@_ZGR16constWithCtorRef_)
|
||||
// LLVM-NEXT: store ptr @_ZGR16constWithCtorRef_, ptr @constWithCtorRef, align 8
|
||||
// LLVM-NEXT: ret void
|
||||
|
||||
// LLVM: define internal void @__cxx_global_var_init{{.*}}()
|
||||
// LLVM: call void @_ZN8WithCtorC1Ei(ptr {{.*}}@_ZGR17constWithCtorRef2_, i32 {{.*}}5)
|
||||
// LLVM-NEXT: store ptr @_ZGR17constWithCtorRef2_, ptr @constWithCtorRef2, align 8
|
||||
// LLVM-NEXT: ret void
|
||||
|
||||
// LLVM: define internal void @__cxx_global_var_init{{.*}}()
|
||||
// LLVM: call void @_ZN12WithCtorDtorC1Ev(ptr {{.*}}@withCtorDtor)
|
||||
// LLVM-NEXT: call {{.*}}@__cxa_atexit(ptr {{.*}}@_ZN12WithCtorDtorD1Ev, ptr {{.*}}@withCtorDtor, ptr {{.*}}@__dso_handle)
|
||||
// LLVM-NEXT: ret void
|
||||
|
||||
// TODO(cir): Once we get destructors for temporaries done, we should test them
|
||||
// here, same as the 'const-WithCtor' examples, except with the 'withCtorDtor'
|
||||
// versions.
|
||||
Loading…
x
Reference in New Issue
Block a user