[clang] [CIR] Implement global array dtor support (PR #169070)
Erich Keane via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 21 14:30:24 PST 2025
================
@@ -693,6 +696,101 @@ void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) {
op.erase();
}
+cir::FuncOp LoweringPreparePass::getOrCreateDtorFunc(CIRBaseBuilderTy &builder,
+ cir::GlobalOp op,
+ mlir::Region &dtorRegion,
+ cir::CallOp &dtorCall) {
+ assert(!cir::MissingFeatures::astVarDeclInterface());
+ assert(!cir::MissingFeatures::opGlobalThreadLocal());
+
+ cir::VoidType voidTy = builder.getVoidTy();
+ auto voidPtrTy = cir::PointerType::get(voidTy);
+
+ // Look for operations in dtorBlock
+ mlir::Block &dtorBlock = dtorRegion.front();
+
+ // The first operation should be a get_global to retrieve the address
+ // of the global variable we're destroying.
+ auto opIt = dtorBlock.getOperations().begin();
+ cir::GetGlobalOp ggop = mlir::cast<cir::GetGlobalOp>(*opIt);
+
+ // The simple case is just a call to a destructor, like this:
+ //
+ // %0 = cir.get_global %globalS : !cir.ptr<!rec_S>
+ // cir.call %_ZN1SD1Ev(%0) : (!cir.ptr<!rec_S>) -> ()
+ // (implicit cir.yield)
+ //
+ // That is, if the second operation is a call that takes the get_global result
+ // as its only operand, and the only other operation is a yield, then we can
+ // just return the called function.
+ if (dtorBlock.getOperations().size() == 3) {
+ auto callOp = mlir::dyn_cast<cir::CallOp>(&*(++opIt));
+ auto yieldOp = mlir::dyn_cast<cir::YieldOp>(&*(++opIt));
+ if (yieldOp && callOp && callOp.getNumOperands() == 1 &&
+ callOp.getArgOperand(0) == ggop) {
+ dtorCall = callOp;
+ return getCalledFunction(callOp);
+ }
+ }
+
+ // Otherwise, we need to create a helper function to replace the dtor region.
+ // This name is kind of arbitrary, but it matches the name that classic
+ // codegen uses, based on the expected case that gets us here.
+ builder.setInsertionPointAfter(op);
+ SmallString<256> fnName("__cxx_global_array_dtor");
+ uint32_t cnt = dynamicInitializerNames[fnName]++;
+ if (cnt)
+ fnName += "." + llvm::Twine(cnt).str();
----------------
erichkeane wrote:
Ah shoot, thats unfortunate. I was hoping we had an in-place overload :)
Can we at least do:
`fnName += (`.` + llvm::Twine(cnt)).str();`?
(OR: `fnName += (llvm::Twine('.') + llvm::Twine(cnt)).str();`?
Rather than creating a string, immediately pre-pending before adding? I guess we're stuck with an extra allocation anyway, unless we resort to an osstringstream, and IDK if that is worth it for as little addition as we're doing.
https://github.com/llvm/llvm-project/pull/169070
More information about the cfe-commits
mailing list