llvm-project/clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp
Bruno Cardoso Lopes da9c513c87
[CIR][LoweringPrepare] Emit guard variables for static local initialization (#179828)
This implements the lowering of static local variables with the Itanium C++ ABI
guard variable pattern in LoweringPrepare. This is initial support, errorNYI covering all that hasn't been added just yet.

When a GlobalOp has the static_local attribute and a ctor region, this pass:
1. Creates a guard variable global (mangled name from AST)
2. Inserts the guard check pattern at each GetGlobalOp use site:
   - Load guard byte with acquire ordering
   - If zero, call __cxa_guard_acquire
   - If acquire returns non-zero, inline the ctor region code
   - Call __cxa_guard_release
3. Clears the static_local attribute and ctor region from the GlobalOp

Once the new design doc lands I'll add more information over there.
2026-02-13 06:22:44 +01:00

62 lines
2.5 KiB
C++

//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This contains code dealing with code generation of C++ declarations
//
//===----------------------------------------------------------------------===//
#include "CIRGenCXXABI.h"
#include "CIRGenFunction.h"
#include "CIRGenModule.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Mangle.h"
#include "clang/Basic/LangOptions.h"
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
using namespace clang;
using namespace clang::CIRGen;
void CIRGenFunction::emitCXXGuardedInit(const VarDecl &varDecl,
cir::GlobalOp globalOp,
bool performInit) {
// If we've been asked to forbid guard variables, emit an error now.
// This diagnostic is hard-coded for Darwin's use case; we can find
// better phrasing if someone else needs it.
if (cgm.getCodeGenOpts().ForbidGuardVariables)
cgm.error(varDecl.getLocation(), "guard variables are forbidden");
// Compute the mangled guard variable name and set the static_local attribute
// BEFORE emitting initialization. This ensures that GetGlobalOps created
// during initialization (e.g., in the ctor region) will see the attribute
// and be marked with static_local accordingly.
llvm::SmallString<256> guardName;
{
llvm::raw_svector_ostream out(guardName);
cgm.getCXXABI().getMangleContext().mangleStaticGuardVariable(&varDecl, out);
}
// Mark the global as static local with the guard name. The emission of the
// guard/acquire is done during LoweringPrepare.
auto guardAttr = mlir::StringAttr::get(&cgm.getMLIRContext(), guardName);
globalOp.setStaticLocalGuardAttr(
cir::StaticLocalGuardAttr::get(&cgm.getMLIRContext(), guardAttr));
// Emit the initializer and add a global destructor if appropriate.
cgm.emitCXXGlobalVarDeclInit(&varDecl, globalOp, performInit);
}
void CIRGenModule::emitCXXGlobalVarDeclInitFunc(const VarDecl *vd,
cir::GlobalOp addr,
bool performInit) {
assert(!cir::MissingFeatures::cudaSupport());
assert(!cir::MissingFeatures::deferredCXXGlobalInit());
emitCXXGlobalVarDeclInit(vd, addr, performInit);
}