@@ -194,6 +194,8 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
194194 QualType ThisTy) override ;
195195 void registerGlobalDtor (CIRGenFunction &CGF, const VarDecl *D,
196196 cir::FuncOp dtor, mlir::Value Addr) override ;
197+ void emitGuardedInit (CIRGenFunction &CGF, const VarDecl &D,
198+ cir::GlobalOp DeclPtr, bool PerformInit) override ;
197199 void emitVirtualObjectDelete (CIRGenFunction &CGF, const CXXDeleteExpr *DE,
198200 Address Ptr, QualType ElementType,
199201 const CXXDestructorDecl *Dtor) override ;
@@ -2375,6 +2377,145 @@ void CIRGenItaniumCXXABI::registerGlobalDtor(CIRGenFunction &CGF,
23752377 // prepare. Nothing to be done for CIR here.
23762378}
23772379
2380+ void CIRGenItaniumCXXABI::emitGuardedInit (CIRGenFunction &CGF, const VarDecl &D,
2381+ cir::GlobalOp declPtr,
2382+ bool performInit) {
2383+ auto &builder = CGF.getBuilder ();
2384+ mlir::Location loc = CGF.getLoc (D.getLocation ());
2385+
2386+ // Inline variables that weren't instantiated from variable templates have
2387+ // partially-ordered initialization within their translation unit.
2388+ bool nonTemplateInline =
2389+ D.isInline () &&
2390+ !isTemplateInstantiation (D.getTemplateSpecializationKind ());
2391+
2392+ // We only need to use thread-safe statics for local non-TLS variables and
2393+ // inline variables; other global initialization is always single-threaded
2394+ // or (through lazy dynamic loading in multiple threads) unsequenced.
2395+ bool threadSafe = getContext ().getLangOpts ().ThreadsafeStatics &&
2396+ (D.isLocalVarDecl () || nonTemplateInline) &&
2397+ !D.getTLSKind ();
2398+
2399+ // If we have a global variable with internal linkage and thread-safe statics
2400+ // are disabled, we can just let the guard variable be of type i8.
2401+ bool useInt8GuardVariable =
2402+ !threadSafe &&
2403+ declPtr.getLinkage () == cir::GlobalLinkageKind::InternalLinkage;
2404+
2405+ // Determine the guard variable type.
2406+ mlir::Type guardTy;
2407+ if (useInt8GuardVariable) {
2408+ guardTy = builder.getUInt8Ty ();
2409+ } else {
2410+ // Guard variables are 64 bits in the generic ABI and size width on ARM
2411+ // (i.e. 32-bit on AArch32, 64-bit on AArch64).
2412+ if (UseARMGuardVarABI) {
2413+ llvm_unreachable (" NYI: ARM guard variable ABI" );
2414+ } else {
2415+ guardTy = builder.getUInt64Ty ();
2416+ }
2417+ }
2418+
2419+ // Create the guard variable if we don't already have it (as we
2420+ // might if we're double-emitting this function body).
2421+ // See CodeGen: ItaniumCXXABI.cpp:2735-2772
2422+ cir::GlobalOp guardGlobal = CGM.getStaticLocalDeclGuardAddress (&D);
2423+ if (!guardGlobal) {
2424+ // Mangle the name for the guard variable.
2425+ SmallString<256 > guardName;
2426+ {
2427+ llvm::raw_svector_ostream out (guardName);
2428+ getMangleContext ().mangleStaticGuardVariable (&D, out);
2429+ }
2430+
2431+ // Create the guard variable with a zero-initializer.
2432+ // Just absorb linkage, visibility and dll storage class from the guarded
2433+ // variable.
2434+ guardGlobal = CIRGenModule::createGlobalOp (
2435+ CGM, loc, guardName.str (), guardTy, /* isConstant=*/ false ,
2436+ {}, /* insertPoint=*/ nullptr ,
2437+ declPtr.getLinkage ());
2438+ guardGlobal.setVisibility (declPtr.getVisibility ());
2439+ guardGlobal.setDSOLocal (declPtr.isDSOLocal ());
2440+
2441+ // DLL storage class should match the guarded variable.
2442+ // See CodeGen: ItaniumCXXABI.cpp:2755
2443+ assert (!cir::MissingFeatures::setDLLStorageClass ());
2444+
2445+ // Set alignment for the guard variable based on its type.
2446+ // See CodeGen: ItaniumCXXABI.cpp:2716-2728, 2758
2447+ CharUnits guardAlignment;
2448+ if (useInt8GuardVariable) {
2449+ guardAlignment = CharUnits::One ();
2450+ } else {
2451+ if (UseARMGuardVarABI) {
2452+ llvm_unreachable (" NYI: ARM guard variable ABI alignment" );
2453+ } else {
2454+ guardAlignment = CharUnits::fromQuantity (
2455+ CGM.getDataLayout ().getABITypeAlign (guardTy));
2456+ }
2457+ }
2458+ guardGlobal.setAlignment (guardAlignment.getQuantity ());
2459+
2460+ // Set the initial value to zero.
2461+ guardGlobal.setInitialValueAttr (builder.getZeroInitAttr (guardTy));
2462+
2463+ // The ABI says: "It is suggested that it be emitted in the same COMDAT
2464+ // group as the associated data object." In practice, this doesn't work for
2465+ // non-ELF and non-Wasm object formats, so only do it for ELF and Wasm.
2466+ // See CodeGen: ItaniumCXXABI.cpp:2760-2770
2467+ bool declHasComdat = declPtr.getComdat ();
2468+ if (!D.isLocalVarDecl () && declHasComdat &&
2469+ (CGM.getTarget ().getTriple ().isOSBinFormatELF () ||
2470+ CGM.getTarget ().getTriple ().isOSBinFormatWasm ())) {
2471+ guardGlobal.setComdat (true );
2472+ } else if (CGM.supportsCOMDAT () && guardGlobal.isWeakForLinker ()) {
2473+ guardGlobal.setComdat (true );
2474+ }
2475+
2476+ // Register the guard variable so we don't create it again.
2477+ CGM.setStaticLocalDeclGuardAddress (&D, guardGlobal);
2478+ }
2479+
2480+ // If the variable is thread-local, so is its guard variable.
2481+ if (D.getTLSKind ())
2482+ llvm_unreachable (" NYI: thread-local guard variables" );
2483+
2484+ // Create a pointer to the guard variable for the GuardedInitOp.
2485+ auto guardAddr = builder.createGetGlobal (guardGlobal);
2486+
2487+ // Get a symbol reference to the static variable.
2488+ auto staticVarSymbol =
2489+ mlir::FlatSymbolRefAttr::get (builder.getContext (), declPtr.getSymName ());
2490+
2491+ // Create the GuardedInitOp.
2492+ bool isLocalVar = D.isLocalVarDecl ();
2493+ mlir::UnitAttr threadSafeAttr = threadSafe ? builder.getUnitAttr () : nullptr ;
2494+ mlir::UnitAttr performInitAttr =
2495+ performInit ? builder.getUnitAttr () : nullptr ;
2496+ mlir::UnitAttr isLocalVarAttr = isLocalVar ? builder.getUnitAttr () : nullptr ;
2497+ auto guardedInitOp = builder.create <cir::GuardedInitOp>(
2498+ loc, guardAddr, staticVarSymbol, threadSafeAttr, performInitAttr,
2499+ isLocalVarAttr);
2500+
2501+ // Build the init region.
2502+ mlir::Region &initRegion = guardedInitOp.getInitRegion ();
2503+ mlir::OpBuilder::InsertionGuard guard (builder);
2504+ mlir::Block *initBlock = builder.createBlock (&initRegion);
2505+ builder.setInsertionPointToStart (initBlock);
2506+
2507+ // Emit the initialization code if performInit is true.
2508+ if (performInit) {
2509+ // Get the address of the static variable for initialization.
2510+ Address declAddr (CGF.getBuilder ().createGetGlobal (declPtr),
2511+ declPtr.getSymType (), getContext ().getDeclAlign (&D));
2512+ CGF.emitCXXGlobalVarDeclInit (D, declAddr, /* performInit=*/ true );
2513+ }
2514+
2515+ // Terminate the init region with a yield.
2516+ builder.create <cir::YieldOp>(loc);
2517+ }
2518+
23782519mlir::Value CIRGenItaniumCXXABI::getCXXDestructorImplicitParam (
23792520 CIRGenFunction &CGF, const CXXDestructorDecl *DD, CXXDtorType Type,
23802521 bool ForVirtualBase, bool Delegating) {
0 commit comments